/// <summary>
        /// Builds the full build script from the list of snippets for each platform.
        /// </summary>
        /// <returns>Finalized build script as a string.</returns>
        private string BuildScriptFromSnippets(
            BuildScriptGeneratorContext context,
            string installationScript,
            IList <BuildScriptSnippet> buildScriptSnippets,
            IDictionary <string, string> toolsToVersion,
            List <string> directoriesToExcludeFromCopyToIntermediateDir,
            List <string> directoriesToExcludeFromCopyToBuildOutputDir,
            IEnumerable <PlatformDetectorResult> detectionResults)
        {
            string script;
            string benvArgs = StringExtensions.JoinKeyValuePairs(toolsToVersion);

            benvArgs = $"{benvArgs} {Constants.BenvDynamicInstallRootDirKey}=\"{this.cliOptions.DynamicInstallRootDir}\"";

            Dictionary <string, string> buildProperties = buildScriptSnippets
                                                          .Where(s => s.BuildProperties != null)
                                                          .SelectMany(s => s.BuildProperties)
                                                          .ToDictionary(p => p.Key, p => p.Value);

            buildProperties[ManifestFilePropertyKeys.OperationId] = context.OperationId;

            var sourceDirInBuildContainer = this.cliOptions.SourceDir;

            if (!string.IsNullOrEmpty(this.cliOptions.IntermediateDir))
            {
                sourceDirInBuildContainer = this.cliOptions.IntermediateDir;
            }

            buildProperties[ManifestFilePropertyKeys.SourceDirectoryInBuildContainer] = sourceDirInBuildContainer;

            var allPlatformNames = detectionResults
                                   .Where(s => s.Platform != null)
                                   .Select(s => s.Platform)
                                   .ToList();

            foreach (var eachPlatformName in allPlatformNames)
            {
                this.logger.LogInformation($"Build Property Key:{ManifestFilePropertyKeys.PlatformName} value: {eachPlatformName} is written into manifest");
                if (buildProperties.ContainsKey(ManifestFilePropertyKeys.PlatformName))
                {
                    var previousValue = buildProperties[ManifestFilePropertyKeys.PlatformName];
                    buildProperties[ManifestFilePropertyKeys.PlatformName]
                        = string.Join(
                              ",",
                              previousValue,
                              eachPlatformName);
                }
                else
                {
                    buildProperties[ManifestFilePropertyKeys.PlatformName] = eachPlatformName;
                }
            }

            buildProperties[ManifestFilePropertyKeys.CompressDestinationDir] =
                this.cliOptions.CompressDestinationDir.ToString().ToLower();

            // Workaround for bug in TestSourceRepo class in validation tests
            // Should be using context.SourceRepo.FileExists
            string filePathForAppYaml = Path.Combine(context.SourceRepo.RootPath, "appsvc.yaml");

            this.logger.LogDebug("Path to appsvc.yaml " + filePathForAppYaml);

            // Override the prebuild and postbuild commands if BuildConfigurationFile exists
            if (File.Exists(filePathForAppYaml))
            {
                this.logger.LogDebug("Found BuildConfigurationFile");
                this.writer.WriteLine(Environment.NewLine + "Found BuildConfigurationFile");
                try
                {
                    BuildConfigurationFIle buildConfigFile = BuildConfigurationFIle.Create(context.SourceRepo.ReadFile("appsvc.yaml"));
                    if (!string.IsNullOrEmpty(buildConfigFile.Prebuild))
                    {
                        this.cliOptions.PreBuildCommand    = buildConfigFile.Prebuild.Replace("\r\n", ";").Replace("\n", ";");
                        this.cliOptions.PreBuildScriptPath = null;
                        this.logger.LogDebug("Overriding the pre-build commands with the BuildConfigurationFile section");
                        this.logger.LogDebug(this.cliOptions.PreBuildCommand.ToString());
                        this.writer.WriteLine("Overriding the pre-build commands with the BuildConfigurationFile section");
                        this.writer.WriteLine("\t" + this.cliOptions.PreBuildCommand.ToString());
                    }

                    if (!string.IsNullOrEmpty(buildConfigFile.Postbuild))
                    {
                        this.cliOptions.PostBuildCommand    = buildConfigFile.Postbuild.Replace("\r\n", ";").Replace("\n", ";");
                        this.cliOptions.PostBuildScriptPath = null;
                        this.logger.LogDebug("Overriding the post-build commands with the BuildConfigurationFile section");
                        this.logger.LogDebug(this.cliOptions.PostBuildCommand.ToString());
                        this.writer.WriteLine("Overriding the post-build commands with the BuildConfigurationFile section");
                        this.writer.WriteLine("\t" + this.cliOptions.PostBuildCommand.ToString());
                    }
                }
                catch (Exception ex)
                {
                    this.logger.LogWarning("Invalid BuildConfigurationFile " + ex.ToString());
                    this.writer.WriteLine(Environment.NewLine + "\"" + DateTime.UtcNow.ToString("yyyy-MM-dd hh:mm:ss") + "\" | WARNING | Invalid BuildConfigurationFile | Exit Code: 1 | Please review your appsvc.yaml | " + Constants.BuildConfigurationFileHelp);
                    this.writer.WriteLine("This is the structure of a valid appsvc.yaml");
                    this.writer.WriteLine("-------------------------------------------");
                    this.writer.WriteLine("version: 1" + Environment.NewLine);
                    this.writer.WriteLine("pre-build: apt-get install xyz" + Environment.NewLine);
                    this.writer.WriteLine("post-build: |");
                    this.writer.WriteLine("  python manage.py makemigrations");
                    this.writer.WriteLine("  python manage.py migrate");
                    this.writer.WriteLine("-------------------------------------------");
                }
            }
            else
            {
                this.logger.LogDebug("No appsvc.yaml found");
            }

            (var preBuildCommand, var postBuildCommand) = PreAndPostBuildCommandHelper.GetPreAndPostBuildCommands(
                context.SourceRepo,
                this.cliOptions);

            var outputIsSubDirOfSourceDir = false;

            if (!string.IsNullOrEmpty(this.cliOptions.DestinationDir))
            {
                outputIsSubDirOfSourceDir = DirectoryHelper.IsSubDirectory(
                    this.cliOptions.DestinationDir,
                    this.cliOptions.SourceDir);
            }

            // Copy the source content to destination only if all the platforms involved in generating the build script
            // say yes.
            var copySourceDirectoryContentToDestinationDirectory = buildScriptSnippets.All(
                snippet => snippet.CopySourceDirectoryContentToDestinationDirectory);

            var buildScriptProps = new BaseBashBuildScriptProperties()
            {
                OsPackagesToInstall = this.cliOptions.RequiredOsPackages ?? Array.Empty <string>(),
                BuildScriptSnippets = buildScriptSnippets.Select(s => s.BashBuildScriptSnippet),
                BenvArgs            = benvArgs,
                PreBuildCommand     = preBuildCommand,
                PostBuildCommand    = postBuildCommand,
                DirectoriesToExcludeFromCopyToIntermediateDir = directoriesToExcludeFromCopyToIntermediateDir,
                DirectoriesToExcludeFromCopyToBuildOutputDir  = directoriesToExcludeFromCopyToBuildOutputDir,
                ManifestFileName      = FilePaths.BuildManifestFileName,
                ManifestDir           = context.ManifestDir,
                BuildCommandsFileName = context.BuildCommandsFileName,
                BuildProperties       = buildProperties,
                BenvPath   = FilePaths.Benv,
                LoggerPath = FilePaths.Logger,
                PlatformInstallationScript = installationScript,
                OutputDirectoryIsNested    = outputIsSubDirOfSourceDir,
                CopySourceDirectoryContentToDestinationDirectory = copySourceDirectoryContentToDestinationDirectory,
                CompressDestinationDir = this.cliOptions.CompressDestinationDir,
            };

            this.LogScriptIfGiven("pre-build", buildScriptProps.PreBuildCommand);
            this.LogScriptIfGiven("post-build", buildScriptProps.PostBuildCommand);

            script = TemplateHelper.Render(
                TemplateHelper.TemplateResource.BaseBashScript,
                buildScriptProps,
                this.logger);
            return(script);
        }
