示例#1
0
        public bool Compile(IReadOnlyCollection <AbstractFunctionDefinition> functionDefinitions,
                            Type backlinkType,
                            PropertyInfo backlinkPropertyInfo,
                            string newAssemblyNamespace,
                            IReadOnlyCollection <string> externalAssemblyLocations,
                            string outputBinaryFolder,
                            string assemblyName,
                            OpenApiOutputModel openApiOutputModel,
                            CompileTargetEnum compileTarget,
                            string outputAuthoredSourceFolder = null)
        {
            HandlebarsHelperRegistration.RegisterHelpers();
            IReadOnlyCollection <SyntaxTree> syntaxTrees = CompileSource(functionDefinitions,
                                                                         openApiOutputModel,
                                                                         backlinkType,
                                                                         backlinkPropertyInfo,
                                                                         newAssemblyNamespace,
                                                                         outputAuthoredSourceFolder);

            bool isFSharpProject = functionDefinitions.Any(x => x.IsFunctionalFunction);

            return(CompileAssembly(
                       syntaxTrees,
                       externalAssemblyLocations,
                       openApiOutputModel,
                       outputBinaryFolder,
                       assemblyName,
                       newAssemblyNamespace,
                       compileTarget,
                       isFSharpProject));
        }
示例#2
0
        private void RegisterCoreDependencies(
            Type mediatorType,
            IReadOnlyCollection <AbstractFunctionDefinition> functionDefinitions,
            CompileTargetEnum target)
        {
            ServiceCollection.AddTransient(typeof(IMediatorDecorator), mediatorType);
            HashSet <Type> types = new HashSet <Type>();

            foreach (AbstractFunctionDefinition abstractFunctionDefinition in functionDefinitions)
            {
                types.Add(abstractFunctionDefinition.CommandDeserializerType);
                if (abstractFunctionDefinition.CommandTransformerType != null)
                {
                    types.Add(abstractFunctionDefinition.CommandTransformerType);
                }
            }
            foreach (Type type in types)
            {
                ServiceCollection.AddTransient(type);
            }

            if (target == CompileTargetEnum.AzureFunctions)
            {
                // Inject an ILogger that picks up the runtime provided logger
                ServiceCollection.AddTransient <ILogger>(sp => new FunctionLogger(this));
                ServiceCollection.AddTransient <ILoggerFactory>(sp => new FunctionLoggerFactory(this));
            }
        }
示例#3
0
        //REVIEW: END REVIEW
        public static string FindBinaryDirectory(this IFileSystem fileSystem, string directory, CompileTargetEnum target)
        {
            var binFolder = FileSystem.Combine(directory, "bin");
            var debugFolder = FileSystem.Combine(binFolder, target.ToString());
            if (fileSystem.DirectoryExists(debugFolder))
            {
                binFolder = debugFolder;
            }

            return binFolder;
        }
示例#4
0
        private List <PortableExecutableReference> BuildReferenceSet(List <string> resolvedLocations,
                                                                     string[] manifestResoureNames,
                                                                     string manifestResourcePrefix,
                                                                     CompileTargetEnum compileTarget)
        {
            // Add our references - if the reference is to a library that forms part of NET Standard 2.0 then make sure we add
            // the reference from the embedded NET Standard reference set - although our target is NET Standard the assemblies
            // in the output folder of the Function App may be NET Core assemblies.
            List <PortableExecutableReference> references = resolvedLocations.Select(x =>
            {
                if (compileTarget == CompileTargetEnum.NETStandard20)
                {
                    string assemblyFilename     = Path.GetFileName(x);
                    string manifestResourceName =
                        manifestResoureNames.SingleOrDefault(m =>
                                                             String.Equals(assemblyFilename, m, StringComparison.CurrentCultureIgnoreCase));
                    if (manifestResourceName != null)
                    {
                        using (Stream lib = GetType().Assembly
                                            .GetManifestResourceStream(String.Concat(manifestResourcePrefix, manifestResourceName)))
                        {
                            return(MetadataReference.CreateFromStream(lib));
                        }
                    }
                }

                return(MetadataReference.CreateFromFile(x));
            }).ToList();

            if (compileTarget == CompileTargetEnum.NETStandard20)
            {
                using (Stream netStandard = GetType().Assembly
                                            .GetManifestResourceStream("FunctionMonkey.Compiler.Core.references.netstandard2._0.netstandard.dll"))
                {
                    references.Add(MetadataReference.CreateFromStream(netStandard));
                }

                using (Stream netStandard = GetType().Assembly
                                            .GetManifestResourceStream("FunctionMonkey.Compiler.Core.references.netstandard2._0.System.Runtime.dll"))
                {
                    references.Add(MetadataReference.CreateFromStream(netStandard));
                }

                using (Stream systemIo = GetType().Assembly
                                         .GetManifestResourceStream(String.Concat(manifestResourcePrefix, "System.IO.dll")))
                {
                    references.Add(MetadataReference.CreateFromStream(systemIo));
                }
            }

            return(references);
        }
        public static string FindBinaryDirectory(this IFileSystem fileSystem, string directory, CompileTargetEnum target)
        {
            var binFolder = directory.AppendPath("bin");
            var compileTargetFolder = binFolder.AppendPath(target.ToString());
            if (fileSystem.DirectoryExists(compileTargetFolder))
            {
                binFolder = compileTargetFolder;
            }
            else
            {
                LogWriter.Current.Trace("'{0}' did not exist.", compileTargetFolder);
            }

            LogWriter.Current.Trace("  Looking for binaries at " + binFolder);

            return binFolder;
        }
