예제 #1
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,
            IList <BuildScriptSnippet> snippets,
            IDictionary <string, string> toolsToVersion,
            List <string> directoriesToExcludeFromCopyToIntermediateDir,
            List <string> directoriesToExcludeFromCopyToBuildOutputDir)
        {
            string script;
            string benvArgs = GetBenvArgs(toolsToVersion);

            _environmentSettingsProvider.TryGetAndLoadSettings(out var environmentSettings);

            Dictionary <string, string> buildProperties = snippets
                                                          .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,
                environmentSettings);

            var buildScriptProps = new BaseBashBuildScriptProperties()
            {
                BuildScriptSnippets = snippets.Select(s => s.BashBuildScriptSnippet),
                BenvArgs            = benvArgs,
                PreBuildCommand     = preBuildCommand,
                PostBuildCommand    = postBuildCommand,
                DirectoriesToExcludeFromCopyToIntermediateDir = directoriesToExcludeFromCopyToIntermediateDir,
                DirectoriesToExcludeFromCopyToBuildOutputDir  = directoriesToExcludeFromCopyToBuildOutputDir,
                ManifestFileName = FilePaths.BuildManifestFileName,
                BuildProperties  = buildProperties
            };

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

            script = TemplateHelpers.Render(
                TemplateHelpers.TemplateResource.BaseBashScript,
                buildScriptProps,
                _logger);
            return(script);
        }
예제 #2
0
 /// <summary>
 /// Handles the error when no platform was found, logging information about the repo.
 /// </summary>
 private void LogAndThrowNoPlatformFound(BuildScriptGeneratorContext context)
 {
     try
     {
         var directoryStructureData = OryxDirectoryStructureHelper.GetDirectoryStructure(
             context.SourceRepo.RootPath);
         _logger.LogTrace(
             "logDirectoryStructure",
             new Dictionary <string, string> {
             { "directoryStructure", directoryStructureData }
         });
     }
     catch (Exception ex)
     {
         _logger.LogError(ex, "Exception caught");
     }
     finally
     {
         throw new UnsupportedLanguageException("Could not detect the language from repo.");
     }
 }
예제 #3
0
        /// <summary>
        /// Gets the installation script snippet which contains snippets for all detected platforms.
        /// </summary>
        /// <param name="context">The <see cref="RepositoryContext"/>.</param>
        /// <param name="detectionResults">Already detected platforms results.</param>
        /// <returns>A snippet having logic to install all detected platforms.</returns>
        public string GetBashScriptSnippet(
            BuildScriptGeneratorContext context,
            IEnumerable <PlatformDetectorResult> detectionResults = null)
        {
            var scriptBuilder = new StringBuilder();

            // Avoid detecting again if detection was already run.
            if (detectionResults == null)
            {
                detectionResults = _platformDetector.DetectPlatforms(context);
            }

            var snippets = GetInstallationScriptSnippets(detectionResults, context);

            foreach (var snippet in snippets)
            {
                scriptBuilder.AppendLine(snippet);
                scriptBuilder.AppendLine();
            }

            return(scriptBuilder.ToString());
        }
        public bool TryGenerateBashScript(BuildScriptGeneratorContext context, out string script)
        {
            script = null;

            var toolsToVersion = new Dictionary <string, string>();
            List <BuildScriptSnippet> snippets;
            var directoriesToExcludeFromCopyToIntermediateDir = new List <string>();
            var directoriesToExcludeFromCopyToBuildOutputDir  = new List <string>();

            using (var timedEvent = _logger.LogTimedEvent("GetBuildSnippets"))
            {
                snippets = GetBuildSnippets(
                    context,
                    toolsToVersion,
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir);
                timedEvent.SetProperties(toolsToVersion);
            }

            if (snippets.Any())
            {
                // By default exclude these irrespective of platform
                directoriesToExcludeFromCopyToIntermediateDir.Add(".git");
                directoriesToExcludeFromCopyToBuildOutputDir.Add(".git");

                script = BuildScriptFromSnippets(
                    snippets,
                    toolsToVersion,
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir);
                return(true);
            }
            else
            {
                LogAndThrowNoPlatformFound(context);
                return(false);
            }
        }
        private IEnumerable <string> GetInstallationScriptSnippets(
            IEnumerable <PlatformDetectorResult> detectionResults,
            BuildScriptGeneratorContext context)
        {
            var installationScriptSnippets = new List <string>();

            foreach (var detectionResult in detectionResults)
            {
                var platform = this.platforms
                               .Where(p => p.Name.EqualsIgnoreCase(detectionResult.Platform))
                               .First();

                var snippet = platform.GetInstallerScriptSnippet(context, detectionResult);
                if (!string.IsNullOrEmpty(snippet))
                {
                    this.outputWriter.WriteLine(
                        $"Version '{detectionResult.PlatformVersion}' of platform '{detectionResult.Platform}' " +
                        $"is not installed. Generating script to install it...");
                    installationScriptSnippets.Add(snippet);
                }
            }

            return(installationScriptSnippets);
        }