Example #2
0
        /// <summary>
        /// Builds the full build script from the list of snippets for each platform.
        /// </summary>
        /// <returns>Finalized build script as a string.</returns>
        private string BuildScriptFromSnippets(
            BuildScriptGeneratorContext context,
            string installationScript,
            IList <BuildScriptSnippet> buildScriptSnippets,
            IDictionary <string, string> toolsToVersion,
            List <string> directoriesToExcludeFromCopyToIntermediateDir,
            List <string> directoriesToExcludeFromCopyToBuildOutputDir,
            IEnumerable <PlatformDetectorResult> detectionResults)
        {
            string script;
            string benvArgs = StringExtensions.JoinKeyValuePairs(toolsToVersion);

            benvArgs = $"{benvArgs} {Constants.BenvDynamicInstallRootDirKey}=\"{_cliOptions.DynamicInstallRootDir}\"";

            Dictionary <string, string> buildProperties = buildScriptSnippets
                                                          .Where(s => s.BuildProperties != null)
                                                          .SelectMany(s => s.BuildProperties)
                                                          .ToDictionary(p => p.Key, p => p.Value);

            buildProperties[ManifestFilePropertyKeys.OperationId] = context.OperationId;

            var sourceDirInBuildContainer = _cliOptions.SourceDir;

            if (!string.IsNullOrEmpty(_cliOptions.IntermediateDir))
            {
                sourceDirInBuildContainer = _cliOptions.IntermediateDir;
            }

            buildProperties[ManifestFilePropertyKeys.SourceDirectoryInBuildContainer] = sourceDirInBuildContainer;

            var allPlatformNames = detectionResults
                                   .Where(s => s.Platform != null)
                                   .Select(s => s.Platform)
                                   .ToList();

            foreach (var eachPlatformName in allPlatformNames)
            {
                _logger.LogInformation($"Build Property Key:{ManifestFilePropertyKeys.PlatformName} value: {eachPlatformName} is written into manifest");
                if (buildProperties.ContainsKey(ManifestFilePropertyKeys.PlatformName))
                {
                    var previousValue = buildProperties[ManifestFilePropertyKeys.PlatformName];
                    buildProperties[ManifestFilePropertyKeys.PlatformName]
                        = string.Join(
                              ",",
                              previousValue,
                              eachPlatformName);
                }
                else
                {
                    buildProperties[ManifestFilePropertyKeys.PlatformName] = eachPlatformName;
                }
            }

            buildProperties[ManifestFilePropertyKeys.CompressDestinationDir] =
                _cliOptions.CompressDestinationDir.ToString().ToLower();

            (var preBuildCommand, var postBuildCommand) = PreAndPostBuildCommandHelper.GetPreAndPostBuildCommands(
                context.SourceRepo,
                _cliOptions);

            var outputIsSubDirOfSourceDir = false;

            if (!string.IsNullOrEmpty(_cliOptions.DestinationDir))
            {
                outputIsSubDirOfSourceDir = DirectoryHelper.IsSubDirectory(
                    _cliOptions.DestinationDir,
                    _cliOptions.SourceDir);
            }

            // Copy the source content to destination only if all the platforms involved in generating the build script
            // say yes.
            var copySourceDirectoryContentToDestinationDirectory = buildScriptSnippets.All(
                snippet => snippet.CopySourceDirectoryContentToDestinationDirectory);

            var buildScriptProps = new BaseBashBuildScriptProperties()
            {
                OsPackagesToInstall = _cliOptions.RequiredOsPackages ?? new string[0],
                BuildScriptSnippets = buildScriptSnippets.Select(s => s.BashBuildScriptSnippet),
                BenvArgs            = benvArgs,
                PreBuildCommand     = preBuildCommand,
                PostBuildCommand    = postBuildCommand,
                DirectoriesToExcludeFromCopyToIntermediateDir = directoriesToExcludeFromCopyToIntermediateDir,
                DirectoriesToExcludeFromCopyToBuildOutputDir  = directoriesToExcludeFromCopyToBuildOutputDir,
                ManifestFileName      = FilePaths.BuildManifestFileName,
                ManifestDir           = context.ManifestDir,
                BuildCommandsFileName = context.BuildCommandsFileName,
                BuildProperties       = buildProperties,
                BenvPath = FilePaths.Benv,
                PlatformInstallationScript = installationScript,
                OutputDirectoryIsNested    = outputIsSubDirOfSourceDir,
                CopySourceDirectoryContentToDestinationDirectory = copySourceDirectoryContentToDestinationDirectory,
                CompressDestinationDir = _cliOptions.CompressDestinationDir,
            };

            LogScriptIfGiven("pre-build", buildScriptProps.PreBuildCommand);
            LogScriptIfGiven("post-build", buildScriptProps.PostBuildCommand);

            script = TemplateHelper.Render(
                TemplateHelper.TemplateResource.BaseBashScript,
                buildScriptProps,
                _logger);
            return(script);
        }
