public void DetachFromProcess_WhenProcessIsNull_Throws()
        {
            var debuggerSetup = new DebuggerSetup();
            var logger = MockRepository.GenerateStub<ILogger>();
            var debugger = new VisualStudioDebugger(debuggerSetup, logger, null);

            Assert.Throws<ArgumentNullException>(() => debugger.DetachFromProcess(null));
        }
Пример #2
0
        public void Start(string workingDirectory, Process debuggerProcess, LoggerResult logger)
        {
            var gameHostAssembly = typeof(GameDebuggerTarget).Assembly.Location;

            using (var debugger = debuggerProcess != null ? VisualStudioDebugger.GetByProcess(debuggerProcess.Id) : null)
            {
                var address   = "Stride/Debugger/" + Guid.NewGuid();
                var arguments = $"--host=\"{address}\"";

                // Child process should wait for a debugger to be attached
                if (debugger != null)
                {
                    arguments += " --wait-debugger-attach";
                }

                var startInfo = new ProcessStartInfo
                {
                    FileName               = gameHostAssembly,
                    Arguments              = arguments,
                    WorkingDirectory       = workingDirectory,
                    CreateNoWindow         = true,
                    UseShellExecute        = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                };

                // Start ServiceWire pipe
                var gameDebuggerHost = new GameDebuggerHost(logger);
                ServiceHost = new NpHost(address, null, null);
                ServiceHost.AddService <IGameDebuggerHost>(gameDebuggerHost);
                ServiceHost.Open();

                var process = new Process {
                    StartInfo = startInfo
                };
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                // Make sure proces will be killed if our process is finished unexpectedly
                attachedChildProcessJob = new AttachedChildProcessJob(process);

                // Attach debugger
                debugger?.AttachToProcess(process.Id);

                GameHost = gameDebuggerHost;
            }
        }
Пример #3
0
        public int Run(string currentDirectory, Dictionary <string, string> environmentVariables, string[] args, bool shadowCache, int?debuggerProcessId, string callbackAddress)
        {
            bool lockTaken = false;

            try
            {
                Monitor.TryEnter(runLock, ref lockTaken);
                if (!lockTaken)
                {
                    // Busy, exit right away
                    return(BusyReturnCode);
                }

                // Do your stuff...
                Console.WriteLine("Run Received {0}", string.Join(" ", args));

                upTime.Restart();

                if (debuggerProcessId.HasValue && !Debugger.IsAttached)
                {
                    using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId.Value))
                    {
                        debugger?.Attach();
                    }
                }
                using (var callbackChannel = new NpClient <IServerLogger>(new NpEndPoint(callbackAddress)))
                {
                    var result = shadowManager.Run(currentDirectory, environmentVariables, args, shadowCache, callbackChannel);
                    return(result);
                }
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(runLock);
                }
            }
        }
Пример #4
0
        public async Task <ResultStatus> TryExecuteRemote(Command command, BuilderContext builderContext, IExecuteContext executeContext, LocalCommandContext commandContext)
        {
            while (!CanSpawnParallelProcess())
            {
                await Task.Delay(1, command.CancellationToken);
            }

            var address   = "net.pipe://localhost/" + Guid.NewGuid();
            var arguments = $"--slave=\"{address}\" --build-path=\"{builderOptions.BuildDirectory}\"";

            using (var debugger = VisualStudioDebugger.GetAttached())
            {
                if (debugger != null)
                {
                    arguments += $" --reattach-debugger={debugger.ProcessId}";
                }
            }

            // Start WCF pipe for communication with process
            var processBuilderRemote = new ProcessBuilderRemote(assemblyContainer, commandContext, command);
            var host = new ServiceHost(processBuilderRemote);

            host.AddServiceEndpoint(typeof(IProcessBuilderRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                MaxReceivedMessageSize = int.MaxValue
            }, address);

            var startInfo = new ProcessStartInfo
            {
                // Note: try to get exec server if it exists, otherwise use CompilerApp.exe
                FileName               = (string)AppDomain.CurrentDomain.GetData("RealEntryAssemblyFile") ?? 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));
        }