示例#6
0
        public FunctionCompiler(Assembly configurationSourceAssembly,
                                string outputBinaryFolder,
                                CompileTargetEnum compileTarget,
                                ICompilerLog compilerLog)
        {
            _configurationSourceAssembly = configurationSourceAssembly;
            _outputBinaryFolder          = outputBinaryFolder;
            _compileTarget     = compileTarget;
            _compilerLog       = compilerLog;
            _serviceCollection = new ServiceCollection();
            CommandingDependencyResolverAdapter adapter = new CommandingDependencyResolverAdapter(
                (fromType, toInstance) => _serviceCollection.AddSingleton(fromType, toInstance),
                (fromType, toType) => _serviceCollection.AddTransient(fromType, toType),
                (resolveType) => null // we never resolve during compilation
                );

            _commandRegistry          = adapter.AddCommanding();
            _assemblyCompiler         = new AssemblyCompiler(compilerLog);
            _triggerReferenceProvider = new TriggerReferenceProvider();
            _jsonCompiler             = new JsonCompiler();
            _openApiCompiler          = new OpenApiCompiler();
        }
示例#7
0
        //REVIEW: END REVIEW



        public static string FindBinaryDirectory(this IFileSystem fileSystem, string directory, CompileTargetEnum target)
        {
            var binFolder   = FileSystem.Combine(directory, "bin");
            var debugFolder = FileSystem.Combine(binFolder, target.ToString());

            if (fileSystem.DirectoryExists(debugFolder))
            {
                binFolder = debugFolder;
            }

            return(binFolder);
        }
 public TemplateProvider(CompileTargetEnum target)
 {
     _target = target;
 }
