示例#1
0
        private static Possible <Unit> TryStartAppServerProcess(AppServer.StartupParameters startupParameters)
        {
            // For simplicity, we clone the current environment block - but add one additional variable.
            // Some variables like PATH are needed for the server to even start. Others like the COMPlus_*
            // family and BuildXLDebugOnStart affect its startup behavior. However, note that each
            // client actually separately provides a replacement environment block to the server; these blocks
            // are intended to affect the pip graph, rather than server startup.
            var environment = new Dictionary <string, string>();

            foreach (DictionaryEntry variable in Environment.GetEnvironmentVariables())
            {
                environment[(string)variable.Key] = (string)variable.Value;
            }

            environment[BuildXlAppServerConfigVariable] = startupParameters.ToString();

            // We create a 'detached' process, since this server process is supposed to live a long time.
            // - We don't inherit any handles (maybe the caller accidentally leaked a bunch of pipe handles into this client process).
            // - We allocate a new hidden console.
            // - We require breakaway from containing jobs (otherwise, someone might use it to wait on the server by accident).
            int newProcessId;
            int errorCode;
            var status = BuildXL.Native.Processes.ProcessUtilities.CreateDetachedProcess(
                commandLine: startupParameters.PathToProcess,
                environmentVariables: environment,

                // Explicitly use the directory of the server process as the working directory. This will later be reset
                // to whatever directory the client is in when it connects to the server process. Some directory is needed
                // here, but it is intentionally using the incorrect directory rather than something that looks correct
                // since this is a once-only set. The correct path needs to be set for each build.
                workingDirectory: Path.GetDirectoryName(startupParameters.PathToProcess),
                newProcessId: out newProcessId,
                errorCode: out errorCode);

            switch (status)
            {
            case CreateDetachedProcessStatus.Succeeded:
                return(Unit.Void);

            case CreateDetachedProcessStatus.JobBreakwayFailed:
                return(new Failure <string>("The server process could not break-away from a containing job"));

            case CreateDetachedProcessStatus.ProcessCreationFailed:
                return(new NativeFailure(errorCode).Annotate("Failed to create a server process"));

            default:
                throw Contract.AssertFailure("Unhandled CreateDetachedProcessStatus");
            }
        }
示例#2
0
        private static ExitKind RunAppServer(AppServer.StartupParameters startupParameters)
        {
            ExitKind exitKind;

            using (
                var server =
                    new AppServer(maximumIdleTime: new TimeSpan(hours: 0, minutes: startupParameters.ServerMaxIdleTimeInMinutes, seconds: 0)))
            {
                exitKind = server.Run(startupParameters);
            }

            Exception telemetryShutdownException;

            if (AriaV2StaticState.TryShutDown(out telemetryShutdownException) == AriaV2StaticState.ShutDownResult.Failure)
            {
                exitKind = ExitKind.InfrastructureError;
            }

            return(exitKind);
        }
示例#3
0
        /// <summary>
        /// The core execution of the tool.
        /// </summary>
        /// <remarks>
        /// If you discover boilerplate in multiple implementations, add it to MainImpl, or add another inheritance hierarchy.
        /// </remarks>
        public int Run()
        {
            // We may have been started to be an app server. See StartAppServerProcess. If so, run as an app server (and expect no args).
            string startupParamsSerialized = Environment.GetEnvironmentVariable(BuildXlAppServerConfigVariable);

            if (startupParamsSerialized != null)
            {
                if (RawArgs.Length > 0)
                {
                    // TODO: Message
                    return(ExitCode.FromExitKind(ExitKind.InvalidCommandLine));
                }

                AppServer.StartupParameters startupParameters = AppServer.StartupParameters.TryParse(startupParamsSerialized);
                if (startupParameters == null)
                {
                    return(ExitCode.FromExitKind(ExitKind.InvalidCommandLine));
                }

                return(ExitCode.FromExitKind(RunAppServer(startupParameters)));
            }

            LightConfig lightConfig;

            if (!LightConfig.TryParse(RawArgs, out lightConfig) && lightConfig.Help == HelpLevel.None)
            {
                // If light config parsing failed, go through the full argument parser to collect & print the errors
                // it would catch.
                ICommandLineConfiguration config;
                Analysis.IgnoreResult(Args.TryParseArguments(RawArgs, new PathTable(), null, out config));
                HelpText.DisplayHelp(BuildXL.ToolSupport.HelpLevel.Verbose);
                return(ExitCode.FromExitKind(ExitKind.InvalidCommandLine));
            }

            // Not an app server; will either run fully within this process ('single instance') or start / connect to an app server.
            if (!lightConfig.NoLogo)
            {
                HelpText.DisplayLogo();
            }

            if (lightConfig.Help != HelpLevel.None)
            {
                // Need to cast here to convert from the configuration enum to the ToolSupoort enum. Their values
                // are manually kept in sync to avoid the additional dependency.
                HelpText.DisplayHelp((BuildXL.ToolSupport.HelpLevel)lightConfig.Help);

                return(ExitCode.FromExitKind(ExitKind.BuildNotRequested));
            }

            // Optionally perform some special tasks related to server mode
            switch (lightConfig.Server)
            {
            case ServerMode.Kill:
                ServerDeployment.KillServer(ServerDeployment.ComputeDeploymentDir(lightConfig.ServerDeploymentDirectory));
                Console.WriteLine(Strings.App_ServerKilled);
                return(ExitCode.FromExitKind(ExitKind.BuildNotRequested));
            }

            ExitKind exitKind = lightConfig.Server != ServerMode.Disabled
                ? ConnectToAppServerAndRun(lightConfig, RawArgs)
                : RunSingleInstance(RawArgs);

            return(ExitCode.FromExitKind(exitKind));
        }