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)); }
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)); } }
//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; }
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; }
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(); }
//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; }
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); }
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); }
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); }
public ICompilerOptionsBuilder HttpTarget(CompileTargetEnum target) { _options.HttpTarget = target; return(this); }