示例#9
0
        private static IReadOnlyCollection <string> BuildCandidateReferenceList(
            IReadOnlyCollection <string> externalAssemblyLocations,
            CompileTargetEnum compileTarget,
            bool isFSharpProject)
        {
            // These are assemblies that Roslyn requires from usage within the template
            HashSet <string> locations = new HashSet <string>
            {
                typeof(Task).GetTypeInfo().Assembly.Location,
                typeof(Runtime).GetTypeInfo().Assembly.Location,
                typeof(IStreamCommand).Assembly.Location,
                typeof(AzureFromTheTrenches.Commanding.Abstractions.ICommand).GetTypeInfo().Assembly.Location,
                typeof(Abstractions.ISerializer).GetTypeInfo().Assembly.Location,
                typeof(System.Net.Http.HttpMethod).GetTypeInfo().Assembly.Location,
                typeof(System.Net.HttpStatusCode).GetTypeInfo().Assembly.Location,
                typeof(HttpRequest).Assembly.Location,
                typeof(JsonConvert).GetTypeInfo().Assembly.Location,
                typeof(OkObjectResult).GetTypeInfo().Assembly.Location,
                typeof(IActionResult).GetTypeInfo().Assembly.Location,
                typeof(FunctionNameAttribute).GetTypeInfo().Assembly.Location,
                typeof(ILogger).GetTypeInfo().Assembly.Location,
                typeof(IServiceProvider).GetTypeInfo().Assembly.Location,
                typeof(IHeaderDictionary).GetTypeInfo().Assembly.Location,
                typeof(StringValues).GetTypeInfo().Assembly.Location,
                typeof(ExecutionContext).GetTypeInfo().Assembly.Location,
                typeof(Document).GetTypeInfo().Assembly.Location,
                typeof(Message).GetTypeInfo().Assembly.Location,
                typeof(ChangeFeedProcessorBuilder).Assembly.Location,
                typeof(CosmosDBAttribute).Assembly.Location,
                typeof(TimerInfo).Assembly.Location,
                typeof(DbConnectionStringBuilder).Assembly.Location,
                typeof(AzureSignalRAuthClient).Assembly.Location,
                typeof(System.Environment).Assembly.Location,
                typeof(HttpTriggerAttribute).Assembly.Location,
                typeof(ServiceBusAttribute).Assembly.Location,
                typeof(QueueAttribute).Assembly.Location,
                typeof(Microsoft.IdentityModel.Protocols.HttpDocumentRetriever).Assembly.Location
            };

            if (isFSharpProject)
            {
                locations.Add(typeof(FSharpOption <>).Assembly.Location);
            }


            if (compileTarget == CompileTargetEnum.NETCore21)
            {
                // we're a 3.x assembly so we can use our assemblies
                Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();

                locations.Add(currentAssemblies.Single(x => x.GetName().Name == "netstandard").Location);
                locations.Add(currentAssemblies.Single(x => x.GetName().Name == "System.Runtime").Location); // System.Runtime
                locations.Add(typeof(TargetFrameworkAttribute).Assembly.Location);                           // NetCoreLib
                locations.Add(typeof(System.Linq.Enumerable).Assembly.Location);                             // System.Linq
                locations.Add(typeof(System.Security.Claims.ClaimsPrincipal).Assembly.Location);
                locations.Add(typeof(System.Uri).Assembly.Location);
                locations.Add(currentAssemblies.Single(x => x.GetName().Name == "System.Collections").Location);
                locations.Add(currentAssemblies.Single(x => x.GetName().Name == "System.Threading").Location);
                locations.Add(currentAssemblies.Single(x => x.GetName().Name == "System.Threading.Tasks").Location);
            }


            foreach (string externalAssemblyLocation in externalAssemblyLocations)
            {
                locations.Add(externalAssemblyLocation);
            }

            return(locations);
        }
示例#10
0
        private bool CompileAssembly(IReadOnlyCollection <SyntaxTree> syntaxTrees,
                                     IReadOnlyCollection <string> externalAssemblyLocations,
                                     OpenApiOutputModel openApiOutputModel,
                                     string outputBinaryFolder,
                                     string outputAssemblyName,
                                     string assemblyNamespace,
                                     CompileTargetEnum compileTarget,
                                     bool isFSharpProject)
        {
            IReadOnlyCollection <string> locations = BuildCandidateReferenceList(externalAssemblyLocations, compileTarget, isFSharpProject);
            const string manifestResourcePrefix    = "FunctionMonkey.Compiler.references.netstandard2._0.";
            // For each assembly we've found we need to check and see if it is already included in the output binary folder
            // If it is then its referenced already by the function host and so we add a reference to that version.
            List <string> resolvedLocations = ResolveLocationsWithExistingReferences(outputBinaryFolder, locations);

            string[] manifestResoureNames = GetType().Assembly.GetManifestResourceNames()
                                            .Where(x => x.StartsWith(manifestResourcePrefix))
                                            .Select(x => x.Substring(manifestResourcePrefix.Length))
                                            .ToArray();

            List <PortableExecutableReference> references = BuildReferenceSet(resolvedLocations, manifestResoureNames, manifestResourcePrefix, compileTarget);

            CSharpCompilation compilation = CSharpCompilation.Create(outputAssemblyName)
                                            .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                                            .AddReferences(references)
                                            .AddSyntaxTrees(syntaxTrees)
            ;

            List <ResourceDescription> resources = null;

            if (openApiOutputModel != null)
            {
                resources = new List <ResourceDescription>();
                Debug.Assert(openApiOutputModel.OpenApiSpecification != null);
                resources.Add(new ResourceDescription($"{assemblyNamespace}.OpenApi.{openApiOutputModel.OpenApiSpecification.Filename}",
                                                      () => new MemoryStream(Encoding.UTF8.GetBytes(openApiOutputModel.OpenApiSpecification.Content)), true));
                if (openApiOutputModel.SwaggerUserInterface != null)
                {
                    foreach (OpenApiFileReference fileReference in openApiOutputModel.SwaggerUserInterface)
                    {
                        OpenApiFileReference closureCapturedFileReference = fileReference;
                        resources.Add(new ResourceDescription($"{assemblyNamespace}.OpenApi.{closureCapturedFileReference.Filename}",
                                                              () => new MemoryStream(Encoding.UTF8.GetBytes(closureCapturedFileReference.Content)), true));
                    }
                }
            }

            string     outputFilename    = Path.Combine(outputBinaryFolder, outputAssemblyName);
            EmitResult compilationResult = compilation.Emit(outputFilename, manifestResources: resources);

            if (!compilationResult.Success)
            {
                IEnumerable <Diagnostic> failures = compilationResult.Diagnostics.Where(diagnostic =>
                                                                                        diagnostic.IsWarningAsError ||
                                                                                        diagnostic.Severity == DiagnosticSeverity.Error);

                foreach (Diagnostic diagnostic in failures)
                {
                    _compilerLog.Error($"Error compiling function: {diagnostic.ToString()}");
                }
            }

            return(compilationResult.Success);
        }