예제 #6
0
        public bool TryGenerateBashScript(BuildScriptGeneratorContext context, out string script)
        {
            script = null;

            var toolsToVersion = new Dictionary <string, string>();
            List <BuildScriptSnippet> snippets;

            using (var timedEvent = _logger.LogTimedEvent("GetBuildSnippets"))
            {
                snippets = GetBuildSnippets(context, toolsToVersion);
                timedEvent.SetProperties(toolsToVersion);
            }

            if (snippets.Any())
            {
                script = BuildScriptFromSnippets(snippets, toolsToVersion);
                return(true);
            }
            else
            {
                LogAndThrowNoPlatformFound(context);
                return(false);
            }
        }
예제 #7
0
        public void GenerateBashScript(
            BuildScriptGeneratorContext context,
            out string script,
            List <ICheckerMessage> checkerMessageSink = null)
        {
            script = null;

            // To be populated by GetBuildSnippets
            var toolsToVersion = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            IList <BuildScriptSnippet> snippets;
            var directoriesToExcludeFromCopyToIntermediateDir = new List <string>();
            var directoriesToExcludeFromCopyToBuildOutputDir  = new List <string>();

            using (var timedEvent = _logger.LogTimedEvent("GetBuildSnippets"))
            {
                snippets = GetBuildSnippets(
                    context,
                    toolsToVersion,
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir);
                timedEvent.SetProperties(toolsToVersion);
            }

            if (_checkers != null && checkerMessageSink != null && context.EnableCheckers)
            {
                try
                {
                    _logger.LogDebug("Running checkers");
                    RunCheckers(context, toolsToVersion, checkerMessageSink);
                }
                catch (Exception exc)
                {
                    _logger.LogError(exc, "Exception caught while running checkers");
                }
            }
            else
            {
                _logger.LogInformation("Not running checkers - condition evaluates to " +
                                       "({checkersNotNull} && {sinkNotNull} && {enableCheckers})",
                                       _checkers != null, checkerMessageSink != null, context.EnableCheckers);
            }

            if (snippets != null)
            {
                foreach (var snippet in snippets)
                {
                    if (snippet.IsFullScript)
                    {
                        script = snippet.BashBuildScriptSnippet;
                        return;
                    }
                }
            }

            if (snippets.Any())
            {
                // By default exclude these irrespective of platform
                directoriesToExcludeFromCopyToIntermediateDir.Add(".git");
                directoriesToExcludeFromCopyToBuildOutputDir.Add(".git");

                script = BuildScriptFromSnippets(
                    context,
                    snippets,
                    new ReadOnlyDictionary <string, string>(toolsToVersion),
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir);
            }
            else
            {
                // TODO: Should an UnsupportedLanguageException be thrown here?
                // Seeing as the issue was that platforms were IDENTIFIED, but no build snippets were emitted from them
                throw new UnsupportedPlatformException(Labels.UnableToDetectPlatformMessage);
            }
        }
예제 #8
0
 public IDictionary <IProgrammingPlatform, string> GetCompatiblePlatforms(BuildScriptGeneratorContext ctx)
 {
     return(_platformDetector.GetCompatiblePlatforms(ctx, ctx.Language, ctx.LanguageVersion));
 }
