public void Execute(PublishCommandOptions options) { var absoluteFilePath = options.File.Path; // if a publish directory has been specified, then it is used directly, otherwise: // -- for EXE {current dir}/publish/{runtime ID} // -- for DLL {current dir}/publish var publishDirectory = options.OutputDirectory ?? (options.PublishType == PublishType.Library ? Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish") : Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish", options.RuntimeIdentifier)); var absolutePublishDirectory = publishDirectory.GetRootedPath(); var compiler = GetScriptCompiler(!options.NoCache, _logFactory); var scriptEmitter = new ScriptEmitter(_scriptConsole, compiler); var publisher = new ScriptPublisher(_logFactory, scriptEmitter); var code = absoluteFilePath.ToSourceText(); var context = new ScriptContext(code, absolutePublishDirectory, Enumerable.Empty <string>(), absoluteFilePath, options.OptimizationLevel, packageSources: options.PackageSources); if (options.PublishType == PublishType.Library) { publisher.CreateAssembly <int, CommandLineScriptGlobals>(context, _logFactory, options.LibraryName); } else { publisher.CreateExecutable <int, CommandLineScriptGlobals>(context, _logFactory, options.RuntimeIdentifier); } }
private static int Wain(string[] args) { var app = new CommandLineApplication(throwOnUnexpectedArg: false) { ExtendedHelpText = "Starting without a path to a CSX file or a command, starts the REPL (interactive) mode." }; var file = app.Argument("script", "Path to CSX script"); var interactive = app.Option("-i | --interactive", "Execute a script and drop into the interactive mode afterwards.", CommandOptionType.NoValue); var configuration = app.Option("-c | --configuration <configuration>", "Configuration to use for running the script [Release/Debug] Default is \"Debug\"", CommandOptionType.SingleValue); var packageSources = app.Option("-s | --sources <SOURCE>", "Specifies a NuGet package source to use when resolving NuGet packages.", CommandOptionType.MultipleValue); var debugMode = app.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); var verbosity = app.Option("--verbosity", " Set the verbosity level of the command. Allowed values are t[trace], d[ebug], i[nfo], w[arning], e[rror], and c[ritical].", CommandOptionType.SingleValue); var nocache = app.Option("--nocache", "Disable caching (Restore and Dll cache)", CommandOptionType.NoValue); var infoOption = app.Option("--info", "Displays environmental information", CommandOptionType.NoValue); var argsBeforeDoubleHyphen = args.TakeWhile(a => a != "--").ToArray(); var argsAfterDoubleHyphen = args.SkipWhile(a => a != "--").Skip(1).ToArray(); const string helpOptionTemplate = "-? | -h | --help"; app.HelpOption(helpOptionTemplate); app.VersionOption("-v | --version", () => new VersionProvider().GetCurrentVersion().Version); var logFactory = CreateLogFactory(verbosity.Value(), debugMode.HasValue()); app.Command("eval", c => { c.Description = "Execute CSX code."; var code = c.Argument("code", "Code to execute."); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory for the code compiler. Defaults to current directory.", CommandOptionType.SingleValue); c.HelpOption(helpOptionTemplate); c.OnExecute(async() => { int exitCode = 0; if (!string.IsNullOrWhiteSpace(code.Value)) { var optimizationLevel = configuration.ValueEquals("release", StringComparison.OrdinalIgnoreCase) ? OptimizationLevel.Release : OptimizationLevel.Debug; exitCode = await RunCode(code.Value, debugMode.HasValue(), !nocache.HasValue(), logFactory, optimizationLevel, app.RemainingArguments.Concat(argsAfterDoubleHyphen), cwd.Value(), packageSources.Values?.ToArray()); } return(exitCode); }); }); app.Command("init", c => { c.Description = "Creates a sample script along with the launch.json file needed to launch and debug the script."; var fileName = c.Argument("filename", "(Optional) The name of the sample script file to be created during initialization. Defaults to 'main.csx'"); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory for initialization. Defaults to current directory.", CommandOptionType.SingleValue); c.HelpOption(helpOptionTemplate); c.OnExecute(() => { var scaffolder = new Scaffolder(logFactory); scaffolder.InitializerFolder(fileName.Value, cwd.Value() ?? Directory.GetCurrentDirectory()); return(0); }); }); app.Command("new", c => { c.Description = "Creates a new script file"; var fileNameArgument = c.Argument("filename", "The script file name"); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory the new script file to be created. Defaults to current directory.", CommandOptionType.SingleValue); c.HelpOption(helpOptionTemplate); c.OnExecute(() => { var scaffolder = new Scaffolder(logFactory); if (fileNameArgument.Value == null) { c.ShowHelp(); return(0); } scaffolder.CreateNewScriptFile(fileNameArgument.Value, cwd.Value() ?? Directory.GetCurrentDirectory()); return(0); }); }); app.Command("publish", c => { c.Description = "Creates a self contained executable or DLL from a script"; var fileNameArgument = c.Argument("filename", "The script file name"); var publishDirectoryOption = c.Option("-o |--output", "Directory where the published executable should be placed. Defaults to a 'publish' folder in the current directory.", CommandOptionType.SingleValue); var dllName = c.Option("-n |--name", "The name for the generated DLL (executable not supported at this time). Defaults to the name of the script.", CommandOptionType.SingleValue); var dllOption = c.Option("--dll", "Publish to a .dll instead of an executable.", CommandOptionType.NoValue); var commandConfig = c.Option("-c | --configuration <configuration>", "Configuration to use for publishing the script [Release/Debug]. Default is \"Debug\"", CommandOptionType.SingleValue); var publishDebugMode = c.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); var runtime = c.Option("-r |--runtime", "The runtime used when publishing the self contained executable. Defaults to your current runtime.", CommandOptionType.SingleValue); c.HelpOption(helpOptionTemplate); c.OnExecute(() => { if (fileNameArgument.Value == null) { c.ShowHelp(); return(0); } var optimizationLevel = commandConfig.ValueEquals("release", StringComparison.OrdinalIgnoreCase) ? OptimizationLevel.Release : OptimizationLevel.Debug; var runtimeIdentifier = runtime.Value() ?? ScriptEnvironment.Default.RuntimeIdentifier; var absoluteFilePath = fileNameArgument.Value.GetRootedPath(); // if a publish directory has been specified, then it is used directly, otherwise: // -- for EXE {current dir}/publish/{runtime ID} // -- for DLL {current dir}/publish var publishDirectory = publishDirectoryOption.Value() ?? (dllOption.HasValue() ? Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish") : Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish", runtimeIdentifier)); var absolutePublishDirectory = publishDirectory.GetRootedPath(); var compiler = GetScriptCompiler(publishDebugMode.HasValue(), !nocache.HasValue(), logFactory); var scriptEmitter = new ScriptEmitter(ScriptConsole.Default, compiler); var publisher = new ScriptPublisher(logFactory, scriptEmitter); var code = absoluteFilePath.ToSourceText(); var context = new ScriptContext(code, absolutePublishDirectory, Enumerable.Empty <string>(), absoluteFilePath, optimizationLevel); if (dllOption.HasValue()) { publisher.CreateAssembly <int, CommandLineScriptGlobals>(context, logFactory, dllName.Value()); } else { publisher.CreateExecutable <int, CommandLineScriptGlobals>(context, logFactory, runtimeIdentifier); } return(0); }); }); app.Command("exec", c => { c.Description = "Run a script from a DLL."; var dllPath = c.Argument("dll", "Path to DLL based script"); var commandDebugMode = c.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); c.HelpOption(helpOptionTemplate); c.OnExecute(async() => { int exitCode = 0; if (!string.IsNullOrWhiteSpace(dllPath.Value)) { if (!File.Exists(dllPath.Value)) { throw new Exception($"Couldn't find file '{dllPath.Value}'"); } var absoluteFilePath = dllPath.Value.GetRootedPath(); var compiler = GetScriptCompiler(commandDebugMode.HasValue(), !nocache.HasValue(), logFactory); var runner = new ScriptRunner(compiler, logFactory, ScriptConsole.Default); var result = await runner.Execute <int>(absoluteFilePath, app.RemainingArguments.Concat(argsAfterDoubleHyphen)); return(result); } return(exitCode); }); }); app.OnExecute(async() => { int exitCode = 0; if (infoOption.HasValue()) { var environmentReporter = new EnvironmentReporter(logFactory); await environmentReporter.ReportInfo(); return(0); } if (!string.IsNullOrWhiteSpace(file.Value)) { var optimizationLevel = configuration.ValueEquals("release", StringComparison.OrdinalIgnoreCase) ? OptimizationLevel.Release : OptimizationLevel.Debug; if (Debugger.IsAttached || nocache.HasValue()) { exitCode = await RunScript(file.Value, debugMode.HasValue(), !nocache.HasValue(), logFactory, optimizationLevel, app.RemainingArguments.Concat(argsAfterDoubleHyphen), interactive.HasValue(), packageSources.Values?.ToArray()); } else { string cacheFolder = Path.Combine(Path.GetTempPath(), "dotnet-scripts"); // create unique folder name based on the path string uniqueFolderName = ""; using (var sha = SHA256.Create()) { uniqueFolderName = Convert.ToBase64String(sha.ComputeHash(Encoding.Unicode.GetBytes(file.Value))).Replace("=", String.Empty).Replace("/", string.Empty); } string publishDirectory = Path.Combine(cacheFolder, uniqueFolderName); if (!Directory.Exists(publishDirectory)) { Directory.CreateDirectory(publishDirectory); } string absoluteSourcePath; SourceText code; if (!File.Exists(file.Value)) { if (IsHttpUri(file.Value)) { var downloader = new ScriptDownloader(); var rawCode = await downloader.Download(file.Value); absoluteSourcePath = Path.Combine(publishDirectory, "source.csx"); File.WriteAllText(absoluteSourcePath, rawCode); code = SourceText.From(rawCode); } else { throw new Exception($"Couldn't find file '{file}'"); } } else { absoluteSourcePath = file.Value.GetRootedPath(); code = absoluteSourcePath.ToSourceText(); } // given the path to a script we create a %temp%\dotnet-scripts\{uniqueFolderName} path string pathToDll = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(absoluteSourcePath) + ".dll"); // source hash is the checkSum of the code string sourceHash = Convert.ToBase64String(code.GetChecksum().ToArray()); // get hash code from previous run string hashCache = Path.Combine(publishDirectory, ".hash"); var compiler = GetScriptCompiler(true, !nocache.HasValue(), logFactory); // if we don't have hash if (!File.Exists(hashCache) || // or we haven't created a dll !Directory.Exists(publishDirectory) || // the hashcode has changed (meaning new content) File.ReadAllText(hashCache) != sourceHash) { // then we autopublish into the %temp%\dotnet-scripts\{uniqueFolderName} path var runtimeIdentifier = ScriptEnvironment.Default.RuntimeIdentifier; var scriptEmitter = new ScriptEmitter(ScriptConsole.Default, compiler); var publisher = new ScriptPublisher(logFactory, scriptEmitter); var context = new ScriptContext(code, publishDirectory, Enumerable.Empty <string>(), absoluteSourcePath, optimizationLevel); // create the assembly in our cache folder publisher.CreateAssembly <int, CommandLineScriptGlobals>(context, logFactory, Path.GetFileNameWithoutExtension(pathToDll)); // save sourceHash for next time, so we can know it's ok to use the generated dll next time File.WriteAllText(hashCache, sourceHash); } // run the cached %temp%\dotnet-scripts\{uniqueFolderName}/package.dll var runner = new ScriptRunner(compiler, logFactory, ScriptConsole.Default); var result = await runner.Execute <int>(pathToDll, app.RemainingArguments.Concat(argsAfterDoubleHyphen)); return(result); } } else { await RunInteractive(debugMode.HasValue(), !nocache.HasValue(), logFactory, packageSources.Values?.ToArray()); } return(exitCode); }); return(app.Execute(argsBeforeDoubleHyphen)); }
private static int Wain(string[] args) { var app = new CommandLineApplication(throwOnUnexpectedArg: false) { ExtendedHelpText = "Starting without a path to a CSX file or a command, starts the REPL (interactive) mode." }; var file = app.Argument("script", "Path to CSX script"); var interactive = app.Option("-i | --interactive", "Execute a script and drop into the interactive mode afterwards.", CommandOptionType.NoValue); var configuration = app.Option("-c | --configuration <configuration>", "Configuration to use for running the script [Release/Debug] Default is \"Debug\"", CommandOptionType.SingleValue); var packageSources = app.Option("-s | --sources <SOURCE>", "Specifies a NuGet package source to use when resolving NuGet packages.", CommandOptionType.MultipleValue); var debugMode = app.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); var argsBeforeDoubleHyphen = args.TakeWhile(a => a != "--").ToArray(); var argsAfterDoubleHypen = args.SkipWhile(a => a != "--").Skip(1).ToArray(); app.HelpOption("-? | -h | --help"); app.VersionOption("-v | --version", GetVersion); var infoOption = app.Option("--info", "Displays environmental information", CommandOptionType.NoValue); app.Command("eval", c => { c.Description = "Execute CSX code."; var code = c.Argument("code", "Code to execute."); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory for the code compiler. Defaults to current directory.", CommandOptionType.SingleValue); c.OnExecute(async() => { int exitCode = 0; if (!string.IsNullOrWhiteSpace(code.Value)) { var optimizationLevel = OptimizationLevel.Debug; if (configuration.HasValue() && configuration.Value().ToLower() == "release") { optimizationLevel = OptimizationLevel.Release; } exitCode = await RunCode(code.Value, debugMode.HasValue(), optimizationLevel, app.RemainingArguments.Concat(argsAfterDoubleHypen), cwd.Value(), packageSources.Values?.ToArray()); } return(exitCode); }); }); app.Command("init", c => { c.Description = "Creates a sample script along with the launch.json file needed to launch and debug the script."; var fileName = c.Argument("filename", "(Optional) The name of the sample script file to be created during initialization. Defaults to 'main.csx'"); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory for initialization. Defaults to current directory.", CommandOptionType.SingleValue); c.OnExecute(() => { var scaffolder = new Scaffolder(new ScriptLogger(ScriptConsole.Default.Error, debugMode.HasValue())); scaffolder.InitializerFolder(fileName.Value, cwd.Value() ?? Directory.GetCurrentDirectory()); return(0); }); }); app.Command("new", c => { c.Description = "Creates a new script file"; var fileNameArgument = c.Argument("filename", "The script file name"); var cwd = c.Option("-cwd |--workingdirectory <currentworkingdirectory>", "Working directory the new script file to be created. Defaults to current directory.", CommandOptionType.SingleValue); c.OnExecute(() => { var scaffolder = new Scaffolder(new ScriptLogger(ScriptConsole.Default.Error, debugMode.HasValue())); if (fileNameArgument.Value == null) { c.ShowHelp(); return(0); } scaffolder.CreateNewScriptFile(fileNameArgument.Value, cwd.Value() ?? Directory.GetCurrentDirectory()); return(0); }); }); app.Command("publish", c => { c.Description = "Creates a self contained executable or DLL from a script"; var fileNameArgument = c.Argument("filename", "The script file name"); var publishDirectoryOption = c.Option("-o |--output", "Directory where the published executable should be placed. Defaults to a 'publish' folder in the current directory.", CommandOptionType.SingleValue); var dllName = c.Option("-n |--name", "The name for the generated DLL (executable not supported at this time). Defaults to the name of the script.", CommandOptionType.SingleValue); var dllOption = c.Option("--dll", "Publish to a .dll instead of an executable.", CommandOptionType.NoValue); var commandConfig = c.Option("-c | --configuration <configuration>", "Configuration to use for publishing the script [Release/Debug]. Default is \"Debug\"", CommandOptionType.SingleValue); var publishDebugMode = c.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); var runtime = c.Option("-r |--runtime", "The runtime used when publishing the self contained executable. Defaults to your current runtime.", CommandOptionType.SingleValue); c.OnExecute(() => { if (fileNameArgument.Value == null) { c.ShowHelp(); return(0); } var optimizationLevel = OptimizationLevel.Debug; if (commandConfig.HasValue() && commandConfig.Value().ToLower() == "release") { optimizationLevel = OptimizationLevel.Release; } var runtimeIdentifier = runtime.Value() ?? ScriptEnvironment.Default.RuntimeIdentifier; var absoluteFilePath = Path.IsPathRooted(fileNameArgument.Value) ? fileNameArgument.Value : Path.Combine(Directory.GetCurrentDirectory(), fileNameArgument.Value); // if a publish directory has been specified, then it is used directly, otherwise: // -- for EXE {current dir}/publish/{runtime ID} // -- for DLL {current dir}/publish var publishDirectory = publishDirectoryOption.Value() ?? (dllOption.HasValue() ? Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish") : Path.Combine(Path.GetDirectoryName(absoluteFilePath), "publish", runtimeIdentifier)); var absolutePublishDirectory = Path.IsPathRooted(publishDirectory) ? publishDirectory : Path.Combine(Directory.GetCurrentDirectory(), publishDirectory); var logFactory = GetLogFactory(); var compiler = GetScriptCompiler(publishDebugMode.HasValue()); var scriptEmmiter = new ScriptEmitter(ScriptConsole.Default, compiler); var publisher = new ScriptPublisher(logFactory, scriptEmmiter); var code = SourceText.From(File.ReadAllText(absoluteFilePath)); var context = new ScriptContext(code, absolutePublishDirectory, Enumerable.Empty <string>(), absoluteFilePath, optimizationLevel); if (dllOption.HasValue()) { publisher.CreateAssembly <int, CommandLineScriptGlobals>(context, logFactory, dllName.Value()); } else { publisher.CreateExecutable <int, CommandLineScriptGlobals>(context, logFactory, runtimeIdentifier); } return(0); LogFactory GetLogFactory() { var logger = new ScriptLogger(ScriptConsole.Default.Error, publishDebugMode.HasValue()); return(type => ((level, message) => { if (level == LogLevel.Debug) { logger.Verbose(message); } if (level == LogLevel.Info) { logger.Log(message); } })); } }); }); app.Command("exec", c => { c.Description = "Run a script from a DLL."; var dllPath = c.Argument("dll", "Path to DLL based script"); var commandDebugMode = c.Option(DebugFlagShort + " | " + DebugFlagLong, "Enables debug output.", CommandOptionType.NoValue); c.OnExecute(async() => { int exitCode = 0; if (!string.IsNullOrWhiteSpace(dllPath.Value)) { if (!File.Exists(dllPath.Value)) { throw new Exception($"Couldn't find file '{dllPath.Value}'"); } var absoluteFilePath = Path.IsPathRooted(dllPath.Value) ? dllPath.Value : Path.Combine(Directory.GetCurrentDirectory(), dllPath.Value); var compiler = GetScriptCompiler(commandDebugMode.HasValue()); var runner = new ScriptRunner(compiler, compiler.Logger, ScriptConsole.Default); var result = await runner.Execute <int>(absoluteFilePath); return(result); } return(exitCode); }); }); app.OnExecute(async() => { int exitCode = 0; if (infoOption.HasValue()) { Console.Write(GetEnvironmentInfo()); return(0); } if (!string.IsNullOrWhiteSpace(file.Value)) { var optimizationLevel = OptimizationLevel.Debug; if (configuration.HasValue() && configuration.Value().ToLower() == "release") { optimizationLevel = OptimizationLevel.Release; } exitCode = await RunScript(file.Value, debugMode.HasValue(), optimizationLevel, app.RemainingArguments.Concat(argsAfterDoubleHypen), interactive.HasValue(), packageSources.Values?.ToArray()); } else { await RunInteractive(debugMode.HasValue(), packageSources.Values?.ToArray()); } return(exitCode); }); return(app.Execute(argsBeforeDoubleHyphen)); }