private static ExitKind ConnectToAppServerAndRun(LightConfig lightConfig, IReadOnlyList <string> rawArgs) { using (AppServer.Connection connection = AppServer.TryStartOrConnect( startupParameters => TryStartAppServerProcess(startupParameters), lightConfig, lightConfig.ServerDeploymentDirectory, out var serverModeStatusAndPerf, out var environmentVariablesToPass)) { if (connection == null) { // Connection failed; fall back to single instance. return(RunSingleInstance(rawArgs, serverModeStatusAndPerf)); } else { try { return(connection.RunWithArgs(rawArgs, environmentVariablesToPass, serverModeStatusAndPerf)); } catch (BuildXLException ex) { Console.Error.WriteLine(Strings.AppServer_TerminatingClient_PipeDisconnect, ex.Message); return(ExitKind.InternalError); } } } }
/// <summary> /// Launches RunInSubst.exe specifying B:\\ as the target subst and the specified source subst (or the config. /// dsc location if not specified), followed by bxl.exe with its associated arguments. /// </summary> /// <remarks> /// This execution always appends to bxl arguments the corresponding subst source and target. In addition, it overrides with /// /RunInSubst-, so the launched process won't try to launch RunInSubst.exe again. /// </remarks> private int ExecuteRunInSubst(LightConfig lightConfig, string[] rawArgs) { // Use the substTarget specified, otherwise default to B:\ var substTarget = string.IsNullOrEmpty(lightConfig.SubstTarget) ? "B:\\" : lightConfig.SubstTarget; // Use the subst source specified. Otherwise use the location of the main config file as the default string substSource = string.IsNullOrEmpty(lightConfig.SubstSource) ? Directory.GetParent(lightConfig.Config).FullName : lightConfig.SubstSource; string clientPath = AssemblyHelper.GetThisProgramExeLocation(); // CODESYNC: keep in sync with bxl deployment, we are assuming RunInSubst.exe is deployed alongside bxl.exe string runInSubstPath = Path.Combine(Directory.GetParent(clientPath).FullName, "RunInSubst.exe"); // Launch bxl again via RunInSubst as a child process, with same arguments, but disable /runInSubst and specify subst target and source string arguments = $"B=\"{substSource}\" \"{clientPath}\" {string.Join(" ", rawArgs)} /runInSubst- /substTarget:{substTarget} /substSource:\"{substSource}\""; var startInfo = new ProcessStartInfo { FileName = runInSubstPath, Arguments = arguments, WorkingDirectory = Directory.GetCurrentDirectory(), UseShellExecute = false, }; var process = new Process() { StartInfo = startInfo }; process.Start(); process.WaitForExit(); return(process.ExitCode); }
/// <summary> /// Attempts to parse the configuration. This is a subset of what's parsed in Args /// </summary> /// <remarks> /// Keep the subset of parsing here limited to whatever's needed to run the client process /// </remarks> public static bool TryParse(string[] args, out LightConfig lightConfig) { lightConfig = new LightConfig(); var cl = new CommandLineUtilities(args); foreach (var option in cl.Options) { switch (option.Name.ToUpperInvariant()) { case "C": case "CONFIG": lightConfig.Config = CommandLineUtilities.ParseStringOption(option); break; case "COLOR": case "COLOR+": case "COLOR-": lightConfig.Color = CommandLineUtilities.ParseBooleanOption(option); break; case "DISABLEPATHTRANSLATION": lightConfig.DisablePathTranslation = true; break; case "HELP": lightConfig.Help = Args.ParseHelpOption(option); break; case "NOLOGO": case "NOLOGO+": case "NOLOGO-": lightConfig.NoLogo = CommandLineUtilities.ParseBooleanOption(option); break; case "FANCYCONSOLE": case "FANCYCONSOLE+": case "FANCYCONSOLE-": case "EXP:FANCYCONSOLE": case "EXP:FANCYCONSOLE+": case "EXP:FANCYCONSOLE-": lightConfig.FancyConsole = CommandLineUtilities.ParseBooleanOption(option); break; case "ENABLEDEDUP": case "ENABLEDEDUP+": case "ENABLEDEDUP-": lightConfig.EnableDedup = CommandLineUtilities.ParseBooleanOption(option); break; case "HASHTYPE": lightConfig.HashType = CommandLineUtilities.ParseStringOption(option); break; case "SERVER": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, true, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVER+": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, true, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVER-": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, false, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVERMAXIDLETIMEINMINUTES": lightConfig.ServerIdleTimeInMinutes = CommandLineUtilities.ParseInt32Option(option, 1, int.MaxValue); break; case "SERVERDEPLOYMENTDIR": lightConfig.ServerDeploymentDirectory = CommandLineUtilities.ParseStringOption(option); break; case "SUBSTSOURCE": lightConfig.SubstSource = CommandLineUtilities.ParseStringOption(option); break; case "SUBSTTARGET": lightConfig.SubstTarget = CommandLineUtilities.ParseStringOption(option); break; case "RUNINSUBST": case "RUNINSUBST+": lightConfig.RunInSubst = true; break; case "RUNINSUBST-": lightConfig.RunInSubst = false; break; } } // This has no attempt at any sort of error handling. Leave that to the real argument parser. Only detect errors // If RunInSubst is specified without an explicit subst source, we fail if the config file does not exist since we need to compute the parent directory of the main config during light config interpretation return(!string.IsNullOrWhiteSpace(lightConfig.Config) && (!lightConfig.RunInSubst || !string.IsNullOrEmpty(lightConfig.SubstSource) || File.Exists(lightConfig.Config))); }
/// <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)); }
/// <summary> /// Attempts to parse the configuration. This is a subset of what's parsed in Args /// </summary> /// <remarks> /// Keep the subset of parsing here limited to whatever's needed to run the client process /// </remarks> public static bool TryParse(string[] args, out LightConfig lightConfig) { lightConfig = new LightConfig(); var cl = new CommandLineUtilities(args); foreach (var option in cl.Options) { switch (option.Name.ToUpperInvariant()) { case "C": case "CONFIG": lightConfig.Config = CommandLineUtilities.ParseStringOption(option); break; case "COLOR": case "COLOR+": case "COLOR-": lightConfig.Color = CommandLineUtilities.ParseBooleanOption(option); break; case "DISABLEPATHTRANSLATION": lightConfig.DisablePathTranslation = true; break; case "HELP": lightConfig.Help = Args.ParseHelpOption(option); break; case "NOLOGO": case "NOLOGO+": case "NOLOGO-": lightConfig.NoLogo = CommandLineUtilities.ParseBooleanOption(option); break; case "FANCYCONSOLE": case "FANCYCONSOLE+": case "FANCYCONSOLE-": case "EXP:FANCYCONSOLE": case "EXP:FANCYCONSOLE+": case "EXP:FANCYCONSOLE-": lightConfig.FancyConsole = CommandLineUtilities.ParseBooleanOption(option); break; case "ENABLEDEDUP": case "ENABLEDEDUP+": case "ENABLEDEDUP-": lightConfig.EnableDedup = CommandLineUtilities.ParseBooleanOption(option); break; case "SERVER": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, true, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVER+": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, true, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVER-": lightConfig.Server = CommandLineUtilities.ParseBoolEnumOption(option, false, ServerMode.Enabled, ServerMode.Disabled); break; case "SERVERMAXIDLETIMEINMINUTES": lightConfig.ServerIdleTimeInMinutes = CommandLineUtilities.ParseInt32Option(option, 1, int.MaxValue); break; case "SERVERDEPLOYMENTDIR": lightConfig.ServerDeploymentDirectory = CommandLineUtilities.ParseStringOption(option); break; case "SUBSTSOURCE": lightConfig.SubstSource = CommandLineUtilities.ParseStringOption(option); break; case "SUBSTTARGET": lightConfig.SubstTarget = CommandLineUtilities.ParseStringOption(option); break; } } // This has no attempt at any sort of error handling. Leave that to the real argument parser. Only detect errors return(!string.IsNullOrWhiteSpace(lightConfig.Config)); }