예제 #9
0
        public void GenerateBashScript(
            BuildScriptGeneratorContext context,
            out string script,
            List <ICheckerMessage> checkerMessageSink = null)
        {
            script = null;

            IList <BuildScriptSnippet> buildScriptSnippets;
            var directoriesToExcludeFromCopyToIntermediateDir = new List <string>();
            var directoriesToExcludeFromCopyToBuildOutputDir  = new List <string>();

            // Try detecting ALL platforms since in some scenarios this is required.
            // For example, in case of a multi-platform app like ASP.NET Core + NodeJs, we might need to dynamically
            // install both these platforms' sdks before actually using any of their commands. So even though a user
            // of Oryx might explicitly supply the platform of the app as .NET Core, we still need to make sure the
            // build environment is setup with detected platforms' sdks.
            var platformInfos      = this.platformsInformationProvider.GetPlatformsInfo(context);
            var detectionResults   = platformInfos.Select(pi => pi.DetectorResult);
            var installationScript = this.environmentSetupScriptProvider.GetBashScriptSnippet(
                context,
                detectionResults);

            // Get list of tools to be set on benv
            var toolsToVersion = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            foreach (var toolsToBeSetInPath in platformInfos
                     .Where(pi => pi.RequiredToolsInPath != null)
                     .Select(pi => pi.RequiredToolsInPath))
            {
                foreach (var toolNameAndVersion in toolsToBeSetInPath)
                {
                    if (!string.IsNullOrEmpty(
                            Environment.GetEnvironmentVariable(toolNameAndVersion.Key)))
                    {
                        this.logger.LogInformation($"If {toolNameAndVersion.Key} is set as environment, it'll be not be set via benv");
                    }
                    else
                    {
                        this.logger.LogInformation($"If {toolNameAndVersion.Key} is not set as environment, it'll be set to {toolNameAndVersion.Value} via benv");
                        toolsToVersion[toolNameAndVersion.Key] = toolNameAndVersion.Value;
                    }
                }
            }

            using (var timedEvent = this.logger.LogTimedEvent("GetBuildSnippets"))
            {
                buildScriptSnippets = this.GetBuildSnippets(
                    context,
                    detectionResults,
                    runDetection: false,
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir);
                timedEvent.SetProperties(toolsToVersion);
            }

            if (this.checkers != null && checkerMessageSink != null && this.cliOptions.EnableCheckers)
            {
                try
                {
                    this.logger.LogDebug("Running checkers");
                    this.RunCheckers(context, toolsToVersion, checkerMessageSink);
                }
                catch (Exception exc)
                {
                    this.logger.LogError(exc, "Exception caught while running checkers");
                }
            }
            else
            {
                this.logger.LogInformation(
                    "Not running checkers - condition evaluates to " +
                    "({checkersNotNull} && {sinkNotNull} && {enableCheckers})",
                    this.checkers != null,
                    checkerMessageSink != null,
                    this.cliOptions.EnableCheckers);
            }

            if (buildScriptSnippets != null)
            {
                foreach (var snippet in buildScriptSnippets)
                {
                    if (snippet.IsFullScript)
                    {
                        script = snippet.BashBuildScriptSnippet;
                        return;
                    }
                }
            }

            if (buildScriptSnippets.Any())
            {
                // By default exclude these irrespective of platform
                directoriesToExcludeFromCopyToIntermediateDir.Add(".git");
                directoriesToExcludeFromCopyToBuildOutputDir.Add(".git");

                script = this.BuildScriptFromSnippets(
                    context,
                    installationScript,
                    buildScriptSnippets,
                    new ReadOnlyDictionary <string, string>(toolsToVersion),
                    directoriesToExcludeFromCopyToIntermediateDir,
                    directoriesToExcludeFromCopyToBuildOutputDir,
                    detectionResults);
            }
            else
            {
                // TODO: Should an UnsupportedPlatformException be thrown here?
                // Seeing as the issue was that platforms were IDENTIFIED, but no build snippets were emitted from them
                throw new UnsupportedPlatformException(Labels.UnableToDetectPlatformMessage);
            }
        }
예제 #10
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}=\"{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);
        }
