public PackageCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, PackageCommandOptions, args) { }
/// <summary> /// Check to see if any of the dependencies listed in the deps.json file are pulling in later version of NETStandard.Library /// then the target framework supports. /// </summary> /// <param name="logger"></param> /// <param name="targetFramework"></param> /// <param name="depsJsonTargetNode"></param> /// <returns></returns> private static bool ValidateDependencies(IToolLogger logger, string targetFramework, JsonData depsJsonTargetNode) { Version maxNETStandardLibraryVersion; // If we don't know the NETStandard.Library NuGet package version then skip validation. This is to handle // the case we are packaging up for a future target framework verion then this version of the tooling knows about. // Skip validation so the tooling doesn't get in the way. if (!NETSTANDARD_LIBRARY_VERSIONS.TryGetValue(targetFramework, out maxNETStandardLibraryVersion)) { return(true); } var dependenciesUsingNETStandard = new List <string>(); Version referencedNETStandardLibrary = null; foreach (KeyValuePair <string, JsonData> dependencyNode in depsJsonTargetNode) { var nameAndVersion = dependencyNode.Key.Split('/'); if (nameAndVersion.Length != 2) { continue; } if (string.Equals(nameAndVersion[0], "netstandard.library", StringComparison.OrdinalIgnoreCase)) { if (!Version.TryParse(nameAndVersion[1], out referencedNETStandardLibrary)) { logger.WriteLine($"Error parsing version number for declared NETStandard.Library: {nameAndVersion[1]}"); return(true); } } // Collect the dependencies that are pulling in the NETStandard.Library metapackage else { var subDependencies = dependencyNode.Value["dependencies"] as JsonData; if (subDependencies != null) { foreach (KeyValuePair <string, JsonData> subDependency in subDependencies) { if (string.Equals(subDependency.Key, "netstandard.library", StringComparison.OrdinalIgnoreCase)) { dependenciesUsingNETStandard.Add(nameAndVersion[0] + " : " + nameAndVersion[1]); break; } } } } } // If true the project is pulling in a new version of NETStandard.Library then the target framework supports. if (referencedNETStandardLibrary != null && maxNETStandardLibraryVersion < referencedNETStandardLibrary) { logger?.WriteLine($"Error: Project is referencing NETStandard.Library version {referencedNETStandardLibrary.ToString()}. Max version supported by {targetFramework} is {maxNETStandardLibraryVersion.ToString()}."); // See if we can find the target framework that does support the version the project is pulling in. // This can help the user know what framework their dependencies are targeting instead of understanding NuGet version numbers. var matchingTargetFramework = NETSTANDARD_LIBRARY_VERSIONS.FirstOrDefault(x => { return(x.Value.Equals(referencedNETStandardLibrary)); }); if (!string.IsNullOrEmpty(matchingTargetFramework.Key)) { logger?.WriteLine($"Error: NETStandard.Library {referencedNETStandardLibrary.ToString()} is used for target framework {matchingTargetFramework.Key}."); } if (dependenciesUsingNETStandard.Count != 0) { logger?.WriteLine($"Error: Check the following dependencies for versions compatible with {targetFramework}:"); foreach (var dependency in dependenciesUsingNETStandard) { logger?.WriteLine($"Error: \t{dependency}"); } } return(false); } return(true); }
public BaseCommand(IToolLogger logger, string workingDirectory) { this.Logger = logger; this.WorkingDirectory = workingDirectory; }
/// <summary> /// Execute the dotnet publish command and zip up the resulting publish folder. /// </summary> /// <param name="defaults"></param> /// <param name="logger"></param> /// <param name="workingDirectory"></param> /// <param name="projectLocation"></param> /// <param name="targetFramework"></param> /// <param name="configuration"></param> /// <param name="msbuildParameters"></param> /// <param name="disableVersionCheck"></param> /// <param name="publishLocation"></param> /// <param name="zipArchivePath"></param> public static bool CreateApplicationBundle(LambdaToolsDefaults defaults, IToolLogger logger, string workingDirectory, string projectLocation, string configuration, string targetFramework, string msbuildParameters, bool disableVersionCheck, out string publishLocation, ref string zipArchivePath) { if (string.IsNullOrEmpty(configuration)) { configuration = LambdaConstants.DEFAULT_BUILD_CONFIGURATION; } string lambdaRuntimePackageStoreManifestContent = null; var computedProjectLocation = Utilities.DetermineProjectLocation(workingDirectory, projectLocation); var packageStoreManifest = LambdaUtilities.LoadPackageStoreManifest(logger, targetFramework); if (!disableVersionCheck) { LambdaUtilities.ValidateMicrosoftAspNetCoreAllReferenceFromProjectPath(logger, targetFramework, packageStoreManifest, computedProjectLocation); } var cli = new LambdaDotNetCLIWrapper(logger, workingDirectory); publishLocation = Utilities.DeterminePublishLocation(workingDirectory, projectLocation, configuration, targetFramework); logger?.WriteLine("Executing publish command"); if (cli.Publish(defaults, projectLocation, publishLocation, targetFramework, configuration, msbuildParameters, lambdaRuntimePackageStoreManifestContent) != 0) { return(false); } var buildLocation = Utilities.DetermineBuildLocation(workingDirectory, projectLocation, configuration, targetFramework); // This is here for legacy reasons. Some older versions of the dotnet CLI were not // copying the deps.json file into the publish folder. foreach (var file in Directory.GetFiles(buildLocation, "*.deps.json", SearchOption.TopDirectoryOnly)) { var destinationPath = Path.Combine(publishLocation, Path.GetFileName(file)); if (!File.Exists(destinationPath)) { File.Copy(file, destinationPath); } } bool flattenRuntime = false; var depsJsonTargetNode = GetDepsJsonTargetNode(logger, publishLocation); // If there is no target node then this means the tool is being used on a future version of .NET Core // then was available when the this tool was written. Go ahead and continue the deployment with warnings so the // user can see if the future version will work. if (depsJsonTargetNode != null && string.Equals(targetFramework, "netcoreapp1.0", StringComparison.OrdinalIgnoreCase)) { // Make sure the project is not pulling in dependencies requiring a later version of .NET Core then the declared target framework if (!ValidateDependencies(logger, targetFramework, depsJsonTargetNode, disableVersionCheck)) { return(false); } // Flatten the runtime folder which reduces the package size by not including native dependencies // for other platforms. flattenRuntime = FlattenRuntimeFolder(logger, publishLocation, depsJsonTargetNode); } if (zipArchivePath == null) { zipArchivePath = Path.Combine(Directory.GetParent(publishLocation).FullName, new DirectoryInfo(computedProjectLocation).Name + ".zip"); } zipArchivePath = Path.GetFullPath(zipArchivePath); logger?.WriteLine($"Zipping publish folder {publishLocation} to {zipArchivePath}"); if (File.Exists(zipArchivePath)) { File.Delete(zipArchivePath); } var zipArchiveParentDirectory = Path.GetDirectoryName(zipArchivePath); if (!Directory.Exists(zipArchiveParentDirectory)) { logger?.WriteLine($"Creating directory {zipArchiveParentDirectory}"); new DirectoryInfo(zipArchiveParentDirectory).Create(); } BundleDirectory(zipArchivePath, publishLocation, flattenRuntime, logger); return(true); }
public DeleteServerlessCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, DeleteCommandOptions, args) { }
/// <summary> /// Make sure that if the project references the Microsoft.AspNetCore.All package which is in implicit package store /// that the Lambda runtime has that store available. Otherwise the Lambda function will fail with an Internal server error. /// </summary> /// <param name="logger"></param> /// <param name="manifestContent"></param> /// <param name="projContent"></param> public static void ValidateMicrosoftAspNetCoreAllReferenceFromProjectContent(IToolLogger logger, string targetFramework, string manifestContent, string projContent) { const string NO_VERSION = "NO_VERSION"; const string ASPNET_CORE_ALL = "Microsoft.AspNetCore.All"; const string ASPNET_CORE_APP = "Microsoft.AspNetCore.App"; try { XDocument projXmlDoc = XDocument.Parse(projContent); Func <string, string> searchForPackageVersion = (nuGetPackage) => { // Not using XPath because to avoid adding an addition dependency for a simple one time use. foreach (var group in projXmlDoc.Root.Elements("ItemGroup")) { foreach (XElement packageReference in group.Elements("PackageReference")) { var name = packageReference.Attribute("Include")?.Value; if (string.Equals(name, nuGetPackage, StringComparison.Ordinal)) { return(packageReference.Attribute("Version")?.Value ?? NO_VERSION); } } } return(null); }; Func <string, string, Tuple <bool, string> > searchForSupportedVersion = (nuGetPackage, nuGetPackageVersion) => { if (string.IsNullOrEmpty(manifestContent)) { return(new Tuple <bool, string>(true, null)); } var manifestXmlDoc = XDocument.Parse(manifestContent); string latestLambdaDeployedVersion = null; foreach (var element in manifestXmlDoc.Root.Elements("Package")) { var name = element.Attribute("Id")?.Value; if (string.Equals(name, nuGetPackage, StringComparison.Ordinal)) { var version = element.Attribute("Version")?.Value; if (string.Equals(nuGetPackageVersion, version, StringComparison.Ordinal)) { // Version specifed in project file is available in Lambda Runtime return(new Tuple <bool, string>(true, null)); } // Record latest supported version to provide meaningful error message. if (latestLambdaDeployedVersion == null || Version.Parse(latestLambdaDeployedVersion) < Version.Parse(version)) { latestLambdaDeployedVersion = version; } } } return(new Tuple <bool, string>(false, latestLambdaDeployedVersion)); }; var projectAspNetCoreAllVersion = searchForPackageVersion(ASPNET_CORE_ALL); var projectAspNetCoreAppVersion = searchForPackageVersion(ASPNET_CORE_APP); if (string.IsNullOrEmpty(projectAspNetCoreAllVersion) && string.IsNullOrEmpty(projectAspNetCoreAppVersion)) { // Project is not using Microsoft.AspNetCore.All so skip validation. return; } if (string.Equals("netcoreapp2.0", targetFramework, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(projectAspNetCoreAllVersion)) { if (string.IsNullOrEmpty(manifestContent)) { return; } var results = searchForSupportedVersion(ASPNET_CORE_ALL, projectAspNetCoreAllVersion); // project specified version is supported. if (results.Item1) { return; } throw new LambdaToolsException($"Project is referencing version {projectAspNetCoreAllVersion} of {ASPNET_CORE_ALL} which is newer " + $"than {results.Item2}, the latest version available in the Lambda Runtime environment. Please update your project to " + $"use version {results.Item2} and then redeploy your Lambda function.", LambdaToolsException.LambdaErrorCode.AspNetCoreAllValidation); } else if (string.Equals("netcoreapp2.1", targetFramework, StringComparison.OrdinalIgnoreCase)) { string packageName, packageVersion; if (projectAspNetCoreAllVersion != null) { packageName = ASPNET_CORE_ALL; packageVersion = projectAspNetCoreAllVersion; } else { packageName = ASPNET_CORE_APP; packageVersion = projectAspNetCoreAppVersion; } var results = searchForSupportedVersion(packageName, packageVersion); // When .NET Core 2.1 was first released developers were encouraged to not include a version attribute for Microsoft.AspNetCore.All or Microsoft.AspNetCore.App. // This turns out not to be a good practice for Lambda because it makes the package bundle require the latest version of these packages // that is installed on the dev/build box regardless of what is supported in Lambda. To avoid deployment failure confusion we will require the version attribute // be set so we can verify compatiblity. if (string.Equals(packageVersion, NO_VERSION, StringComparison.OrdinalIgnoreCase)) { var message = $"Project is referencing {packageName} without specifying a version. A version is required to ensure compatiblity with the supported versions of {packageName} " + $"in the Lambda compute environment. Edit the PackageReference for {packageName} in your project file to include a Version attribute."; if (!string.IsNullOrEmpty(results.Item2)) { message += " The latest version supported in Lambda is {results.Item2}."; } throw new LambdaToolsException(message, LambdaToolsException.LambdaErrorCode.AspNetCoreAllValidation); } // project specified version is supported. if (results.Item1) { return; } if (packageVersion.StartsWith("2.0", StringComparison.OrdinalIgnoreCase)) { throw new LambdaToolsException($"Project is referencing version {packageVersion} of {packageName}. The minimum supported version is 2.1.0 for the .NET Core 2.1 Lambda runtime.", LambdaToolsException.LambdaErrorCode.AspNetCoreAllValidation); } throw new LambdaToolsException($"Project is referencing version {packageVersion} of {packageName} which is newer " + $"than {results.Item2}, the latest version available in the Lambda Runtime environment. Please update your project to " + $"use version {results.Item2} and then redeploy your Lambda function.", LambdaToolsException.LambdaErrorCode.AspNetCoreAllValidation); } } catch (LambdaToolsException) { throw; } catch (Exception e) { logger?.WriteLine($"Unknown error validating version of {ASPNET_CORE_ALL}: {e.Message}"); } }
public DotNetCLIWrapper(IToolLogger logger, string workingDirectory) : base(logger, workingDirectory) { }
private static EventHandler <StreamTransferProgressArgs> CreateProgressHandler(IToolLogger logger) { int percentToUpdateOn = UPLOAD_PROGRESS_INCREMENT; EventHandler <StreamTransferProgressArgs> handler = ((s, e) => { if (e.PercentDone == percentToUpdateOn || e.PercentDone > percentToUpdateOn) { int increment = e.PercentDone % UPLOAD_PROGRESS_INCREMENT; if (increment == 0) { increment = UPLOAD_PROGRESS_INCREMENT; } percentToUpdateOn = e.PercentDone + increment; logger.WriteLine($"... Progress: {e.PercentDone}%"); } }); return(handler); }
/// <summary> /// Creates the deployment bundle using the native zip tool installed /// on the system (default /usr/bin/zip). This is what is typically used on Linux and OSX /// </summary> /// <param name="zipCLI">The path to the located zip binary.</param> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="rootDirectory">The root directory where all of the relative paths in includedFiles is pointing to.</param> /// <param name="includedFiles">Map of relative to absolute path of files to include in bundle.</param> /// <param name="logger">Logger instance.</param> private static void BundleWithZipCLI(string zipCLI, string zipArchivePath, string rootDirectory, IDictionary <string, string> includedFiles, IToolLogger logger) { var args = new StringBuilder("\"" + zipArchivePath + "\""); foreach (var kvp in includedFiles) { args.AppendFormat(" \"{0}\"", kvp.Key); } var psiZip = new ProcessStartInfo { FileName = zipCLI, Arguments = args.ToString(), WorkingDirectory = rootDirectory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; var handler = (DataReceivedEventHandler)((o, e) => { if (string.IsNullOrEmpty(e.Data)) { return; } logger?.WriteLine("... zipping: " + e.Data); }); using (var proc = new Process()) { proc.StartInfo = psiZip; proc.Start(); proc.ErrorDataReceived += handler; proc.OutputDataReceived += handler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.EnableRaisingEvents = true; proc.WaitForExit(); if (proc.ExitCode == 0) { logger?.WriteLine(string.Format("Created publish archive ({0}).", zipArchivePath)); } } }
public PushDockerImageCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, CommandOptions, args) { }
/// <summary> /// Creates the deployment bundle using the native zip tool installed /// on the system (default /usr/bin/zip). This is what is typically used on Linux and OSX /// </summary> /// <param name="zipCLI">The path to the located zip binary.</param> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="publishLocation">The location to be bundled.</param> /// <param name="flattenRuntime">If true the runtimes folder will be flatten</param> /// <param name="logger">Logger instance.</param> private static void BundleWithZipCLI(string zipCLI, string zipArchivePath, string publishLocation, bool flattenRuntime, IToolLogger logger) { var allFiles = GetFilesToIncludeInArchive(publishLocation, flattenRuntime); BundleWithZipCLI(zipCLI, zipArchivePath, publishLocation, allFiles, logger); }
/// <summary> /// Zip up the publish folder using the .NET compression libraries. This is what is used when run on Windows. /// </summary> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="rootDirectory">The root directory where all of the relative paths in includedFiles is pointing to.</param> /// <param name="includedFiles">Map of relative to absolute path of files to include in bundle.</param> /// <param name="logger">Logger instance.</param> private static void BundleWithDotNetCompression(string zipArchivePath, string rootDirectory, IDictionary <string, string> includedFiles, IToolLogger logger) { using (var zipArchive = ZipFile.Open(zipArchivePath, ZipArchiveMode.Create)) { foreach (var kvp in includedFiles) { zipArchive.CreateEntryFromFile(kvp.Value, kvp.Key); logger?.WriteLine($"... zipping: {kvp.Key}"); } } }
/// <summary> /// Zip up the publish folder using the .NET compression libraries. This is what is used when run on Windows. /// </summary> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="publishLocation">The location to be bundled.</param> /// <param name="flattenRuntime">If true the runtimes folder will be flatten</param> /// <param name="logger">Logger instance.</param> private static void BundleWithDotNetCompression(string zipArchivePath, string publishLocation, bool flattenRuntime, IToolLogger logger) { var includedFiles = GetFilesToIncludeInArchive(publishLocation, flattenRuntime); BundleWithDotNetCompression(zipArchivePath, publishLocation, includedFiles, logger); }
/// <summary> /// Zip up the publish folder using the .NET compression libraries. This is what is used when run on Windows. /// </summary> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="publishLocation">The location to be bundled.</param> /// <param name="flattenRuntime">If true the runtimes folder will be flatten</param> /// <param name="logger">Logger instance.</param> private static void BundleWithDotNetCompression(string zipArchivePath, string publishLocation, bool flattenRuntime, IToolLogger logger) { using (var zipArchive = ZipFile.Open(zipArchivePath, ZipArchiveMode.Create)) { var includedFiles = GetFilesToIncludeInArchive(publishLocation, flattenRuntime); foreach (var kvp in includedFiles) { zipArchive.CreateEntryFromFile(kvp.Value, kvp.Key); logger?.WriteLine($"... zipping: {kvp.Key}"); } } }
/// <summary> /// Execute the dotnet publish command and zip up the resulting publish folder. /// </summary> /// <param name="defaults"></param> /// <param name="logger"></param> /// <param name="workingDirectory"></param> /// <param name="projectLocation"></param> /// <param name="targetFramework"></param> /// <param name="configuration"></param> /// <param name="disableVersionCheck"></param> /// <param name="publishLocation"></param> /// <param name="zipArchivePath"></param> public static bool CreateApplicationBundle(LambdaToolsDefaults defaults, IToolLogger logger, string workingDirectory, string projectLocation, string configuration, string targetFramework, string msbuildParameters, bool disableVersionCheck, out string publishLocation, ref string zipArchivePath) { string lambdaRuntimePackageStoreManifestContent = null; if (!disableVersionCheck) { Utilities.ValidateMicrosoftAspNetCoreAllReference(logger, Utilities.DetermineProjectLocation(workingDirectory, projectLocation), out lambdaRuntimePackageStoreManifestContent); } var cli = new DotNetCLIWrapper(logger, workingDirectory); publishLocation = Utilities.DeterminePublishLocation(workingDirectory, projectLocation, configuration, targetFramework); logger?.WriteLine("Executing publish command"); if (cli.Publish(defaults, projectLocation, publishLocation, targetFramework, configuration, msbuildParameters, lambdaRuntimePackageStoreManifestContent) != 0) { return(false); } var buildLocation = Utilities.DetermineBuildLocation(workingDirectory, projectLocation, configuration, targetFramework); // This is here for legacy reasons. Some older versions of the dotnet CLI were not // copying the deps.json file into the publish folder. foreach (var file in Directory.GetFiles(buildLocation, "*.deps.json", SearchOption.TopDirectoryOnly)) { var destinationPath = Path.Combine(publishLocation, Path.GetFileName(file)); if (!File.Exists(destinationPath)) { File.Copy(file, destinationPath); } } bool flattenRuntime = false; var depsJsonTargetNode = GetDepsJsonTargetNode(logger, publishLocation); // If there is no target node then this means the tool is being used on a future version of .NET Core // then was available when the this tool was written. Go ahead and continue the deployment with warnings so the // user can see if the future version will work. if (depsJsonTargetNode != null && string.Equals(targetFramework, "netcoreapp1.0", StringComparison.OrdinalIgnoreCase)) { // Make sure the project is not pulling in dependencies requiring a later version of .NET Core then the declared target framework if (!ValidateDependencies(logger, targetFramework, depsJsonTargetNode, disableVersionCheck)) { return(false); } // Flatten the runtime folder which reduces the package size by not including native dependencies // for other platforms. flattenRuntime = FlattenRuntimeFolder(logger, publishLocation, depsJsonTargetNode); } if (zipArchivePath == null) { zipArchivePath = Path.Combine(Directory.GetParent(publishLocation).FullName, new DirectoryInfo(workingDirectory).Name + ".zip"); } zipArchivePath = Path.GetFullPath(zipArchivePath); logger?.WriteLine($"Zipping publish folder {publishLocation} to {zipArchivePath}"); if (File.Exists(zipArchivePath)) { File.Delete(zipArchivePath); } var zipArchiveParentDirectory = Path.GetDirectoryName(zipArchivePath); if (!Directory.Exists(zipArchiveParentDirectory)) { logger?.WriteLine($"Creating directory {zipArchiveParentDirectory}"); new DirectoryInfo(zipArchiveParentDirectory).Create(); } #if NETCORE if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { BundleWithDotNetCompression(zipArchivePath, publishLocation, flattenRuntime, logger); } else { // Use the native zip utility if it exist which will maintain linux/osx file permissions var zipCLI = DotNetCLIWrapper.FindExecutableInPath("zip"); if (!string.IsNullOrEmpty(zipCLI)) { BundleWithZipCLI(zipCLI, zipArchivePath, publishLocation, flattenRuntime, logger); } else { throw new LambdaToolsException("Failed to find the \"zip\" utility program in path. This program is required to maintain Linux file permissions in the zip archive.", LambdaToolsException.ErrorCode.FailedToFindZipProgram); } } #else BundleWithDotNetCompression(zipArchivePath, publishLocation, flattenRuntime, logger); #endif return(true); }
/// <summary> /// Execute the dotnet publish command and zip up the resulting publish folder. /// </summary> /// <param name="defaults"></param> /// <param name="logger"></param> /// <param name="workingDirectory"></param> /// <param name="projectLocation"></param> /// <param name="targetFramework"></param> /// <param name="configuration"></param> /// <param name="publishLocation"></param> /// <param name="zipArchivePath"></param> public static bool CreateApplicationBundle(LambdaToolsDefaults defaults, IToolLogger logger, string workingDirectory, string projectLocation, string configuration, string targetFramework, out string publishLocation, ref string zipArchivePath) { var cli = new DotNetCLIWrapper(logger, workingDirectory); publishLocation = Utilities.DeterminePublishLocation(workingDirectory, projectLocation, configuration, targetFramework); logger?.WriteLine("Executing publish command"); if (cli.Publish(defaults, projectLocation, publishLocation, targetFramework, configuration) != 0) { return(false); } var buildLocation = Utilities.DetermineBuildLocation(workingDirectory, projectLocation, configuration, targetFramework); // This is here for legacy reasons. Some older versions of the dotnet CLI were not // copying the deps.json file into the publish folder. foreach (var file in Directory.GetFiles(buildLocation, "*.deps.json", SearchOption.TopDirectoryOnly)) { var destinationPath = Path.Combine(publishLocation, Path.GetFileName(file)); if (!File.Exists(destinationPath)) { File.Copy(file, destinationPath); } } bool flattenRuntime = false; var depsJsonTargetNode = GetDepsJsonTargetNode(logger, publishLocation); // If there is no target node then this means the tool is being used on a future version of .NET Core // then was available when the this tool was written. Go ahead and continue the deployment with warnings so the // user can see if the future version will work. if (depsJsonTargetNode != null) { // Make sure the project is not pulling in dependencies requiring a later version of .NET Core then the declared target framework if (!ValidateDependencies(logger, targetFramework, depsJsonTargetNode)) { return(false); } // Flatten the runtime folder which reduces the package size by not including native dependencies // for other platforms. flattenRuntime = FlattenRuntimeFolder(logger, publishLocation, depsJsonTargetNode); } if (zipArchivePath == null) { zipArchivePath = Path.Combine(Directory.GetParent(publishLocation).FullName, new DirectoryInfo(workingDirectory).Name + ".zip"); } zipArchivePath = Path.GetFullPath(zipArchivePath); logger?.WriteLine($"Zipping publish folder {publishLocation} to {zipArchivePath}"); if (File.Exists(zipArchivePath)) { File.Delete(zipArchivePath); } var zipArchiveParentDirectory = Path.GetDirectoryName(zipArchivePath); if (!Directory.Exists(zipArchiveParentDirectory)) { logger?.WriteLine($"Creating directory {zipArchiveParentDirectory}"); new DirectoryInfo(zipArchiveParentDirectory).Create(); } // Use the native zip utility if it exist which will maintain linux/osx file permissions var zipCLI = DotNetCLIWrapper.FindExecutableInPath("zip"); if (!string.IsNullOrEmpty(zipCLI)) { BundleWithZipCLI(zipCLI, zipArchivePath, publishLocation, flattenRuntime, logger); } else { BundleWithDotNetCompression(zipArchivePath, publishLocation, flattenRuntime, logger); } return(true); }
public ECSBaseCommand(IToolLogger logger, string workingDirectory) : base(logger, workingDirectory) { }
/// <summary> /// Creates the deployment bundle using the native zip tool installed /// on the system (default /usr/bin/zip). /// </summary> /// <param name="zipCLI">The path to the located zip binary.</param> /// <param name="zipArchivePath">The path and name of the zip archive to create.</param> /// <param name="publishLocation">The location to be bundled.</param> /// <param name="logger">Optional logger instance.</param> private static void BundleWithZipCLI(string zipCLI, string zipArchivePath, string publishLocation, IToolLogger logger) { var args = new StringBuilder("\"" + zipArchivePath + "\""); // so that we can archive content in subfolders, take the length of the // path to the root publish location and we'll just substring the // found files so the subpaths are retained var publishRootLength = publishLocation.Length; if (publishLocation[publishRootLength - 1] != Path.DirectorySeparatorChar) { publishRootLength++; } var allFiles = Directory.GetFiles(publishLocation, "*.*", SearchOption.AllDirectories); foreach (var f in allFiles) { args.AppendFormat(" \"{0}\"", f.Substring(publishRootLength)); } var psiZip = new ProcessStartInfo { FileName = zipCLI, Arguments = args.ToString(), WorkingDirectory = publishLocation, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; var handler = (DataReceivedEventHandler)((o, e) => { if (string.IsNullOrEmpty(e.Data)) { return; } logger?.WriteLine("... publish: " + e.Data); }); using (var proc = new Process()) { proc.StartInfo = psiZip; proc.Start(); proc.ErrorDataReceived += handler; proc.OutputDataReceived += handler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.EnableRaisingEvents = true; proc.WaitForExit(); if (proc.ExitCode == 0) { logger?.WriteLine(string.Format("Created publish archive ({0}).", zipArchivePath)); } } }
public ECSBaseCommand(IToolLogger logger, string workingDirectory, IList <CommandOption> possibleOptions, string[] args) : base(logger, workingDirectory, possibleOptions, args) { }
public ListServerlessCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, ListCommandOptions, args) { }
public DeployFunctionCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, DeployCommandOptions, args) { }
public static string ProcessTemplateSubstitions(IToolLogger logger, string templateBody, IDictionary <string, string> substitutions, string workingDirectory) { if (DetermineTemplateFormat(templateBody) != TemplateFormat.Json || substitutions == null || !substitutions.Any()) { return(templateBody); } logger?.WriteLine($"Processing {substitutions.Count} substitutions."); var root = JsonConvert.DeserializeObject(templateBody) as JObject; foreach (var kvp in substitutions) { logger?.WriteLine($"Processing substitution: {kvp.Key}"); var token = root.SelectToken(kvp.Key); if (token == null) { throw new LambdaToolsException($"Failed to locate JSONPath {kvp.Key} for template substitution.", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } logger?.WriteLine($"\tFound element of type {token.Type}"); string replacementValue; if (workingDirectory != null && File.Exists(Path.Combine(workingDirectory, kvp.Value))) { var path = Path.Combine(workingDirectory, kvp.Value); logger?.WriteLine($"\tReading: {path}"); replacementValue = File.ReadAllText(path); } else { replacementValue = kvp.Value; } try { switch (token.Type) { case JTokenType.String: ((JValue)token).Value = replacementValue; break; case JTokenType.Boolean: bool b; if (bool.TryParse(replacementValue, out b)) { ((JValue)token).Value = b; } else { throw new LambdaToolsException($"Failed to convert {replacementValue} to a bool", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } break; case JTokenType.Integer: int i; if (int.TryParse(replacementValue, out i)) { ((JValue)token).Value = i; } else { throw new LambdaToolsException($"Failed to convert {replacementValue} to an int", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } break; case JTokenType.Float: double d; if (double.TryParse(replacementValue, out d)) { ((JValue)token).Value = d; } else { throw new LambdaToolsException($"Failed to convert {replacementValue} to a double", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } break; case JTokenType.Array: case JTokenType.Object: var jcon = token as JContainer; var jprop = jcon.Parent as JProperty; JToken subData; try { subData = JsonConvert.DeserializeObject(replacementValue) as JToken; } catch (Exception e) { throw new LambdaToolsException($"Failed to parse substitue JSON data: {e.Message}", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } jprop.Value = subData; break; default: throw new LambdaToolsException($"Unable to determine how to convert substitute value into the template. " + "Make sure to have a default value in the template which is used to determine the type. " + "For example \"\" for string fields or {} for JSON objects.", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } } catch (Exception e) { throw new LambdaToolsException($"Error setting property {kvp.Key} with value {kvp.Value}: {e.Message}", LambdaToolsException.LambdaErrorCode.ServerlessTemplateSubstitutionError); } } var json = JsonConvert.SerializeObject(root); return(json); }
public LambdaDotNetCLIWrapper(IToolLogger logger, string workingDirectory) { this._logger = logger; this._workingDirectory = workingDirectory; }
public DeployEnvironmentCommand(IToolLogger logger, string workingDirectory, string[] args) : base(logger, workingDirectory, CommandOptions, args) { }
public static void BundleFiles(string zipArchivePath, string rootDirectory, string[] files, IToolLogger logger) { var includedFiles = ConvertToMapOfFiles(rootDirectory, files); #if NETCORE if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { BundleWithDotNetCompression(zipArchivePath, rootDirectory, includedFiles, logger); } else { // Use the native zip utility if it exist which will maintain linux/osx file permissions var zipCLI = LambdaDotNetCLIWrapper.FindExecutableInPath("zip"); if (!string.IsNullOrEmpty(zipCLI)) { BundleWithZipCLI(zipCLI, zipArchivePath, rootDirectory, includedFiles, logger); } else { throw new LambdaToolsException("Failed to find the \"zip\" utility program in path. This program is required to maintain Linux file permissions in the zip archive.", LambdaToolsException.LambdaErrorCode.FailedToFindZipProgram); } } #else BundleWithDotNetCompression(zipArchivePath, rootDirectory, includedFiles, logger); #endif }