예제 #1
0
        private static Process StartProcess(ShellProcessArgs args)
        {
            var startInfo = new ProcessStartInfo()
            {
                FileName               = args.Executable,
                Arguments              = string.Join(" ", args.Arguments),
                WorkingDirectory       = args.WorkingDirectory?.FullName ?? new DirectoryInfo(".").FullName,
                RedirectStandardInput  = true,
                RedirectStandardOutput = true,
                StandardOutputEncoding = Encoding.UTF8,
                RedirectStandardError  = true,
                StandardErrorEncoding  = Encoding.UTF8,
                CreateNoWindow         = true,
                UseShellExecute        = false
            };

            if (args.EnvironmentVariables != null)
            {
                foreach (var pair in args.EnvironmentVariables)
                {
                    startInfo.EnvironmentVariables[pair.Key] = pair.Value;
                }
            }

            var process = new Process {
                StartInfo = startInfo
            };

            if (args.OutputDataReceived != null)
            {
                process.OutputDataReceived += args.OutputDataReceived;
            }

            if (args.ErrorDataReceived != null)
            {
                process.ErrorDataReceived += args.ErrorDataReceived;
            }

            process.Start();

            if (args.OutputDataReceived != null)
            {
                process.BeginOutputReadLine();
            }

            if (args.ErrorDataReceived != null)
            {
                process.BeginErrorReadLine();
            }

            return(process);
        }
예제 #2
0
        public static ShellProcessOutput Run(ShellProcessArgs shellArgs)
        {
            Assert.IsNotNull(shellArgs);
            Assert.IsFalse(string.IsNullOrEmpty(shellArgs.Executable));

            var command = string.Join(" ", shellArgs.Executable.AsArray().Concat(shellArgs.Arguments));

            try
            {
                var runOutput   = new ShellProcessOutput();
                var hasErrors   = false;
                var output      = new StringBuilder();
                var logOutput   = new StringBuilder();
                var errorOutput = new StringBuilder();

                // Setup shell command
                if (shellArgs.ExtraPaths != null)
                {
                    var extraPaths = string.Join(k_PathSeparator.ToString(), shellArgs.ExtraPaths.Select(p => p.DoubleQuoted()));
#if UNITY_EDITOR_WIN
                    command = $"SET PATH={extraPaths}{k_PathSeparator}%PATH%{Environment.NewLine}{command}";
#else
                    command = $"export PATH={extraPaths}{k_PathSeparator}$PATH{Environment.NewLine}{command}";
#endif
                }

                LogProcessData($"TINY SHELL> {shellArgs.WorkingDirectory?.FullName ?? Application.RootDirectory.FullName}", logOutput);
                LogProcessData(command, logOutput);

                // Setup temporary command file
                var tmpCommandFile = Path.GetTempPath() + Guid.NewGuid().ToString();
#if UNITY_EDITOR_WIN
                tmpCommandFile += ".bat";
#else
                tmpCommandFile += ".sh";
#endif
                File.WriteAllText(tmpCommandFile, command);

                // Prepare data received handlers
                DataReceivedEventHandler outputReceived = (sender, e) =>
                {
                    LogProcessData(e.Data, output);
                    logOutput.AppendLine(e.Data);
                };
                DataReceivedEventHandler errorReceived = (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        errorOutput.AppendLine(e.Data);
                        hasErrors = true;
                    }
                    LogProcessData(e.Data, output);
                    logOutput.AppendLine(e.Data);
                };

                // Run command in shell and wait for exit
                try
                {
                    using (var process = StartProcess(new ShellProcessArgs()
                    {
#if UNITY_EDITOR_WIN
                        Executable = "cmd.exe",
                        Arguments = new string[] { "/Q", "/C", tmpCommandFile.DoubleQuoted() },
#else
                        Executable = "bash",
                        Arguments = tmpCommandFile.DoubleQuoted().AsArray(),
#endif
                        WorkingDirectory = shellArgs.WorkingDirectory,
                        OutputDataReceived = outputReceived,
                        ErrorDataReceived = errorReceived
                    }))
                    {
                        var processUpdate = WaitForProcess(process, shellArgs.MaxIdleTimeInMilliseconds);
                        while (processUpdate.MoveNext())
                        {
                        }
                        var exitCode = runOutput.ExitCode = processUpdate.Current == ProcessStatus.Killed ? -1 : process.ExitCode;
                        runOutput.Command       = command;
                        runOutput.CommandOutput = output;
                        runOutput.FullOutput    = logOutput.ToString();
                        runOutput.ErrorOutput   = errorOutput.ToString();
                        LogProcessData($"Process exited with code '{exitCode}'", logOutput);
                        hasErrors |= (exitCode != 0);
                    }
                }
                finally
                {
                    File.Delete(tmpCommandFile);
                }

                if (hasErrors && shellArgs.ThrowOnError)
                {
                    throw new Exception(errorOutput.ToString());
                }

                runOutput.Succeeded = !hasErrors;
                return(runOutput);
            }
            catch (Exception)
            {
                //TinyEditorAnalytics.SendException(nameof(Shell.Run), e);
                throw;
            }
        }
