public async Task <ResultStatus> TryExecuteRemote(Command command, BuilderContext builderContext, IExecuteContext executeContext, LocalCommandContext commandContext) { while (!CanSpawnParallelProcess()) { await Task.Delay(1, command.CancellationToken); } var address = "Stride/CompilerApp/PackageBuilderApp/" + Guid.NewGuid(); var arguments = $"--slave=\"{address}\" --build-path=\"{builderOptions.BuildDirectory}\""; using (var debugger = VisualStudioDebugger.GetAttached()) { if (debugger != null) { arguments += $" --reattach-debugger={debugger.ProcessId}"; } } // Start ServiceWire pipe for communication with process var processBuilderRemote = new ProcessBuilderRemote(assemblyContainer, commandContext, command); var host = new NpHost(address, null, null, new StrideServiceWireSerializer()); host.AddService <IProcessBuilderRemote>(processBuilderRemote); var startInfo = new ProcessStartInfo { // Note: try to get exec server if it exists, otherwise use CompilerApp.exe FileName = LoaderToolLocator.GetExecutable(typeof(PackageBuilder).Assembly.Location), Arguments = arguments, WorkingDirectory = Environment.CurrentDirectory, CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; host.Open(); var output = new List <string>(); var process = new Process { StartInfo = startInfo }; process.Start(); process.OutputDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.ErrorDataReceived += (_, args) => LockProcessAndAddDataToList(process, output, args); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Note: we don't want the thread to schedule another job since the CPU core will be in use by the process, so we do a blocking WaitForExit. process.WaitForExit(); host.Close(); NotifyParallelProcessEnded(); if (process.ExitCode != 0) { executeContext.Logger.Error($"Remote command crashed with output:{Environment.NewLine}{string.Join(Environment.NewLine, output)}"); } if (processBuilderRemote.Result != null) { // Register results back locally foreach (var outputObject in processBuilderRemote.Result.OutputObjects) { commandContext.RegisterOutput(outputObject.Key, outputObject.Value); } // Register log messages foreach (var logMessage in processBuilderRemote.Result.LogMessages) { commandContext.Logger.Log(logMessage); } // Register tags foreach (var tag in processBuilderRemote.Result.TagSymbols) { commandContext.AddTag(tag.Key, tag.Value); } } return(command.CancellationToken.IsCancellationRequested ? ResultStatus.Cancelled : (process.ExitCode == 0 ? ResultStatus.Successful : ResultStatus.Failed)); }
public static bool EnsureRouterLaunched(bool attachChildJob = false, bool checkIfPortOpen = true) { try { // Try to connect to router FileVersionInfo runningRouterVersion = null; Process runningRouterProcess = null; foreach (var process in Process.GetProcessesByName("Stride.ConnectionRouter")) { try { runningRouterVersion = process.MainModule.FileVersionInfo; runningRouterProcess = process; break; } catch (Exception) { } } // Make sure to use .exe rather than .dll (.NET Core) var defaultRouterAssemblyLocation = LoaderToolLocator.GetExecutable(typeof(Router).Assembly.Location); if (defaultRouterAssemblyLocation == null) { throw new InvalidOperationException("Could not find Connection Router assembly location"); } // Setup with default locations var routerAssemblyLocation = defaultRouterAssemblyLocation; var routerAssemblyExe = Path.GetFileName(routerAssemblyLocation); // Try to locate using Stride.ConnectionRouter package var logger = new LoggerResult(); var package = PackageStore.Instance.FindLocalPackage("Stride.ConnectionRouter", new PackageVersionRange(new PackageVersion(StrideVersion.NuGetVersion))); if (package != null) { routerAssemblyLocation = package.GetFiles().FirstOrDefault(x => string.Compare(Path.GetFileName(x.Path), routerAssemblyExe, true) == 0)?.FullPath ?? routerAssemblyLocation; } // If already started, check if found version is same that we wanted to start if (runningRouterVersion != null) { var routerAssemblyFileVersionInfo = FileVersionInfo.GetVersionInfo(routerAssemblyLocation); // Check that current router is at least as good as the one of latest found Stride if (new PackageVersion(routerAssemblyFileVersionInfo.FileVersion) <= new PackageVersion(runningRouterVersion.FileVersion)) { return(true); } } // Kill previous router process (if any) if (runningRouterProcess != null) { runningRouterProcess.Kill(); runningRouterProcess.WaitForExit(); } // Start new router process var spawnedRouterProcess = Process.Start(routerAssemblyLocation); // If we are in "developer" mode, attach job so that it gets killed with editor if (attachChildJob && spawnedRouterProcess != null) { new AttachedChildProcessJob(spawnedRouterProcess); } if (checkIfPortOpen) { using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { // Try during 5 seconds (10 * 500 msec) for (int i = 0; i < 10; ++i) { try { socket.Connect("localhost", RouterClient.DefaultPort); } catch (SocketException) { // Try again in 500 msec Thread.Sleep(500); continue; } break; } } } return(spawnedRouterProcess != null); } catch { return(false); } }
/// <summary> /// Gets the current proxy. /// </summary> /// <returns>StrideCommandsProxy.</returns> public static IStrideCommands GetProxy() { lock (commandProxyLock) { // New instance? bool shouldReload = strideCommands == null || solutionChanged || ShouldReload(); if (!shouldReload) { // TODO: Assemblies changed? //shouldReload = ShouldReload(); } // If new instance or assemblies changed, reload if (shouldReload) { ClosePipeAndProcess(); var address = "Stride/VSPackageCommands/" + Guid.NewGuid(); var stridePackageInfo = FindStrideSdkDir(solution).Result; if (stridePackageInfo.LoadedVersion == null) { return(null); } var commandAssembly = stridePackageInfo.SdkPaths.First(x => Path.GetFileNameWithoutExtension(x) == "Stride.VisualStudio.Commands"); var commandExecutable = LoaderToolLocator.GetExecutable(commandAssembly); // .NET Core: .dll => .exe var startInfo = new ProcessStartInfo { // Note: try to get exec server if it exists, otherwise use CompilerApp.exe FileName = commandExecutable, Arguments = $"--pipe=\"{address}\"", WorkingDirectory = Environment.CurrentDirectory, UseShellExecute = false, }; var strideCommandsProcess = new Process { StartInfo = startInfo }; strideCommandsProcess.Start(); strideCommandsProcessJob = new AttachedChildProcessJob(strideCommandsProcess); for (int i = 0; i < 10; ++i) { try { strideCommands = new NpClient <IStrideCommands>(new NpEndPoint(address + "/IStrideCommands")); break; } catch { // Last try, forward exception if (i == 9) { throw; } // Wait until process is ready to accept connections Thread.Sleep(100); } } solutionChanged = false; } return(strideCommands?.Proxy); } }