// 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); }
// 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); }