示例#11
0
        static void Main(string[] args)
        {
            CompilerLog compilerLog = new CompilerLog();

            compilerLog.Message("Compiler starting");
            LogOutputType outputType = args.Any(x => x.ToLower() == "--jsonoutput")
                ? LogOutputType.Json
                : LogOutputType.Console;

            CompileTargetEnum target = args.Any(x => x.ToLower() == "--netcore21") ? CompileTargetEnum.NETCore21 : CompileTargetEnum.NETStandard20;
            string            outputBinaryDirectory = String.Empty;

            compilerLog.Message($"Targeting {target}");

            if (args.Length == 0)
            {
                compilerLog.Error("Must specify the assembly file to build the functions from");
            }
            else
            {
                try
                {
                    string inputAssemblyFile = args[0];
                    compilerLog.Message($"Loading assembly {inputAssemblyFile}");
                    // TODO: convert the input to an absolute path if necessary
                    Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(inputAssemblyFile);
                    outputBinaryDirectory = Path.GetDirectoryName(assembly.Location);

                    // Not sure why the AssemblyLoadContext doesn't deal with the below. I thought it did. Clearly not.
                    // TODO: Have a chat with someone who knows a bit more about this.
                    AssemblyLoadContext.Default.Resolving += (context, name) =>
                    {
                        string path = Path.Combine(outputBinaryDirectory, $"{name.Name}.dll");
                        //string path = $"{outputBinaryDirectory}\\{name.Name}.dll";
                        if (File.Exists(path))
                        {
                            Assembly referencedAssembly = context.LoadFromAssemblyPath(path);
                            return(referencedAssembly);
                        }
                        return(null);
                    };

                    FunctionCompiler compiler = new FunctionCompiler(assembly, outputBinaryDirectory, target, compilerLog);
                    compiler.Compile();
                }
                catch (Exception e)
                {
                    compilerLog.Error($"Unexpected error: {e.Message}");
                }
            }
            compilerLog.Message("Compilation complete");

            if (compilerLog.HasItems)
            {
                if (string.IsNullOrWhiteSpace(outputBinaryDirectory) && outputType == LogOutputType.Json)
                {
                    compilerLog.Warning("Cannot write errors to output file as no output directory can be found, likely a missing assembly");
                    outputType = LogOutputType.Console;
                }

                if (outputType == LogOutputType.Console)
                {
                    System.Console.WriteLine(compilerLog.ToConsole());
                }
                else
                {
                    string outputPath = Path.Combine(outputBinaryDirectory, "__fm__errors.json");
                    File.WriteAllText(outputPath, compilerLog.ToJson());
                }
            }
        }
        public static string FindBinaryDirectory(this IFileSystem fileSystem, string directory, CompileTargetEnum target)
        {
            var binFolder           = directory.AppendPath("bin");
            var compileTargetFolder = binFolder.AppendPath(target.ToString());

            if (fileSystem.DirectoryExists(compileTargetFolder))
            {
                binFolder = compileTargetFolder;
            }
            else
            {
                LogWriter.Current.Trace("'{0}' did not exist.", compileTargetFolder);
            }

            LogWriter.Current.Trace("  Looking for binaries at " + binFolder);

            return(binFolder);
        }
示例#13
0
 public ICompilerOptionsBuilder HttpTarget(CompileTargetEnum target)
 {
     _options.HttpTarget = target;
     return(this);
 }