예제 #11
0
        private IList <BuildScriptSnippet> GetBuildSnippets(
            BuildScriptGeneratorContext context,
            IEnumerable <PlatformDetectorResult> detectionResults,
            bool runDetection,
            [CanBeNull] List <string> directoriesToExcludeFromCopyToIntermediateDir,
            [CanBeNull] List <string> directoriesToExcludeFromCopyToBuildOutputDir)
        {
            var snippets = new List <BuildScriptSnippet>();

            IDictionary <IProgrammingPlatform, PlatformDetectorResult> platformsToUse;

            if (runDetection)
            {
                platformsToUse = this.compatiblePlatformDetector.GetCompatiblePlatforms(context);
            }
            else
            {
                platformsToUse = this.compatiblePlatformDetector.GetCompatiblePlatforms(context, detectionResults);
            }

            foreach (var platformAndDetectorResult in platformsToUse)
            {
                var(platform, detectorResult) = platformAndDetectorResult;

                if (directoriesToExcludeFromCopyToIntermediateDir != null)
                {
                    var excludedDirs = platform.GetDirectoriesToExcludeFromCopyToIntermediateDir(context);
                    if (excludedDirs.Any())
                    {
                        directoriesToExcludeFromCopyToIntermediateDir.AddRange(excludedDirs);
                    }
                }

                if (directoriesToExcludeFromCopyToBuildOutputDir != null)
                {
                    var excludedDirs = platform.GetDirectoriesToExcludeFromCopyToBuildOutputDir(context);
                    if (excludedDirs.Any())
                    {
                        directoriesToExcludeFromCopyToBuildOutputDir.AddRange(excludedDirs);
                    }
                }

                string cleanOrNot = platform.IsCleanRepo(context.SourceRepo) ? "clean" : "not clean";
                this.logger.LogDebug($"Repo is {cleanOrNot} for {platform.Name}");

                var snippet = platform.GenerateBashBuildScriptSnippet(context, detectorResult);
                if (snippet != null)
                {
                    this.logger.LogDebug(
                        "Platform {platformName} with version {platformVersion} was used.",
                        platform.Name,
                        detectorResult.PlatformVersion);
                    snippets.Add(snippet);
                }
                else
                {
                    this.logger.LogWarning(
                        "{platformType}.GenerateBashBuildScriptSnippet() returned null",
                        platform.GetType());
                }
            }

            return(snippets);
        }
예제 #12
0
        public IList <Tuple <IProgrammingPlatform, string> > GetCompatiblePlatforms(BuildScriptGeneratorContext ctx)
        {
            var resultPlatforms = new List <Tuple <IProgrammingPlatform, string> >();

            var enabledPlatforms = _programmingPlatforms.Where(p =>
            {
                if (!p.IsEnabled(ctx))
                {
                    _logger.LogDebug("{platformName} has been disabled", p.Name);
                    return(false);
                }
                return(true);
            });

            // If a user supplied the language explicitly, check if the platform is enabled for that
            IProgrammingPlatform userSuppliedPlatform = null;
            string platformVersion = null;

            if (!string.IsNullOrEmpty(ctx.Language))
            {
                var selectedPlatform = enabledPlatforms
                                       .Where(p => string.Equals(ctx.Language, p.Name, StringComparison.OrdinalIgnoreCase))
                                       .FirstOrDefault();

                if (selectedPlatform == null)
                {
                    ThrowInvalidLanguageProvided(ctx);
                }

                userSuppliedPlatform = selectedPlatform;

                platformVersion = ctx.LanguageVersion;
                if (string.IsNullOrEmpty(platformVersion))
                {
                    var detectionResult = userSuppliedPlatform.Detect(ctx.SourceRepo);
                    if (detectionResult == null || string.IsNullOrEmpty(detectionResult.LanguageVersion))
                    {
                        throw new UnsupportedVersionException(
                                  $"Couldn't detect a version for the platform '{userSuppliedPlatform.Name}' in the repo.");
                    }

                    platformVersion = detectionResult.LanguageVersion;
                }

                resultPlatforms.Add(Tuple.Create(userSuppliedPlatform, platformVersion));

                // if the user explicitly supplied a platform and if that platform does not want to be part of
                // multi-platform builds, then short-circuit immediately ignoring going through other platforms
                if (!IsEnabledForMultiPlatformBuild(userSuppliedPlatform, ctx))
                {
                    return(resultPlatforms);
                }
            }

            // Ignore processing the same platform again
            if (userSuppliedPlatform != null)
            {
                enabledPlatforms = enabledPlatforms.Where(p => !ReferenceEquals(p, userSuppliedPlatform));
            }

            foreach (var platform in enabledPlatforms)
            {
                string targetVersionSpec = null;

                _logger.LogDebug("Detecting platform using {platformName}", platform.Name);
                var detectionResult = platform.Detect(ctx.SourceRepo);
                if (detectionResult != null)
                {
                    _logger.LogDebug(
                        "Detected {platformName} version {platformVersion} for app in repo",
                        platform.Name,
                        detectionResult.LanguageVersion);

                    targetVersionSpec = detectionResult.LanguageVersion;
                    if (string.IsNullOrEmpty(targetVersionSpec))
                    {
                        throw new UnsupportedVersionException(
                                  $"Couldn't detect a version for the platform '{platform.Name}' in the repo.");
                    }

                    resultPlatforms.Add(Tuple.Create(platform, targetVersionSpec));

                    if (!IsEnabledForMultiPlatformBuild(platform, ctx))
                    {
                        return(resultPlatforms);
                    }
                }
            }

            return(resultPlatforms);
        }