예제 #3
0
 public static Process RunAsync(ShellProcessArgs args)
 {
     return(StartProcess(args));
 }
예제 #4
0
        public static IEnumerator <ProgressInfo> Run(string arguments, StringBuilder command, StringBuilder output, DirectoryInfo workingDirectory = null)
        {
            var beeExe     = Path.GetFullPath("Packages/com.unity.tiny/DotsPlayer/bee~/bee.exe");
            var executable = beeExe;

            arguments = "--no-colors " + arguments;

#if !UNITY_EDITOR_WIN
            arguments  = executable.DoubleQuoted() + " " + arguments;
            executable = Application.MonoDirectory.GetFile("mono").FullName;
#endif

            command.Append(executable);
            command.Append(" ");
            command.Append(arguments);

            var progressInfo = new ProgressInfo()
            {
                Progress = 0.0f,
                Info     = null
            };

            void ProgressHandler(object sender, DataReceivedEventArgs args)
            {
                if (args.Data != null)
                {
                    lock (output)
                    {
                        output.AppendLine(args.Data);
                    }
                }

                var msg = args.Data;

                if (string.IsNullOrWhiteSpace(msg))
                {
                    return;
                }

                progressInfo.FullInfo = msg;

                var match = BeeProgressRegex.Match(msg);

                if (match.Success)
                {
                    var num = match.Groups[1].Value;
                    var den = match.Groups[2].Value;
                    if (int.TryParse(num, out var numInt) && int.TryParse(den, out var denInt))
                    {
                        progressInfo.Progress = (float)numInt / denInt;
                    }
                    progressInfo.Info = match.Groups[3].Value;
                }
                else
                {
                    progressInfo.Progress = float.MinValue;
                    progressInfo.Info     = null;
                }
            }

            var config = new ShellProcessArgs()
            {
                Executable       = executable,
                Arguments        = arguments.AsEnumerable(),
                WorkingDirectory = workingDirectory,
#if !UNITY_EDITOR_WIN
                // bee requires external programs to perform build actions
                EnvironmentVariables = new Dictionary <string, string>()
                {
                    { "PATH", string.Join(":",
                                          Application.MonoDirectory.FullName,
                                          "/bin",
                                          "/usr/bin",
                                          "/usr/local/bin") }
                },
#else
                EnvironmentVariables = null,
#endif
                OutputDataReceived = ProgressHandler,
                ErrorDataReceived  = ProgressHandler
            };

            var bee = Shell.RunAsync(config);

            yield return(progressInfo);

            const int maxBuildTimeInMs = 30 * 60 * 1000; // 30 minutes

            var statusEnum = Shell.WaitForProcess(bee, maxBuildTimeInMs);
            while (statusEnum.MoveNext())
            {
                yield return(progressInfo);
            }

            progressInfo.Progress = 1.0f;
            progressInfo.IsDone   = true;
            progressInfo.ExitCode = bee.ExitCode;
            progressInfo.Info     = "Build completed";
            yield return(progressInfo);
        }