Пример #5
0
        public int Run(string[] args)
        {
            // This is used by ExecServer to retrieve the logs directly without using the console redirect (which is not working well
            // in a multi-domain scenario)
            var redirectLogToAppDomainAction = AppDomain.CurrentDomain.GetData("AppDomainLogToAction") as Action <string, ConsoleColor>;

            clock = Stopwatch.StartNew();

            // TODO this is hardcoded. Check how to make this dynamic instead.
            RuntimeHelpers.RunModuleConstructor(typeof(IProceduralModel).Module.ModuleHandle);
            RuntimeHelpers.RunModuleConstructor(typeof(MaterialKeys).Module.ModuleHandle);
            RuntimeHelpers.RunModuleConstructor(typeof(SpriteFontAsset).Module.ModuleHandle);
            RuntimeHelpers.RunModuleConstructor(typeof(ModelAsset).Module.ModuleHandle);
            RuntimeHelpers.RunModuleConstructor(typeof(SpriteStudioAnimationAsset).Module.ModuleHandle);
            RuntimeHelpers.RunModuleConstructor(typeof(ParticleSystem).Module.ModuleHandle);
            //var project = new Package();
            //project.Save("test.sdpkg");

            //Thread.Sleep(10000);
            //var spriteFontAsset = StaticFontAsset.New();
            //Content.Save("test.sdfnt", spriteFontAsset);
            //project.Refresh();

            //args = new string[] { "test.sdpkg", "-o:app_data", "-b:tmp", "-t:1" };

            var exeName           = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
            var showHelp          = false;
            var packMode          = false;
            var buildEngineLogger = GlobalLogger.GetLogger("BuildEngine");
            var options           = new PackageBuilderOptions(new ForwardingLoggerResult(buildEngineLogger));

            var p = new OptionSet
            {
                "Copyright (c) Stride contributors (https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) All Rights Reserved",
                "Stride Build Tool - Version: "
                +
                String.Format(
                    "{0}.{1}.{2}",
                    typeof(Program).Assembly.GetName().Version.Major,
                    typeof(Program).Assembly.GetName().Version.Minor,
                    typeof(Program).Assembly.GetName().Version.Build) + string.Empty,
                string.Format("Usage: {0} inputPackageFile [options]* -b buildPath", exeName),
                string.Empty,
                "=== Options ===",
                string.Empty,
                { "h|help", "Show this message and exit", v => showHelp = v != null },
                { "v|verbose", "Show more verbose progress logs", v => options.Verbose = v != null },
                { "d|debug", "Show debug logs (imply verbose)", v => options.Debug = v != null },
                { "log", "Enable file logging", v => options.EnableFileLogging = v != null },
                { "disable-auto-compile", "Disable auto-compile of projects", v => options.DisableAutoCompileProjects = v != null },
                { "project-configuration=", "Project configuration", v => options.ProjectConfiguration = v },
                { "platform=", "Platform name", v => options.Platform = (PlatformType)Enum.Parse(typeof(PlatformType), v) },
                { "solution-file=", "Solution File Name", v => options.SolutionFile = v },
                { "package-id=", "Package Id from the solution file", v => options.PackageId = Guid.Parse(v) },
                { "package-file=", "Input Package File Name", v => options.PackageFile = v },
                { "o|output-path=", "Output path", v => options.OutputDirectory = v },
                { "b|build-path=", "Build path", v => options.BuildDirectory = v },
                { "log-file=", "Log build in a custom file.", v =>
                  {
                      options.EnableFileLogging = v != null;
                      options.CustomLogFileName = v;
                  } },
                { "log-pipe=", "Log pipe.", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          options.LogPipeNames.Add(v);
                      }
                  } },
                { "monitor-pipe=", "Monitor pipe.", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          options.MonitorPipeNames.Add(v);
                      }
                  } },
                { "slave=", "Slave pipe", v => options.SlavePipe = v }, // Benlitz: I don't think this should be documented
                { "server=", "This Compiler is launched as a server", v => { } },
                { "pack", "Special mode to copy assets and resources in a folder for NuGet packaging", v => packMode = true },
                { "t|threads=", "Number of threads to create. Default value is the number of hardware threads available.", v => options.ThreadCount = int.Parse(v) },
                { "test=", "Run a test session.", v => options.TestName = v },
                { "property:", "Properties. Format is name1=value1;name2=value2", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          foreach (var nameValue in v.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                          {
                              var equalIndex = nameValue.IndexOf('=');
                              if (equalIndex == -1)
                              {
                                  throw new OptionException("Expect name1=value1;name2=value2 format.", "property");
                              }

                              options.Properties.Add(nameValue.Substring(0, equalIndex), nameValue.Substring(equalIndex + 1));
                          }
                      }
                  } },
                { "compile-property:", "Compile properties. Format is name1=value1;name2=value2", v =>
                  {
                      if (!string.IsNullOrEmpty(v))
                      {
                          if (options.ExtraCompileProperties == null)
                          {
                              options.ExtraCompileProperties = new Dictionary <string, string>();
                          }

                          foreach (var nameValue in v.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                          {
                              var equalIndex = nameValue.IndexOf('=');
                              if (equalIndex == -1)
                              {
                                  throw new OptionException("Expect name1=value1;name2=value2 format.", "property");
                              }

                              options.ExtraCompileProperties.Add(nameValue.Substring(0, equalIndex), nameValue.Substring(equalIndex + 1));
                          }
                      }
                  } },
                {
                    "reattach-debugger=", "Reattach to a Visual Studio debugger", v =>
                    {
                        int debuggerProcessId;
                        if (!string.IsNullOrEmpty(v) && int.TryParse(v, out debuggerProcessId))
                        {
                            if (!Debugger.IsAttached)
                            {
                                using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId))
                                {
                                    debugger?.Attach();
                                }
                            }
                        }
                    }
                },
            };

            TextWriterLogListener fileLogListener = null;

            BuildResultCode exitCode;

            RemoteLogForwarder assetLogger = null;

            try
            {
                var unexpectedArgs = p.Parse(args);

                // Set remote logger
                assetLogger = new RemoteLogForwarder(options.Logger, options.LogPipeNames);
                GlobalLogger.GlobalMessageLogged += assetLogger;

                // Activate proper log level
                buildEngineLogger.ActivateLog(options.LoggerType);

                // Output logs to the console with colored messages
                if (options.SlavePipe == null && !options.LogPipeNames.Any())
                {
                    if (redirectLogToAppDomainAction != null)
                    {
                        globalLoggerOnGlobalMessageLogged = new LogListenerRedirectToAction(redirectLogToAppDomainAction);
                    }
                    else
                    {
                        globalLoggerOnGlobalMessageLogged = new ConsoleLogListener {
                            LogMode = ConsoleLogMode.Always
                        };
                    }
                    globalLoggerOnGlobalMessageLogged.TextFormatter = FormatLog;
                    GlobalLogger.GlobalMessageLogged += globalLoggerOnGlobalMessageLogged;
                }

                if (unexpectedArgs.Any())
                {
                    throw new OptionException("Unexpected arguments [{0}]".ToFormat(string.Join(", ", unexpectedArgs)), "args");
                }
                try
                {
                    options.ValidateOptions();
                }
                catch (ArgumentException ex)
                {
                    throw new OptionException(ex.Message, ex.ParamName);
                }

                if (showHelp)
                {
                    p.WriteOptionDescriptions(Console.Out);
                    return((int)BuildResultCode.Successful);
                }
                else if (packMode)
                {
                    PackageSessionPublicHelper.FindAndSetMSBuildVersion();

                    var csprojFile = options.PackageFile;
                    var intermediatePackagePath = options.BuildDirectory;
                    var generatedItems          = new List <(string SourcePath, string PackagePath)>();
                    var logger = new LoggerResult();
                    if (!PackAssetsHelper.Run(logger, csprojFile, intermediatePackagePath, generatedItems))
                    {
                        foreach (var message in logger.Messages)
                        {
                            Console.WriteLine(message);
                        }
                        return((int)BuildResultCode.BuildError);
                    }
                    foreach (var generatedItem in generatedItems)
                    {
                        Console.WriteLine($"{generatedItem.SourcePath}|{generatedItem.PackagePath}");
                    }
                    return((int)BuildResultCode.Successful);
                }

                // Also write logs from master process into a file
                if (options.SlavePipe == null)
                {
                    if (options.EnableFileLogging)
                    {
                        string logFileName = options.CustomLogFileName;
                        if (string.IsNullOrEmpty(logFileName))
                        {
                            string inputName = Path.GetFileNameWithoutExtension(options.PackageFile);
                            logFileName = "Logs/Build-" + inputName + "-" + DateTime.Now.ToString("yy-MM-dd-HH-mm") + ".txt";
                        }

                        string dirName = Path.GetDirectoryName(logFileName);
                        if (dirName != null)
                        {
                            Directory.CreateDirectory(dirName);
                        }

                        fileLogListener = new TextWriterLogListener(new FileStream(logFileName, FileMode.Create))
                        {
                            TextFormatter = FormatLog
                        };
                        GlobalLogger.GlobalMessageLogged += fileLogListener;
                    }

                    options.Logger.Info("BuildEngine arguments: " + string.Join(" ", args));
                    options.Logger.Info("Starting builder.");
                }
                else
                {
                    IsSlave = true;
                }

                if (!string.IsNullOrEmpty(options.TestName))
                {
                    var test = new TestSession();
                    test.RunTest(options.TestName, options.Logger);
                    exitCode = BuildResultCode.Successful;
                }
                else
                {
                    builder = new PackageBuilder(options);
                    if (!IsSlave && redirectLogToAppDomainAction == null)
                    {
                        Console.CancelKeyPress += OnConsoleOnCancelKeyPress;
                    }
                    exitCode = builder.Build();
                }
            }
            catch (OptionException e)
            {
                options.Logger.Error($"Command option '{e.OptionName}': {e.Message}");
                exitCode = BuildResultCode.CommandLineError;
            }
            catch (Exception e)
            {
                options.Logger.Error($"Unhandled exception", e);
                exitCode = BuildResultCode.BuildError;
            }
            finally
            {
                // Flush and close remote logger
                if (assetLogger != null)
                {
                    GlobalLogger.GlobalMessageLogged -= assetLogger;
                    assetLogger.Dispose();
                }

                if (fileLogListener != null)
                {
                    GlobalLogger.GlobalMessageLogged -= fileLogListener;
                    fileLogListener.LogWriter.Close();
                }

                // Output logs to the console with colored messages
                if (globalLoggerOnGlobalMessageLogged != null)
                {
                    GlobalLogger.GlobalMessageLogged -= globalLoggerOnGlobalMessageLogged;
                }
                if (builder != null && !IsSlave && redirectLogToAppDomainAction == null)
                {
                    Console.CancelKeyPress -= OnConsoleOnCancelKeyPress;
                }

                // Reset cache hold by YamlSerializer
                YamlSerializer.Default.ResetCache();
            }
            return((int)exitCode);
        }
