internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var scriptGenerator = new BuildScriptGenerator( serviceProvider, console, checkerMessageSink: null, operationId: null); if (!scriptGenerator.TryGenerateScript(out var generatedScript)) { return(ProcessConstants.ExitFailure); } if (string.IsNullOrEmpty(OutputPath)) { console.WriteLine(generatedScript); } else { OutputPath.SafeWriteAllText(generatedScript); console.WriteLine($"Script written to '{OutputPath}'"); // Try making the script executable ProcessHelper.TrySetExecutableMode(OutputPath); } return(ProcessConstants.ExitSuccess); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var scriptGenerator = new BuildScriptGenerator(console, serviceProvider); if (!scriptGenerator.TryGenerateScript(out var generatedScript)) { return(ProcessConstants.ExitFailure); } console.WriteLine(generatedScript); return(ProcessConstants.ExitSuccess); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var scriptGenerator = new BuildScriptGenerator( serviceProvider, console, checkerMessageSink: null, operationId: null); if (!scriptGenerator.TryGenerateScript(out var generatedScript)) { return(ProcessConstants.ExitFailure); } console.WriteLine(generatedScript); return(ProcessConstants.ExitSuccess); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var generator = serviceProvider.GetRequiredService <IBuildScriptGenerator>(); var ctx = BuildScriptGenerator.CreateContext(serviceProvider, operationId: null); var compatPlats = generator.GetCompatiblePlatforms(ctx); if (compatPlats != null && compatPlats.Any()) { console.WriteLine("Detected platforms:"); console.WriteLine(string.Join(' ', compatPlats.Select(pair => $"{pair.Item1.Name}=\"{pair.Item2}\""))); // Write the detected platforms into the build plan as TOML File.WriteAllLines(PlanPath, compatPlats.Select(pair => $"{pair.Item1.Name} = {{ version = \"{pair.Item2}\" }}")); return(ProcessConstants.ExitSuccess); } return(DetectorFailCode); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var generator = serviceProvider.GetRequiredService <IBuildScriptGenerator>(); var options = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; var env = serviceProvider.GetRequiredService <CliEnvironmentSettings>(); var repo = serviceProvider.GetRequiredService <ISourceRepoProvider>().GetSourceRepo(); var ctx = BuildScriptGenerator.CreateContext(options, env, repo, operationId: null); var compatPlats = generator.GetCompatiblePlatforms(ctx); if (compatPlats != null && compatPlats.Any()) { console.WriteLine("# Detected platforms:"); console.WriteLine(string.Join(' ', compatPlats.Select(pair => $"{pair.Item1.Name}=\"{pair.Item2}\""))); return(ProcessConstants.ExitSuccess); } return(DetectorFailCode); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var logger = serviceProvider.GetRequiredService <ILogger <ExecCommand> >(); var env = serviceProvider.GetRequiredService <IEnvironment>(); var opts = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; var beginningOutputLog = GetBeginningCommandOutputLog(); console.WriteLine(beginningOutputLog); if (string.IsNullOrWhiteSpace(Command)) { logger.LogDebug("Command is empty; exiting"); return(ProcessConstants.ExitSuccess); } var shellPath = env.GetEnvironmentVariable("BASH") ?? FilePaths.Bash; var context = BuildScriptGenerator.CreateContext(serviceProvider, operationId: null); var detector = serviceProvider.GetRequiredService <DefaultPlatformDetector>(); var detectedPlatforms = detector.DetectPlatforms(context); if (!detectedPlatforms.Any()) { return(ProcessConstants.ExitFailure); } int exitCode; using (var timedEvent = logger.LogTimedEvent("ExecCommand")) { // Build envelope script var scriptBuilder = new ShellScriptBuilder("\n") .AddShebang(shellPath) .AddCommand("set -e"); var envSetupProvider = serviceProvider.GetRequiredService <PlatformsInstallationScriptProvider>(); var installationScript = envSetupProvider.GetBashScriptSnippet( context, detectedPlatforms); if (!string.IsNullOrEmpty(installationScript)) { scriptBuilder.AddCommand(installationScript); } scriptBuilder.Source( $"{FilePaths.Benv} " + $"{string.Join(" ", detectedPlatforms.Select(p => $"{p.Platform}={p.PlatformVersion}"))}"); scriptBuilder .AddCommand("echo Executing supplied command...") .AddCommand(Command); // Create temporary file to store script // Get the path where the generated script should be written into. var tempDirectoryProvider = serviceProvider.GetRequiredService <ITempDirectoryProvider>(); var tempScriptPath = Path.Combine(tempDirectoryProvider.GetTempDirectory(), "execCommand.sh"); var script = scriptBuilder.ToString(); File.WriteAllText(tempScriptPath, script); console.WriteLine("Finished generating script."); timedEvent.AddProperty(nameof(tempScriptPath), tempScriptPath); if (DebugMode) { console.WriteLine($"Temporary script @ {tempScriptPath}:"); console.WriteLine("---"); console.WriteLine(script); console.WriteLine("---"); } console.WriteLine(); console.WriteLine("Executing generated script..."); console.WriteLine(); exitCode = ProcessHelper.RunProcess( shellPath, new[] { tempScriptPath }, opts.SourceDir, (sender, args) => { if (args.Data != null) { console.WriteLine(args.Data); } }, (sender, args) => { if (args.Data != null) { console.Error.WriteLine(args.Data); } }, waitTimeForExit: null); timedEvent.AddProperty("exitCode", exitCode.ToString()); } return(exitCode); }
// To enable unit testing internal int Execute( IServiceProvider serviceProvider, IConsole console, DataReceivedEventHandler stdOutHandler, DataReceivedEventHandler stdErrHandler) { var logger = serviceProvider.GetRequiredService <ILogger <BuildCommand> >(); // This will be an App Service app name if Oryx was invoked by Kudu var appName = Environment.GetEnvironmentVariable( LoggingConstants.AppServiceAppNameEnvironmentVariableName) ?? ".oryx"; var buildOpId = logger.StartOperation(appName); console.WriteLine("Build orchestrated by Microsoft Oryx, https://github.com/Microsoft/Oryx"); console.WriteLine("You can report issues at https://github.com/Microsoft/Oryx/issues"); console.WriteLine(); var buildInfo = new DefinitionListFormatter(); buildInfo.AddDefinition("Oryx Version", $"{Program.GetVersion()}, Commit: {Program.GetCommit()}"); buildInfo.AddDefinition("Build Operation ID", buildOpId); var sourceRepo = serviceProvider.GetRequiredService <ISourceRepoProvider>().GetSourceRepo(); var commitId = GetSourceRepoCommitId( serviceProvider.GetRequiredService <IEnvironment>(), sourceRepo, logger); if (!string.IsNullOrWhiteSpace(commitId)) { buildInfo.AddDefinition("Repository Commit", commitId); } console.WriteLine(buildInfo.ToString()); // Try writing the ID to a file in the source directory try { using (logger.LogTimedEvent("WriteBuildIdFile")) using (var idFileWriter = new StreamWriter( Path.Combine(sourceRepo.RootPath, Common.FilePaths.BuildIdFileName))) { idFileWriter.Write(buildOpId); } } catch (Exception exc) { logger.LogError(exc, "Exception caught while trying to write build ID file"); } var environmentSettingsProvider = serviceProvider.GetRequiredService <IEnvironmentSettingsProvider>(); if (!environmentSettingsProvider.TryGetAndLoadSettings(out var environmentSettings)) { return(ProcessConstants.ExitFailure); } // Generate build script string scriptContent; using (var stopwatch = logger.LogTimedEvent("GenerateBuildScript")) { var scriptGenerator = new BuildScriptGenerator(console, serviceProvider); if (!scriptGenerator.TryGenerateScript(out scriptContent)) { stopwatch.AddProperty("failed", "true"); return(ProcessConstants.ExitFailure); } } // Get the path where the generated script should be written into. var tempDirectoryProvider = serviceProvider.GetRequiredService <ITempDirectoryProvider>(); var buildScriptPath = Path.Combine(tempDirectoryProvider.GetTempDirectory(), "build.sh"); // Write build script to selected path File.WriteAllText(buildScriptPath, scriptContent); logger.LogTrace("Build script written to file"); var buildEventProps = new Dictionary <string, string>() { { "oryxVersion", Program.GetVersion() }, { "oryxCommitId", Program.GetCommit() }, { "oryxCommandLine", string.Join( ' ', serviceProvider.GetRequiredService <IEnvironment>().GetCommandLineArgs()) }, { nameof(commitId), commitId }, { "scriptPath", buildScriptPath }, { "envVars", string.Join(",", GetEnvVarNames(serviceProvider.GetRequiredService <IEnvironment>())) }, }; var buildScriptOutput = new StringBuilder(); var stdOutEventLogger = new TextSpanEventLogger(logger, _measurableStdOutSpans); DataReceivedEventHandler stdOutBaseHandler = (sender, args) => { string line = args.Data; if (line == null) { return; } console.WriteLine(line); buildScriptOutput.AppendLine(line); stdOutEventLogger.CheckString(line); }; DataReceivedEventHandler stdErrBaseHandler = (sender, args) => { string line = args.Data; if (line == null) { return; } console.Error.WriteLine(args.Data); buildScriptOutput.AppendLine(args.Data); }; // Try make the pre-build & post-build scripts executable ProcessHelper.TrySetExecutableMode(environmentSettings.PreBuildScriptPath); ProcessHelper.TrySetExecutableMode(environmentSettings.PostBuildScriptPath); // Run the generated script var options = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; int exitCode; using (var timedEvent = logger.LogTimedEvent("RunBuildScript", buildEventProps)) { exitCode = serviceProvider.GetRequiredService <IScriptExecutor>().ExecuteScript( buildScriptPath, new[] { sourceRepo.RootPath, options.DestinationDir ?? string.Empty, options.IntermediateDir ?? string.Empty }, workingDirectory: sourceRepo.RootPath, stdOutHandler == null ? stdOutBaseHandler : stdOutBaseHandler + stdOutHandler, stdErrHandler == null ? stdErrBaseHandler : stdErrBaseHandler + stdErrHandler); } logger.LogDebug("Build script content:\n" + scriptContent); logger.LogDebug("Build script output:\n" + buildScriptOutput.ToString()); if (exitCode != ProcessConstants.ExitSuccess) { logger.LogError("Build script exited with {exitCode}", exitCode); return(exitCode); } return(ProcessConstants.ExitSuccess); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var logger = serviceProvider.GetRequiredService <ILogger <PrepareEnvironmentCommand> >(); var options = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; var beginningOutputLog = GetBeginningCommandOutputLog(); console.WriteLine(beginningOutputLog); int exitCode; using (var timedEvent = logger.LogTimedEvent("EnvSetupCommand")) { var context = BuildScriptGenerator.CreateContext(serviceProvider, operationId: null); IEnumerable <PlatformDetectorResult> detectedPlatforms = null; if (SkipDetection) { console.WriteLine( $"Skipping platform detection since '{SkipDetectionTemplate}' switch was used..."); var platforms = serviceProvider.GetRequiredService <IEnumerable <IProgrammingPlatform> >(); if (TryValidateSuppliedPlatformsAndVersions( platforms, PlatformsAndVersions, PlatformsAndVersionsFile, console, out var results)) { detectedPlatforms = results; } else { console.WriteErrorLine( $"Invalid value for switch '{PlatformsAndVersionsTemplate}'."); return(ProcessConstants.ExitFailure); } } else { var detector = serviceProvider.GetRequiredService <DefaultPlatformsInformationProvider>(); var platformInfos = detector.GetPlatformsInfo(context); if (!platformInfos.Any()) { return(ProcessConstants.ExitFailure); } detectedPlatforms = platformInfos.Select(pi => pi.DetectorResult); } var environmentScriptProvider = serviceProvider.GetRequiredService <PlatformsInstallationScriptProvider>(); var snippet = environmentScriptProvider.GetBashScriptSnippet(context, detectedPlatforms); var scriptBuilder = new StringBuilder() .AppendLine($"#!{FilePaths.Bash}") .AppendLine("set -e") .AppendLine(); if (!string.IsNullOrEmpty(snippet)) { scriptBuilder .AppendLine("echo") .AppendLine("echo Setting up environment...") .AppendLine("echo") .AppendLine(snippet) .AppendLine("echo") .AppendLine("echo Done setting up environment.") .AppendLine("echo"); } // Create temporary file to store script // Get the path where the generated script should be written into. var tempDirectoryProvider = serviceProvider.GetRequiredService <ITempDirectoryProvider>(); var tempScriptPath = Path.Combine(tempDirectoryProvider.GetTempDirectory(), "setupEnvironment.sh"); var script = scriptBuilder.ToString(); File.WriteAllText(tempScriptPath, script); timedEvent.AddProperty(nameof(tempScriptPath), tempScriptPath); if (DebugMode) { console.WriteLine($"Temporary script @ {tempScriptPath}:"); console.WriteLine("---"); console.WriteLine(scriptBuilder); console.WriteLine("---"); } var environment = serviceProvider.GetRequiredService <IEnvironment>(); var shellPath = environment.GetEnvironmentVariable("BASH") ?? FilePaths.Bash; exitCode = ProcessHelper.RunProcess( shellPath, new[] { tempScriptPath }, options.SourceDir, (sender, args) => { if (args.Data != null) { console.WriteLine(args.Data); } }, (sender, args) => { if (args.Data != null) { console.Error.WriteLine(args.Data); } }, waitTimeForExit: null); timedEvent.AddProperty("exitCode", exitCode.ToString()); } return(exitCode); }
// To enable unit testing internal int Execute( IServiceProvider serviceProvider, IConsole console, DataReceivedEventHandler stdOutHandler, DataReceivedEventHandler stdErrHandler) { var logger = serviceProvider.GetRequiredService <ILogger <BuildCommand> >(); var buildOperationId = logger.StartOperation( BuildOperationName(serviceProvider.GetRequiredService <IEnvironment>())); var options = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; console.WriteLine("Build orchestrated by Microsoft Oryx, https://github.com/Microsoft/Oryx"); console.WriteLine("You can report issues at https://github.com/Microsoft/Oryx/issues"); console.WriteLine(); var buildInfo = new DefinitionListFormatter(); buildInfo.AddDefinition("Oryx Version", $"{Program.GetVersion()}, Commit: {Program.GetCommit()}"); buildInfo.AddDefinition("Build Operation ID", buildOperationId); var sourceRepo = serviceProvider.GetRequiredService <ISourceRepoProvider>().GetSourceRepo(); var commitId = GetSourceRepoCommitId( serviceProvider.GetRequiredService <IEnvironment>(), sourceRepo, logger); if (!string.IsNullOrWhiteSpace(commitId)) { buildInfo.AddDefinition("Repository Commit", commitId); } console.WriteLine(buildInfo.ToString()); var environmentSettingsProvider = serviceProvider.GetRequiredService <IEnvironmentSettingsProvider>(); if (!environmentSettingsProvider.TryGetAndLoadSettings(out var environmentSettings)) { return(ProcessConstants.ExitFailure); } // Generate build script string scriptContent; using (var stopwatch = logger.LogTimedEvent("GenerateBuildScript")) { var checkerMessages = new List <ICheckerMessage>(); var scriptGenerator = new BuildScriptGenerator( serviceProvider, console, checkerMessages, buildOperationId); var generated = scriptGenerator.TryGenerateScript(out scriptContent); stopwatch.AddProperty("generateSucceeded", generated.ToString()); if (checkerMessages.Count > 0) { var messageFormatter = new DefinitionListFormatter(); checkerMessages.ForEach(msg => messageFormatter.AddDefinition(msg.Level.ToString(), msg.Content)); console.WriteLine(messageFormatter.ToString()); } else { logger.LogDebug("No checker messages emitted"); } if (!generated) { return(ProcessConstants.ExitFailure); } } // Get the path where the generated script should be written into. var tempDirectoryProvider = serviceProvider.GetRequiredService <ITempDirectoryProvider>(); var buildScriptPath = Path.Combine(tempDirectoryProvider.GetTempDirectory(), "build.sh"); // Write build script to selected path File.WriteAllText(buildScriptPath, scriptContent); logger.LogTrace("Build script written to file"); var buildEventProps = new Dictionary <string, string>() { { "oryxVersion", Program.GetVersion() }, { "oryxCommitId", Program.GetCommit() }, { "oryxCommandLine", string.Join( ' ', serviceProvider.GetRequiredService <IEnvironment>().GetCommandLineArgs()) }, { nameof(commitId), commitId }, { "scriptPath", buildScriptPath }, { "envVars", string.Join(",", GetEnvVarNames(serviceProvider.GetRequiredService <IEnvironment>())) }, }; var buildScriptOutput = new StringBuilder(); var stdOutEventLogger = new TextSpanEventLogger(logger, _measurableStdOutSpans); DataReceivedEventHandler stdOutBaseHandler = (sender, args) => { string line = args.Data; if (line == null) { return; } console.WriteLine(line); buildScriptOutput.AppendLine(line); stdOutEventLogger.CheckString(line); }; DataReceivedEventHandler stdErrBaseHandler = (sender, args) => { string line = args.Data; if (line == null) { return; } console.Error.WriteLine(args.Data); buildScriptOutput.AppendLine(args.Data); }; // Try make the pre-build & post-build scripts executable ProcessHelper.TrySetExecutableMode(environmentSettings.PreBuildScriptPath); ProcessHelper.TrySetExecutableMode(environmentSettings.PostBuildScriptPath); // Run the generated script int exitCode; using (var timedEvent = logger.LogTimedEvent("RunBuildScript", buildEventProps)) { exitCode = serviceProvider.GetRequiredService <IScriptExecutor>().ExecuteScript( buildScriptPath, new[] { sourceRepo.RootPath, options.DestinationDir ?? string.Empty, options.IntermediateDir ?? string.Empty }, workingDirectory: sourceRepo.RootPath, stdOutHandler == null ? stdOutBaseHandler : stdOutBaseHandler + stdOutHandler, stdErrHandler == null ? stdErrBaseHandler : stdErrBaseHandler + stdErrHandler); timedEvent.AddProperty("exitCode", exitCode.ToString()); } logger.LogDebug("Build script content:\n" + scriptContent); logger.LogLongMessage(LogLevel.Debug, "Build script output", buildScriptOutput.ToString()); if (exitCode != ProcessConstants.ExitSuccess) { logger.LogError("Build script exited with {exitCode}", exitCode); return(exitCode); } return(ProcessConstants.ExitSuccess); }
internal override int Execute(IServiceProvider serviceProvider, IConsole console) { var logger = serviceProvider.GetRequiredService <ILogger <ExecCommand> >(); var env = serviceProvider.GetRequiredService <IEnvironment>(); var generator = serviceProvider.GetRequiredService <IBuildScriptGenerator>(); var opts = serviceProvider.GetRequiredService <IOptions <BuildScriptGeneratorOptions> >().Value; if (string.IsNullOrWhiteSpace(Command)) { logger.LogDebug("Command is empty; exiting"); return(ProcessConstants.ExitSuccess); } var shellPath = env.GetEnvironmentVariable("BASH") ?? FilePaths.Bash; var ctx = BuildScriptGenerator.CreateContext(serviceProvider, operationId: null); ctx.DisableMultiPlatformBuild = false; var tools = generator.GetRequiredToolVersions(ctx); int exitCode; using (var timedEvent = logger.LogTimedEvent("ExecCommand")) { // Build envelope script var scriptBuilder = new ShellScriptBuilder("\n") .AddShebang(shellPath) .AddCommand("set -e"); if (tools.Count > 0) { scriptBuilder.Source($"{FilePaths.Benv} {StringExtensions.JoinKeyValuePairs(tools)}"); } var script = scriptBuilder.AddCommand(Command).ToString(); // Create temporary file to store script var tempScriptPath = Path.GetTempFileName(); File.WriteAllText(tempScriptPath, script); timedEvent.AddProperty(nameof(tempScriptPath), tempScriptPath); if (DebugMode) { console.WriteLine($"Temporary script @ {tempScriptPath}:"); console.WriteLine("---"); console.WriteLine(script); console.WriteLine("---"); } exitCode = ProcessHelper.RunProcess( shellPath, new[] { tempScriptPath }, opts.SourceDir, (sender, args) => { if (args.Data != null) { console.WriteLine(args.Data); } }, (sender, args) => { if (args.Data != null) { console.Error.WriteLine(args.Data); } }, waitTimeForExit: null); timedEvent.AddProperty("exitCode", exitCode.ToString()); } return(exitCode); }