예제 #13
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);
        }
예제 #14
0
        private List <BuildScriptSnippet> GetBuildSnippets(BuildScriptGeneratorContext context, Dictionary <string, string> toolsToVersion)
        {
            bool providedLanguageFound = false;
            var  snippets = new List <BuildScriptSnippet>();

            foreach (var platform in _programmingPlatforms)
            {
                if (!platform.IsEnabled(context))
                {
                    _logger.LogDebug("{platformName} has been disabled", platform.Name);
                    continue;
                }

                bool usePlatform = false;
                var  currPlatformMatchesProvided = !string.IsNullOrEmpty(context.Language) &&
                                                   string.Equals(context.Language, platform.Name, StringComparison.OrdinalIgnoreCase);

                string targetVersionSpec = null;
                if (currPlatformMatchesProvided)
                {
                    providedLanguageFound = true;
                    targetVersionSpec     = context.LanguageVersion;
                    usePlatform           = true;
                }
                else if (context.DisableMultiPlatformBuild && !string.IsNullOrEmpty(context.Language))
                {
                    _logger.LogDebug("Multi platform build is disabled and platform was specified. Skipping language {skippedLang}", platform.Name);
                    continue;
                }

                if (!currPlatformMatchesProvided || string.IsNullOrEmpty(targetVersionSpec))
                {
                    _logger.LogDebug("Detecting platform using {platformName}", platform.Name);
                    var detectionResult = platform.Detect(context.SourceRepo);
                    if (detectionResult != null)
                    {
                        _logger.LogDebug("Detected {platformName} version {platformVersion} for app in repo", platform.Name, detectionResult.LanguageVersion);
                        usePlatform       = true;
                        targetVersionSpec = detectionResult.LanguageVersion;
                        if (string.IsNullOrEmpty(targetVersionSpec))
                        {
                            throw new UnsupportedVersionException($"Couldn't detect a version for the platform '{platform.Name}' in the repo.");
                        }
                    }
                }

                if (usePlatform)
                {
                    string targetVersion = GetMatchingTargetVersion(platform, targetVersionSpec);
                    platform.SetVersion(context, targetVersion);

                    string cleanOrNot = platform.IsCleanRepo(context.SourceRepo) ? "clean" : "not clean";
                    _logger.LogDebug($"Repo is {cleanOrNot} for {platform.Name}");

                    var snippet = platform.GenerateBashBuildScriptSnippet(context);
                    if (snippet != null)
                    {
                        _logger.LogDebug("Script generator {scriptGenType} was used", platform.GetType());
                        snippets.Add(snippet);
                        platform.SetRequiredTools(context.SourceRepo, targetVersion, toolsToVersion);
                    }
                    else
                    {
                        _logger.LogDebug("Script generator {scriptGenType} cannot be used", platform.GetType());
                    }
                }
            }

            // Even if a language was detected, we throw an error if the user provided an unsupported language as target.
            if (!string.IsNullOrEmpty(context.Language) && !providedLanguageFound)
            {
                ThrowInvalidLanguageProvided(context);
            }

            return(snippets);
        }
예제 #15
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);
        }