Пример #6
0
        private async Task <ResultStatus> StartCommand(IExecuteContext executeContext, ListStore <CommandResultEntry> commandResultEntries, BuilderContext builderContext)
        {
            var logger = executeContext.Logger;

            //await Scheduler.Yield();

            ResultStatus status;

            using (commandResultEntries)
            {
                logger.Debug($"Starting command {Command}...");

                // Creating the CommandResult object
                var commandContext = new LocalCommandContext(executeContext, this, builderContext);

                // Actually processing the command
                if (Command.ShouldSpawnNewProcess() && builderContext.MaxParallelProcesses > 0 && builderContext.SlaveBuilderPath != null)
                {
                    while (!builderContext.CanSpawnParallelProcess())
                    {
                        await Task.Delay(1, Command.CancellationToken);
                    }

                    var address   = "net.pipe://localhost/" + Guid.NewGuid();
                    var arguments = string.Format("--slave=\"{0}\" --build-path=\"{1}\" --profile=\"{2}\"", address, builderContext.BuildPath, builderContext.BuildProfile);

                    using (var debugger = VisualStudioDebugger.GetAttached())
                    {
                        if (debugger != null)
                        {
                            arguments += $" --reattach-debugger={debugger.ProcessId}";
                        }
                    }

                    var startInfo = new ProcessStartInfo
                    {
                        FileName               = builderContext.SlaveBuilderPath,
                        Arguments              = arguments,
                        WorkingDirectory       = Environment.CurrentDirectory,
                        CreateNoWindow         = true,
                        UseShellExecute        = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError  = true,
                    };

                    // Start WCF pipe for communication with process
                    var processBuilderRemote = new ProcessBuilderRemote(commandContext, Command, builderContext.Parameters);
                    var host = new ServiceHost(processBuilderRemote);
                    host.AddServiceEndpoint(typeof(IProcessBuilderRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
                    {
                        MaxReceivedMessageSize = int.MaxValue
                    }, address);
                    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();

                    // Attach debugger to newly created process
                    // Add a reference to EnvDTE80 in the csproj and uncomment this (and also the Thread.Sleep in BuildEngineCmmands), then start the master process without debugger to attach to a slave.
                    //var dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.11.0");
                    //foreach (EnvDTE.Process dteProcess in dte.Debugger.LocalProcesses)
                    //{
                    //    if (dteProcess.ProcessID == process.Id)
                    //    {
                    //        dteProcess.Attach();
                    //        dte.Debugger.CurrentProcess = dteProcess;
                    //    }
                    //}

                    Task[] tasksToWait = null;

                    while (!process.HasExited)
                    {
                        Thread.Sleep(1);
                        lock (spawnedCommandsToWait)
                        {
                            if (spawnedCommandsToWait.Count > 0)
                            {
                                tasksToWait = spawnedCommandsToWait.ToArray();
                                spawnedCommandsToWait.Clear();
                            }
                        }

                        if (tasksToWait != null)
                        {
                            await Task.WhenAll(tasksToWait);

                            tasksToWait = null;
                        }
                    }
                    host.Close();

                    builderContext.NotifyParallelProcessEnded();

                    if (process.ExitCode != 0)
                    {
                        logger.Debug($"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)
                        {
                            TagSymbol tagSymbol;

                            // Resolve tag locally
                            if (!Command.TagSymbols.TryGetValue(tag.Value, out tagSymbol))
                            {
                                // Should we ignore silently? (with warning)
                                throw new InvalidOperationException("Could not find tag symbol.");
                            }

                            commandContext.AddTag(tag.Key, tagSymbol);
                        }
                    }

                    status = Command.CancellationToken.IsCancellationRequested ? ResultStatus.Cancelled : (process.ExitCode == 0 ? ResultStatus.Successful : ResultStatus.Failed);
                }
                else
                {
                    Command.PreCommand(commandContext);
                    if (!Command.BasePreCommandCalled)
                    {
                        throw new InvalidOperationException("base.PreCommand not called in command " + Command);
                    }

                    try
                    {
                        // Merge results from prerequisites
                        // TODO: This will prevent us from overwriting this asset with different content as it will result in a write conflict
                        // At some point we _might_ want to get rid of WaitBuildStep/ListBuildStep system and write a fully stateless input/output-based system; probably need further discussions
                        var fileProvider = ContentManager.FileProvider;
                        if (fileProvider != null)
                        {
                            var assetIndexMap = fileProvider.ContentIndexMap;
                            foreach (var prerequisiteStep in PrerequisiteSteps)
                            {
                                foreach (var output in prerequisiteStep.OutputObjectIds)
                                {
                                    assetIndexMap[output.Key.Path] = output.Value;
                                }
                            }
                        }

                        status = await Command.DoCommand(commandContext);
                    }
                    catch (Exception ex)
                    {
                        executeContext.Logger.Error("Exception in command " + this + ": " + ex);
                        status = ResultStatus.Failed;
                    }

                    Command.PostCommand(commandContext, status);
                    if (!Command.BasePostCommandCalled)
                    {
                        throw new InvalidOperationException("base.PostCommand not called in command " + Command);
                    }
                }

                // Ensure the command set at least the result status
                if (status == ResultStatus.NotProcessed)
                {
                    throw new InvalidDataException("The command " + Command + " returned ResultStatus.NotProcessed after completion.");
                }

                // Registering the result to the build cache
                RegisterCommandResult(commandResultEntries, commandContext.ResultEntry, status);
            }

            return(status);
        }
Пример #7
0
        private const int RetryWait     = 1000;          // in ms

        /// <summary>
        /// Runs the specified arguments copy.
        /// </summary>
        /// <param name="argsCopy">The arguments copy.</param>
        /// <returns>System.Int32.</returns>
        public int Run(string[] argsCopy)
        {
            if (argsCopy.Length == 0)
            {
                Console.WriteLine("Usage ExecServer.exe [/direct executablePath|/server entryAssemblyPath executablePath CPUindex] /shadow [executableArguments]");
                return(0);
            }
            var args = new List <string>(argsCopy);

            if (args[0] == "/direct")
            {
                args.RemoveAt(0);
                var executablePath = ExtractPath(args, "executable");
                var execServerApp  = new ExecServerRemote(executablePath, executablePath, false, false, true);
                int result         = execServerApp.Run(Environment.CurrentDirectory, new Dictionary <string, string>(), args.ToArray(), false, null);
                return(result);
            }

            if (args[0] == "/server")
            {
                args.RemoveAt(0);
                var entryAssemblyPath = ExtractPath(args, "entryAssembly");
                var executablePath    = ExtractPath(args, "executable");
                var cpu = int.Parse(args[0]);
                args.RemoveAt(0);
                int result = 0;
                try
                {
                    result = RunServer(entryAssemblyPath, executablePath, cpu);
                }
                catch (Exception ex)
                {
                    try
                    {
                        var pid     = Process.GetCurrentProcess().Id;
                        var logPath = GetExecServerErrorLogFilePath(executablePath, pid);
                        File.AppendAllText(logPath, $"Unexpected error while trying to run ExecServerApp [{executablePath}]. Exception: {ex}");
                    }
                    catch (Exception)
                    {
                        // Don't try to log an error
                    }
                    result = 1;
                }
                return(result);
            }
            else
            {
                bool useShadowCache = false;
                if (args[0] == "/shadow")
                {
                    args.RemoveAt(0);
                    useShadowCache = true;
                }

                var executablePath   = ExtractPath(args, "executable");
                var workingDirectory = ExtractPath(args, "working directory");

                // Collect environment variables
                var environmentVariables = new Dictionary <string, string>();
                foreach (DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables())
                {
                    environmentVariables.Add((string)environmentVariable.Key, (string)environmentVariable.Value);
                }

                int?debuggerProcessId = null;
                using (var debugger = VisualStudioDebugger.GetAttached())
                {
                    if (debugger != null)
                    {
                        debuggerProcessId = debugger.ProcessId;
                    }
                }

                var result = RunClient(executablePath, workingDirectory, environmentVariables, args, useShadowCache, debuggerProcessId);
                return(result);
            }
        }
Пример #8
0
        public static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            EditorPath.EditorTitle = XenkoGameStudio.EditorName;

            if (IntPtr.Size == 4)
            {
                MessageBox.Show("Xenko GameStudio requires a 64bit OS to run.", "Xenko", MessageBoxButton.OK, MessageBoxImage.Error);
                Environment.Exit(1);
            }

            PrivacyPolicyHelper.RestartApplication = RestartApplication;
            PrivacyPolicyHelper.EnsurePrivacyPolicyXenko30();

            // Set the XenkoDir environment variable
            var installDir = DirectoryHelper.GetInstallationDirectory("Xenko");

            Environment.SetEnvironmentVariable("XenkoDir", installDir);

            // We use MRU of the current version only when we're trying to reload last session.
            var mru = new MostRecentlyUsedFileCollection(InternalSettings.LoadProfileCopy, InternalSettings.MostRecentlyUsedSessions, InternalSettings.WriteFile, XenkoGameStudio.EditorVersionMajor, false);

            mru.LoadFromSettings();

            EditorSettings.Initialize();
            Thread.CurrentThread.Name = "Main thread";

            // Install Metrics for the editor
            using (XenkoGameStudio.MetricsClient = new MetricsClient(CommonApps.XenkoEditorAppId))
            {
                try
                {
                    // Environment.GetCommandLineArgs correctly process arguments regarding the presence of '\' and '"'
                    var args = Environment.GetCommandLineArgs().Skip(1).ToList();
                    var startupSessionPath = XenkoEditorSettings.StartupSession.GetValue();
                    var lastSessionPath    = EditorSettings.ReloadLastSession.GetValue() ? mru.MostRecentlyUsedFiles.FirstOrDefault() : null;
                    var initialSessionPath = !UPath.IsNullOrEmpty(startupSessionPath) ? startupSessionPath : lastSessionPath?.FilePath;

                    // Handle arguments
                    for (var i = 0; i < args.Count; i++)
                    {
                        if (args[i] == "/LauncherWindowHandle")
                        {
                            windowHandle = new IntPtr(long.Parse(args[++i]));
                        }
                        else if (args[i] == "/NewProject")
                        {
                            initialSessionPath = null;
                        }
                        else if (args[i] == "/DebugEditorGraphics")
                        {
                            EmbeddedGame.DebugMode = true;
                        }
                        else if (args[i] == "/RenderDoc")
                        {
                            // TODO: RenderDoc is not working here (when not in debug)
                            GameStudioPreviewService.DisablePreview = true;
                            renderDocManager = new RenderDocManager();
                        }
                        else if (args[i] == "/Reattach")
                        {
                            var debuggerProcessId = int.Parse(args[++i]);

                            if (!System.Diagnostics.Debugger.IsAttached)
                            {
                                using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId))
                                {
                                    debugger?.Attach();
                                }
                            }
                        }
                        else if (args[i] == "/RecordEffects")
                        {
                            GameStudioBuilderService.GlobalEffectLogPath = args[++i];
                        }
                        else
                        {
                            initialSessionPath = args[i];
                        }
                    }
                    RuntimeHelpers.RunModuleConstructor(typeof(Asset).Module.ModuleHandle);

                    //listen to logger for crash report
                    GlobalLogger.GlobalMessageLogged += GlobalLoggerOnGlobalMessageLogged;

                    mainDispatcher = Dispatcher.CurrentDispatcher;
                    mainDispatcher.InvokeAsync(() => Startup(initialSessionPath));

                    using (new WindowManager(mainDispatcher))
                    {
                        app = new App {
                            ShutdownMode = ShutdownMode.OnExplicitShutdown
                        };
                        app.Activated += (sender, eventArgs) =>
                        {
                            XenkoGameStudio.MetricsClient?.SetActiveState(true);
                        };
                        app.Deactivated += (sender, eventArgs) =>
                        {
                            XenkoGameStudio.MetricsClient?.SetActiveState(false);
                        };

                        app.InitializeComponent();
                        app.Run();
                    }

                    renderDocManager?.Shutdown();
                }
                catch (Exception e)
                {
                    HandleException(e, 0);
                }
            }
        }
        public void CanAttachToProcessWithDebugger()
        {
            var debuggerSetup = new DebuggerSetup();
            var logger = new MarkupStreamLogger(TestLog.Default);
            var debugger = new VisualStudioDebugger(debuggerSetup, logger, null);

            ProcessStartInfo processStartInfo = CreateProcessStartInfoForDummyProcess();

            Process process = Process.Start(processStartInfo);
            try
            {
                Assert.IsFalse(debugger.IsAttachedToProcess(process), "Initially the debugger is not attached.");

                Assert.AreEqual(AttachDebuggerResult.Attached, debugger.AttachToProcess(process),
                    "Should attach to process.");
                Assert.IsTrue(debugger.IsAttachedToProcess(process), "Should report that it has attached to process.");
                Assert.AreEqual(AttachDebuggerResult.AlreadyAttached, debugger.AttachToProcess(process),
                    "Should report that it was already attached to process.");

                /* This fails because Visual Studio returns "The requested operation is not supported."
                 * It seems to be related to having the Native debugger engine attached.
                Assert.AreEqual(DetachDebuggerResult.Detached, debugger.DetachFromProcess(process), "Should detach from process.");
                Assert.IsFalse(debugger.IsAttachedToProcess(process), "Finally the debugger is not attached.");
                Assert.AreEqual(DetachDebuggerResult.AlreadyDetached, debugger.DetachFromProcess(process), "Should report that it was already detached from process.");
                 */
            }
            finally
            {
                process.Kill();
            }
        }
