Beispiel #1
0
 static void DoRepl()
 {
     using var scope = new SynchronizationContextScope();
     scope.Install(null);
     Application.Init();
     Application.Top.Add(new ReplApp());
     Application.Run();
 }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
            }