// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Design.Internal; using Microsoft.DotNet.InternalAbstractions; using Microsoft.DotNet.ProjectModel; using Microsoft.Extensions.CommandLineUtils; using Microsoft.Extensions.Internal; using NuGet.Frameworks; namespace Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Internal { public class PrecompileDispatchCommand { private CommandLineApplication Application { get; set; } private CommonOptions Options { get; } = new CommonOptions(); private CommandOption FrameworkOption { get; set; } private CommandOption ConfigurationOption { get; set; } private CommandOption OutputPathOption { get; set; } private CommandOption BuildBasePathOption { get; set; } private NuGetFramework TargetFramework { get; set; } private CommandOption DumpFilesOption { get; set; } private string ProjectPath { get; set; } private string Configuration { get; set; } private string OutputPath { get; set; } public void Configure(CommandLineApplication app) { Application = app; Options.Configure(app); FrameworkOption = app.Option( "-f|--framework", "Target Framework", CommandOptionType.SingleValue); ConfigurationOption = app.Option( "-c|--configuration", "Configuration", CommandOptionType.SingleValue); OutputPathOption = app.Option( "-o|--output-path", "Output path.", CommandOptionType.SingleValue); app.OnExecute(() => Execute()); } private int Execute() { if (!ParseArguments()) { return 1; } var runtimeContext = GetRuntimeContext(); var outputPaths = runtimeContext.GetOutputPaths(Configuration); var applicationName = Path.GetFileNameWithoutExtension(outputPaths.CompilationFiles.Assembly); var dispatchArgs = new List { ProjectPath, PrecompileRunCommand.ApplicationNameTemplate, applicationName, PrecompileRunCommand.OutputPathTemplate, OutputPath, CommonOptions.ContentRootTemplate, Options.ContentRootOption.Value() ?? Directory.GetCurrentDirectory(), }; if (Options.ConfigureCompilationType.HasValue()) { dispatchArgs.Add(CommonOptions.ConfigureCompilationTypeTemplate); dispatchArgs.Add(Options.ConfigureCompilationType.Value()); } if (Options.EmbedViewSourcesOption.HasValue()) { dispatchArgs.Add(CommonOptions.EmbedViewSourceTemplate); } var compilerOptions = runtimeContext.ProjectFile.GetCompilerOptions(runtimeContext.TargetFramework, Configuration); if (!string.IsNullOrEmpty(compilerOptions.KeyFile)) { dispatchArgs.Add(StrongNameOptions.StrongNameKeyPath); var keyFilePath = Path.GetFullPath(Path.Combine(runtimeContext.ProjectDirectory, compilerOptions.KeyFile)); dispatchArgs.Add(keyFilePath); if (compilerOptions.DelaySign ?? false) { dispatchArgs.Add(StrongNameOptions.DelaySignTemplate); } if (compilerOptions.PublicSign ?? false) { dispatchArgs.Add(StrongNameOptions.PublicSignTemplate); } } #if DEBUG var commandLineArgs = Environment.GetCommandLineArgs(); if (commandLineArgs.Length > 1 && commandLineArgs[1] == "--debug") { dispatchArgs.Insert(0, commandLineArgs[1]); } #endif var toolName = typeof(Design.Program).GetTypeInfo().Assembly.GetName().Name; var dispatchCommand = DotnetToolDispatcher.CreateDispatchCommand( dispatchArgs, runtimeContext.TargetFramework, Configuration, outputPath: outputPaths.RuntimeOutputPath, buildBasePath: null, projectDirectory: ProjectPath, toolName: toolName); var commandExitCode = dispatchCommand .ForwardStdErr(Application.Error) .ForwardStdOut(Application.Out) .Execute() .ExitCode; return commandExitCode; } private bool ParseArguments() { ProjectPath = GetProjectPath(Options.ProjectArgument.Value); Configuration = ConfigurationOption.Value() ?? DotNet.Cli.Utils.Constants.DefaultConfiguration; if (FrameworkOption.HasValue()) { TargetFramework = NuGetFramework.Parse(FrameworkOption.Value()); } if (!OutputPathOption.HasValue()) { Application.Error.WriteLine($"Option {OutputPathOption.Template} does not have a value."); return false; } OutputPath = OutputPathOption.Value(); return true; } public static string GetProjectPath(string projectArgument) { string projectPath; if (!string.IsNullOrEmpty(projectArgument)) { projectPath = Path.GetFullPath(projectArgument); if (string.Equals(Path.GetFileName(projectPath), "project.json", StringComparison.OrdinalIgnoreCase)) { projectPath = Path.GetDirectoryName(projectPath); } if (!Directory.Exists(projectPath)) { throw new InvalidOperationException($"Could not find directory {projectPath}."); } } else { projectPath = Directory.GetCurrentDirectory(); } return projectPath; } private ProjectContext GetRuntimeContext() { var workspace = new BuildWorkspace(ProjectReaderSettings.ReadFromEnvironment()); var projectContexts = ProjectContext.CreateContextForEachFramework(ProjectPath).ToArray(); ProjectContext projectContext; if (TargetFramework != null) { projectContext = projectContexts.FirstOrDefault(context => context.TargetFramework == TargetFramework); if (projectContext == null) { throw new InvalidOperationException($"Project '{ProjectPath}' does not support framework: {FrameworkOption.Value()}"); } } else if (projectContexts.Length == 1) { projectContext = projectContexts[0]; } else { throw new InvalidOperationException($"Project '{ProjectPath}' targets multiple frameworks. Specify one using '{FrameworkOption.Template}."); } return workspace.GetRuntimeContext( projectContext, RuntimeEnvironmentRidExtensions.GetAllCandidateRuntimeIdentifiers()); } } }