Пример #10
0
        public static void Main()
        {
            // wait, are we already running?
            int waitToClose = 16;

            while (Process.GetProcessesByName("Focus.GameStudio").Length > 1)
            {
                if (waitToClose-- <= 0)
                {
                    MessageBox.Show("Focus GameStudio is already running! Only one instance is possible at a time.", "Focus", MessageBoxButton.OK, MessageBoxImage.Error);
                    Environment.Exit(1);
                }
                Thread.Sleep(250);
            }

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            EditorPath.EditorTitle = XenkoGameStudio.EditorName;

            if (IntPtr.Size == 4)
            {
                MessageBox.Show(EngineName + " " + GameStudioName + " requires a 64bit OS to run.", "Focus", MessageBoxButton.OK, MessageBoxImage.Error);
                Environment.Exit(1);
            }

            PrivacyPolicyHelper.RestartApplication = RestartApplication;
            PrivacyPolicyHelper.EnsurePrivacyPolicyXenko30();

            // We use MRU of the current version only when we're trying to reload last session.
            var mru = new MostRecentlyUsedFileCollection(InternalSettings.LoadProfileCopy, InternalSettings.MostRecentlyUsedSessions, InternalSettings.WriteFile);

            mru.LoadFromSettings();

            EditorSettings.Initialize();
            Thread.CurrentThread.Name    = "EditorGameThread (GameStudio)";
            EntityManager.EnforceThreads = false;

            try
            {
                // Environment.GetCommandLineArgs correctly process arguments regarding the presence of '\' and '"'
                var args = Environment.GetCommandLineArgs().Skip(1).ToList();
                var startupSessionPath = XenkoEditorSettings.StartupSession.GetValue();
                var lastSessionPath    = EditorSettings.ReloadLastSession.GetValue() ? mru.MostRecentlyUsedFiles.FirstOrDefault() : null;
                var initialSessionPath = !UPath.IsNullOrEmpty(startupSessionPath) ? startupSessionPath : lastSessionPath?.FilePath;

                // Handle arguments
                for (var i = 0; i < args.Count; i++)
                {
                    if (args[i] == "/LauncherWindowHandle")
                    {
                        windowHandle = new IntPtr(long.Parse(args[++i]));
                    }
                    else if (args[i] == "/NewProject")
                    {
                        initialSessionPath = null;
                    }
                    else if (args[i] == "/DebugEditorGraphics")
                    {
                        EmbeddedGame.DebugMode = true;
                    }
                    else if (args[i] == "/RenderDoc")
                    {
                        // TODO: RenderDoc is not working here (when not in debug)
                        GameStudioPreviewService.DisablePreview = true;
                        renderDocManager = new RenderDocManager();
                    }
                    else if (args[i] == "/Reattach")
                    {
                        var debuggerProcessId = int.Parse(args[++i]);

                        if (!System.Diagnostics.Debugger.IsAttached)
                        {
                            using (var debugger = VisualStudioDebugger.GetByProcess(debuggerProcessId))
                            {
                                debugger?.Attach();
                            }
                        }
                    }
                    else if (args[i] == "/RecordEffects")
                    {
                        GameStudioBuilderService.GlobalEffectLogPath = args[++i];
                    }
                    else
                    {
                        initialSessionPath = args[i];
                    }
                }
                RuntimeHelpers.RunModuleConstructor(typeof(Asset).Module.ModuleHandle);

                //listen to logger for crash report
                GlobalLogger.GlobalMessageLogged += GlobalLoggerOnGlobalMessageLogged;

                mainDispatcher = Dispatcher.CurrentDispatcher;
                mainDispatcher.InvokeAsync(() => Startup(initialSessionPath));

                using (new WindowManager(mainDispatcher))
                {
                    app = new App {
                        ShutdownMode = ShutdownMode.OnExplicitShutdown
                    };
                    app.InitializeComponent();
                    app.Run();
                }

                renderDocManager?.Shutdown();
            }
            catch (Exception e)
            {
                HandleException(e, 0);
            }
        }