public static void ProcessScala( FunctionItem function, bool skipCompile, bool noAssemblyValidation, string gitSha, string gitBranch, string buildConfiguration, string outputDirectory, HashSet <string> existingPackages, string gitInfoFilename, ModuleBuilder builder ) { var showOutput = Settings.VerboseLevel >= VerboseLevel.Detailed; var scalaOutputJar = ScalaPackager.Process(function, skipCompile, noAssemblyValidation, gitSha, gitBranch, buildConfiguration, showOutput); // compute hash for zip contents string hash; using (var zipArchive = ZipFile.OpenRead(scalaOutputJar)) { using (var md5 = MD5.Create()) using (var hashStream = new CryptoStream(Stream.Null, md5, CryptoStreamMode.Write)) { foreach (var entry in zipArchive.Entries.OrderBy(e => e.FullName)) { // hash file path var filePathBytes = Encoding.UTF8.GetBytes(entry.FullName.Replace('\\', '/')); hashStream.Write(filePathBytes, 0, filePathBytes.Length); // hash file contents using (var stream = entry.Open()) { stream.CopyTo(hashStream); } } hashStream.FlushFinalBlock(); hash = md5.Hash.ToHexString(); } } // rename function package with hash var package = Path.Combine(outputDirectory, $"function_{function.Name}_{hash}.jar"); if (!existingPackages.Remove(package)) { File.Move(scalaOutputJar, package); // add git-info.json file using (var zipArchive = ZipFile.Open(package, ZipArchiveMode.Update)) { var entry = zipArchive.CreateEntry(gitInfoFilename); // Set RW-R--R-- permissions attributes on non-Windows operating system if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { entry.ExternalAttributes = 0b1_000_000_110_100_100 << 16; } using (var stream = entry.Open()) { stream.Write(Encoding.UTF8.GetBytes(JObject.FromObject(new ModuleManifestGitInfo { SHA = gitSha, Branch = gitBranch }).ToString(Formatting.None))); } } } else { File.Delete(scalaOutputJar); } // decompress project zip into temporary folder so we can add the 'GITSHAFILE' files builder.AddAsset($"{function.FullName}::PackageName", package); }
private void ProcessDotNet( FunctionItem function, bool noCompile, bool noAssemblyValidation, string gitSha, string gitBranch, string buildConfiguration ) { function.Language = "csharp"; // check if AWS Lambda Tools extension is installed if (!CheckDotNetLambdaToolIsInstalled()) { return; } // read settings from project file var csproj = XDocument.Load(function.Project, LoadOptions.PreserveWhitespace); var mainPropertyGroup = csproj.Element("Project")?.Element("PropertyGroup"); var targetFramework = mainPropertyGroup?.Element("TargetFramework").Value; var rootNamespace = mainPropertyGroup?.Element("RootNamespace")?.Value; var projectName = mainPropertyGroup?.Element("AssemblyName")?.Value ?? Path.GetFileNameWithoutExtension(function.Project); // compile function project Console.WriteLine($"=> Building function {function.Name} [{targetFramework}, {buildConfiguration}]"); var projectDirectory = Path.Combine(Settings.WorkingDirectory, Path.GetFileNameWithoutExtension(function.Project)); var temporaryPackage = Path.Combine(Settings.OutputDirectory, $"function_{function.Name}_temporary.zip"); // check if the project contains an obsolete AWS Lambda Tools extension: <DotNetCliToolReference Include="Amazon.Lambda.Tools"/> var obsoleteNodes = csproj.DescendantNodes() .Where(node => (node is XElement element) && (element.Name == "DotNetCliToolReference") && ((string)element.Attribute("Include") == "Amazon.Lambda.Tools") ) .ToList(); if (obsoleteNodes.Any()) { LogWarn($"removing obsolete AWS Lambda Tools extension from {Path.GetRelativePath(Settings.WorkingDirectory, function.Project)}"); foreach (var obsoleteNode in obsoleteNodes) { var parent = obsoleteNode.Parent; // remove obsolete node obsoleteNode.Remove(); // remove parent if no children are left if (!parent.Elements().Any()) { parent.Remove(); } } csproj.Save(function.Project); } // validate the project is using the most recent lambdasharp assembly references if (!noAssemblyValidation && function.HasAssemblyValidation) { var includes = csproj.Element("Project") ?.Elements("ItemGroup") .Elements("PackageReference") .Where(elem => elem.Attribute("Include")?.Value.StartsWith("LambdaSharp", StringComparison.Ordinal) ?? false); if (includes != null) { foreach (var include in includes) { var expectedVersion = VersionInfo.Parse($"{Settings.ToolVersion.Major}.{Settings.ToolVersion.Minor}{Settings.ToolVersion.Suffix}"); var library = include.Attribute("Include").Value; var libraryVersionText = include.Attribute("Version")?.Value; if (libraryVersionText == null) { LogError($"csproj file is missing a version attribute in its assembly reference for {library} (expected version: '{expectedVersion}')"); } else if (libraryVersionText.EndsWith(".*", StringComparison.Ordinal)) { if (!VersionInfo.TryParse(libraryVersionText.Substring(0, libraryVersionText.Length - 2), out var libraryVersion)) { LogError($"csproj file contains an invalid wildcard version in its assembly reference for {library} (expected version: '{expectedVersion}', found: '{libraryVersionText}')"); } else if (!libraryVersion.IsCompatibleWith(expectedVersion)) { LogError($"csproj file contains a mismatched assembly reference for {library} (expected version: '{expectedVersion}', found: '{libraryVersionText}')"); } } else if (!VersionInfo.TryParse(libraryVersionText, out var libraryVersion)) { LogError($"csproj file contains an invalid version in its assembly reference for {library} (expected version: '{expectedVersion}', found: '{libraryVersionText}')"); } else if (!libraryVersion.IsCompatibleWith(expectedVersion)) { LogError($"csproj file contains a mismatched assembly reference for {library} (expected version: '{expectedVersion}', found: '{libraryVersionText}')"); } } if (Settings.HasErrors) { return; } } } if (noCompile) { return; } // build project with AWS dotnet CLI lambda tool if (!DotNetLambdaPackage(targetFramework, buildConfiguration, temporaryPackage, projectDirectory)) { LogError("'dotnet lambda package' command failed"); return; } // collect sources with invoke methods var mappings = Enumerable.Empty <ApiGatewayInvocationMapping>() .Union(function.Sources .OfType <RestApiSource>() .Where(source => source.Invoke != null) .Select(source => new ApiGatewayInvocationMapping { RestApi = $"{source.HttpMethod}:/{string.Join("/", source.Path)}", Method = source.Invoke, RestApiSource = source }) ) .Union(function.Sources .OfType <WebSocketSource>() .Where(source => source.Invoke != null) .Select(source => new ApiGatewayInvocationMapping { WebSocket = source.RouteKey, Method = source.Invoke, WebSocketSource = source }) ) .ToList(); // verify the function handler can be found in the compiled assembly var buildFolder = Path.Combine(projectDirectory, "bin", buildConfiguration, targetFramework, "publish"); if (function.HasHandlerValidation) { if (function.Function.Handler is string handler) { ValidateEntryPoint( buildFolder, handler ); } } // create request/response schemas for invocation methods if (!LambdaSharpCreateInvocationSchemas( buildFolder, rootNamespace, function.Function.Handler as string, mappings )) { LogError("'lash util create-invoke-methods-schema' command failed"); return; } // add api mappings JSON file(s) if (mappings.Any()) { using (var zipArchive = ZipFile.Open(temporaryPackage, ZipArchiveMode.Update)) { var entry = zipArchive.CreateEntry(API_MAPPINGS); // Set RW-R--R-- permissions attributes on non-Windows operating system if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { entry.ExternalAttributes = 0b1_000_000_110_100_100 << 16; } using (var stream = entry.Open()) { stream.Write(Encoding.UTF8.GetBytes(JObject.FromObject(new ApiGatewayInvocationMappings { Mappings = mappings }).ToString(Formatting.None))); } } } // compute hash for zip contents string hash; using (var zipArchive = ZipFile.OpenRead(temporaryPackage)) { using (var md5 = MD5.Create()) using (var hashStream = new CryptoStream(Stream.Null, md5, CryptoStreamMode.Write)) { foreach (var entry in zipArchive.Entries.OrderBy(e => e.FullName)) { // hash file path var filePathBytes = Encoding.UTF8.GetBytes(entry.FullName.Replace('\\', '/')); hashStream.Write(filePathBytes, 0, filePathBytes.Length); // hash file contents using (var stream = entry.Open()) { stream.CopyTo(hashStream); } } hashStream.FlushFinalBlock(); hash = md5.Hash.ToHexString(); } } // rename function package with hash var package = Path.Combine(Settings.OutputDirectory, $"function_{function.Name}_{hash}.zip"); if (!_existingPackages.Remove(package)) { File.Move(temporaryPackage, package); // add git-info.json file using (var zipArchive = ZipFile.Open(package, ZipArchiveMode.Update)) { var entry = zipArchive.CreateEntry(GIT_INFO_FILE); // Set RW-R--R-- permissions attributes on non-Windows operating system if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { entry.ExternalAttributes = 0b1_000_000_110_100_100 << 16; } using (var stream = entry.Open()) { stream.Write(Encoding.UTF8.GetBytes(JObject.FromObject(new ModuleManifestGitInfo { SHA = gitSha, Branch = gitBranch }).ToString(Formatting.None))); } } } else { File.Delete(temporaryPackage); } // set the module variable to the final package name _builder.AddAsset($"{function.FullName}::PackageName", package); }