static void DoRepl() { using var scope = new SynchronizationContextScope(); scope.Install(null); Application.Init(); Application.Top.Add(new ReplApp()); Application.Run(); }
static async Task <ErrorCodes> MainAsync(string[] args) { using var syncCtxScope = new SynchronizationContextScope(); await syncCtxScope.InstallAndYield(new CurrentThreadSynchronizationContext()); Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA); using var thisProcess = Process.GetCurrentProcess(); var dir = Path.Combine(Path.GetDirectoryName(thisProcess.MainModule.FileName), "running"); Directory.CreateDirectory(dir); using var file = new FileStream(Path.Combine(dir, thisProcess.Id.ToString()), FileMode.Create, FileAccess.Write, FileShare.Read, 512, FileOptions.DeleteOnClose | FileOptions.Asynchronous); using (var writer = new StreamWriter(file, null, -1, true)) await writer.WriteAsync(Environment.CommandLine); Console.WriteLine($"{nameof(CSharpScriptRunner)}, {BuildInfo.ReleaseTag}"); if (args == null || args.Length == 0) { PrintHelp(); return(ErrorCodes.OK); } try { switch (args[0].ToLowerInvariant()) { default: return(await RunScript(args)); case Verbs.Version: break; case Verbs.Install: await Install(args.Length > 1?string.Equals(args[1], "inplace", StringComparison.OrdinalIgnoreCase) : false); break; case Verbs.Update: await Update(); break; case Verbs.New: CreateNew(args.Length > 1 ? args[1] : null); break; case Verbs.ClearCache: await ClearCache(); break; case Verbs.InitVSCode: InitVSCode(); break; case Verbs.ListRunning: await ListRunning(); break; case Verbs.Repl: DoRepl(); break; } } catch (Exception ex) { if (ex is AggregateException aggregateException) { ex = aggregateException.InnerException; } WriteLineError(ex.ToString(), ConsoleColor.Red); return(ErrorCodes.GenericError); } return(ErrorCodes.OK); }
static async Task <ErrorCodes> RunScript(string[] arguments) { const string NuGetReferenceRegex = @"^\s*#r\s+""\s*nuget:\s*(?<name>[\w\d.-]+)\s*[\/,]\s*(?<version>[\w\d.-]+)\s*""\s*$"; IEnumerable <string> args = arguments; var runtimeExt = string.Empty; while (args.FirstOrDefault()?.StartsWith('-') ?? false) { var arg = args.First(); args = args.Skip(1); if (arg.StartsWith("-r", StringComparison.OrdinalIgnoreCase)) { runtimeExt = arg.Substring(2); } else { WriteLineError($"Argument {arg} is not recognized.", ConsoleColor.Red); return(ErrorCodes.UnrecognizedArgument); } } var filePath = args.FirstOrDefault(); if (!File.Exists(filePath)) { WriteLineError($"Script file '{filePath}' does not exist.", ConsoleColor.Red); return(ErrorCodes.ScriptFileDoesNotExist); } var scriptPath = Path.GetFullPath(filePath); if (string.IsNullOrEmpty(runtimeExt)) { runtimeExt = Path.GetExtension(Path.GetFileNameWithoutExtension(scriptPath)).TrimStart('.'); } if (!string.IsNullOrEmpty(runtimeExt)) { var exePath = Process.GetCurrentProcess().MainModule.FileName; var filename = Path.GetFileName(exePath); var dir = Path.GetDirectoryName(Path.GetDirectoryName(exePath)); var runtimeDir = Path.GetFileName(dir); dir = Path.GetDirectoryName(dir); if (runtimeExt != runtimeDir) { exePath = Path.Combine(dir, runtimeExt, "bin", filename); if (File.Exists(exePath)) { using var process = Process.Start(new ProcessStartInfo(exePath, string.Join(" ", args.Select(x => $"\"{x.Replace("\"", "\\\"")}\""))) { UseShellExecute = false }); await process.WaitForExitAsync(); return((ErrorCodes)process.ExitCode); } WriteLine($"Warning: Runtime '{runtimeExt}' was not found. Proceeding anyway...", ConsoleColor.Yellow); } } var(buildReferences, assemblyLoader) = await LoadPackages(scriptPath); var cacheFileBase = GetCacheFilenameBase(scriptPath); var assemblyFile = cacheFileBase + ".dll"; var hashFile = cacheFileBase + ".hash"; var configFile = cacheFileBase + ".json"; var scriptHash = GetFileHash(scriptPath); if (!TryGetCache(assemblyFile, hashFile, configFile, scriptHash, out var config)) { // Check for new release only when compiling Process.Start(new ProcessStartInfo { FileName = Process.GetCurrentProcess().MainModule.FileName, Arguments = Verbs.Update, CreateNoWindow = true, UseShellExecute = false }); if (!TryBuild(scriptPath, assemblyFile, hashFile, configFile, scriptHash, buildReferences, out config)) { return(ErrorCodes.ScriptCompilationFailed); } } var assembly = Assembly.Load(File.ReadAllBytes(assemblyFile)); var type = assembly.GetType(config.Type); if (type == null) { throw new Exception($"Entry type '{config.Type}' not found"); } var entryPoint = type.GetMethod(config.Method, BindingFlags.Static | BindingFlags.Public); if (entryPoint == null) { throw new Exception($"Entry point '{config.Type}.{config.Method}' not found"); } // Clear SynchronizationContext to mimic standard console app behavior in script using (var nullSyncCtxScope = new SynchronizationContextScope()) { nullSyncCtxScope.Install(null); Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA); var task = (Task <object>)entryPoint.Invoke(null, new object[] { new object[] { new ScriptGlobals(args.Skip(1).ToArray()), assemblyLoader } }); var errorCode = (ErrorCodes?)((await task)as int?) ?? ErrorCodes.OK; if (errorCode > ErrorCodes.OK && errorCode <= ErrorCodes.Reserved) { return(ErrorCodes.ScriptReturnRangeConflict); } return(errorCode); }