Example #3
0
        /// <summary>
        /// Builds the full build script from the list of snippets for each platform.
        /// </summary>
        /// <returns>Finalized build script as a string.</returns>
        private string BuildScriptFromSnippets(
            BuildScriptGeneratorContext context,
            string installationScript,
            IList <BuildScriptSnippet> buildScriptSnippets,
            IDictionary <string, string> toolsToVersion,
            List <string> directoriesToExcludeFromCopyToIntermediateDir,
            List <string> directoriesToExcludeFromCopyToBuildOutputDir)
        {
            string script;
            string benvArgs = StringExtensions.JoinKeyValuePairs(toolsToVersion);

            Dictionary <string, string> buildProperties = buildScriptSnippets
                                                          .Where(s => s.BuildProperties != null)
                                                          .SelectMany(s => s.BuildProperties)
                                                          .ToDictionary(p => p.Key, p => p.Value);

            buildProperties[ManifestFilePropertyKeys.OperationId] = context.OperationId;

            (var preBuildCommand, var postBuildCommand) = PreAndPostBuildCommandHelper.GetPreAndPostBuildCommands(
                context.SourceRepo,
                _cliOptions);

            var outputIsSubDirOfSourceDir = false;

            if (!string.IsNullOrEmpty(_cliOptions.DestinationDir))
            {
                outputIsSubDirOfSourceDir = DirectoryHelper.IsSubDirectory(
                    _cliOptions.DestinationDir,
                    _cliOptions.SourceDir);
            }

            // Copy the source content to destination only if all the platforms involved in generating the build script
            // say yes.
            var copySourceDirectoryContentToDestinationDirectory = buildScriptSnippets.All(
                snippet => snippet.CopySourceDirectoryContentToDestinationDirectory);

            var buildScriptProps = new BaseBashBuildScriptProperties()
            {
                OsPackagesToInstall = _cliOptions.RequiredOsPackages ?? new string[0],
                BuildScriptSnippets = buildScriptSnippets.Select(s => s.BashBuildScriptSnippet),
                BenvArgs            = benvArgs,
                PreBuildCommand     = preBuildCommand,
                PostBuildCommand    = postBuildCommand,
                DirectoriesToExcludeFromCopyToIntermediateDir = directoriesToExcludeFromCopyToIntermediateDir,
                DirectoriesToExcludeFromCopyToBuildOutputDir  = directoriesToExcludeFromCopyToBuildOutputDir,
                ManifestFileName           = FilePaths.BuildManifestFileName,
                ManifestDir                = context.ManifestDir,
                BuildProperties            = buildProperties,
                BenvPath                   = FilePaths.Benv,
                PlatformInstallationScript = installationScript,
                OutputDirectoryIsNested    = outputIsSubDirOfSourceDir,
                CopySourceDirectoryContentToDestinationDirectory = copySourceDirectoryContentToDestinationDirectory,
            };

            LogScriptIfGiven("pre-build", buildScriptProps.PreBuildCommand);
            LogScriptIfGiven("post-build", buildScriptProps.PostBuildCommand);

            script = TemplateHelper.Render(
                TemplateHelper.TemplateResource.BaseBashScript,
                buildScriptProps,
                _logger);
            return(script);
        }
        public string GenerateDockerfile(DockerfileContext ctx)
        {
            var dockerfileBuildImageName = "build";
            var dockerfileBuildImageTag  = "azfunc-jamstack";

            var dockerfileRuntimeImage = !string.IsNullOrEmpty(this.commonOptions.RuntimePlatformName) ?
                                         ConvertToRuntimeName(this.commonOptions.RuntimePlatformName) : string.Empty;
            var dockerfileRuntimeImageTag = !string.IsNullOrEmpty(this.commonOptions.RuntimePlatformVersion) ?
                                            this.commonOptions.RuntimePlatformVersion : string.Empty;
            var compatiblePlatforms = this.GetCompatiblePlatforms(ctx);

            if (!compatiblePlatforms.Any())
            {
                throw new UnsupportedPlatformException(Labels.UnableToDetectPlatformMessage);
            }

            foreach (var platformAndDetectorResult in compatiblePlatforms)
            {
                var platform = platformAndDetectorResult.Key;
                var platformDetectorResult = platformAndDetectorResult.Value;
                var detectedRuntimeName    = ConvertToRuntimeName(platform.Name);

                // If the runtime platform name wasn't previously provided, see if we can use the current detected platform as the runtime image.
                if (string.IsNullOrEmpty(dockerfileRuntimeImage))
                {
                    // If the detected platform isn't in our currently list of runtime versions, skip it with a notice to the user.
                    if (!this.supportedRuntimeVersions.ContainsKey(detectedRuntimeName))
                    {
                        this.logger.LogDebug($"The detected platform {platform.Name} does not currently have a supported runtime image." +
                                             $"If this Dockerfile command or image is outdated, please provide the runtime platform name manually.");
                        continue;
                    }

                    dockerfileRuntimeImage = detectedRuntimeName;
                }

                // If the runtime platform version wasn't previously provided, see if we can detect one from the current detected platform.
                // Note: we first need to ensure that the current detected platform is the same as the runtime platform name previously set or pvodied.
                if (!string.IsNullOrEmpty(dockerfileRuntimeImage) && dockerfileRuntimeImage.Equals(detectedRuntimeName, StringComparison.OrdinalIgnoreCase) &&
                    string.IsNullOrEmpty(dockerfileRuntimeImageTag))
                {
                    dockerfileRuntimeImageTag = this.ConvertToRuntimeVersion(dockerfileRuntimeImage, platformDetectorResult.PlatformVersion);
                }

                // If the runtime image has been set manually or by the platform detection result, stop searching.
                if (!string.IsNullOrEmpty(dockerfileRuntimeImage))
                {
                    break;
                }
            }

            var properties = new DockerfileProperties()
            {
                RuntimeImageName = dockerfileRuntimeImage,
                RuntimeImageTag  = dockerfileRuntimeImageTag,
                BuildImageName   = dockerfileBuildImageName,
                BuildImageTag    = dockerfileBuildImageTag,
            };

            return(TemplateHelper.Render(
                       TemplateHelper.TemplateResource.Dockerfile,
                       properties,
                       this.logger));
        }