private async Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile, bool validateSettings) { var launchSettings = new List <DebugLaunchSettings>(); // Resolve the tokens in the profile ILaunchProfile resolvedProfile = await TokenReplacer.ReplaceTokensInProfileAsync(activeProfile); // For "run project", we want to launch the process if it's a console app via the command shell when // not debugging, except when this debug session is being launched for profiling. bool useCmdShell = IsRunProjectCommand(resolvedProfile) && (launchOptions & (DebugLaunchOptions.NoDebug | DebugLaunchOptions.Profiling)) == DebugLaunchOptions.NoDebug && await IsConsoleAppAsync(); DebugLaunchSettings consoleTarget = await GetConsoleTargetForProfile(resolvedProfile, launchOptions, useCmdShell, validateSettings); launchSettings.Add(consoleTarget); return(launchSettings.ToArray()); }
/// <summary> /// When F5\Ctrl-F5 is invoked on a NoAction profile and error is thrown to the user. Typical case is trying to run a /// class library project /// </summary> public Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile) { if (activeProfile.OtherSettings.TryGetValue("ErrorString", out object objErrorString) && objErrorString is string errorString) { throw new Exception(string.Format(VSResources.ErrorInProfilesFile2, Path.GetFileNameWithoutExtension(_configuredProject.UnconfiguredProject.FullPath), errorString)); } throw new Exception(string.Format(VSResources.ErrorInProfilesFile, Path.GetFileNameWithoutExtension(_configuredProject.UnconfiguredProject.FullPath))); }
public Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile) { return(QueryDebugTargetsAsync(launchOptions, activeProfile, validateSettings: false)); }
/// <summary> /// This provider handles running the Project and empty commandName (this generally just runs the executable) /// </summary> public bool SupportsProfile(ILaunchProfile profile) { return(string.IsNullOrWhiteSpace(profile.CommandName) || IsRunProjectCommand(profile) || IsRunExecutableCommand(profile)); }
/// <summary> /// This provider handles the NoAction profile /// </summary> public bool SupportsProfile(ILaunchProfile profile) { return(string.Equals(profile.CommandName, LaunchSettingsProvider.ErrorProfileCommandName)); }
public LaunchCompleteCallback(IProjectThreadingService threadingService, DebugLaunchOptions launchOptions, IDebugProfileLaunchTargetsProvider?targetProfile, ILaunchProfile activeProfile) { _threadingService = threadingService; _launchOptions = launchOptions; _targetProfile = targetProfile; _activeProfile = activeProfile; }
private static bool IsRunProjectCommand(ILaunchProfile profile) { return(string.Equals(profile.CommandName, LaunchSettingsProvider.RunProjectCommandName, StringComparison.OrdinalIgnoreCase)); }
public async Task <bool> CanBeStartupProjectAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) { try { _ = await QueryDebugTargetsForDebugLaunchAsync(launchOptions, profile); } catch (ProjectNotRunnableDirectlyException) { return(false); } catch (Exception) { } return(true); }
private static bool IsRunExecutableCommand(ILaunchProfile profile) { return(string.Equals(profile.CommandName, LaunchSettingsProvider.RunExecutableCommandName, StringComparisons.LaunchProfileCommandNames)); }
public Task OnAfterLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) => Task.CompletedTask;
private static bool ProfileShouldBePersisted(ILaunchProfile profile) { return(!profile.IsInMemoryObject()); }
/// <summary> /// This is called on F5 to return the list of debug targets. What we return depends on the type /// of project. /// </summary> private async Task <DebugLaunchSettings> GetConsoleTargetForProfile(ILaunchProfile resolvedProfile, DebugLaunchOptions launchOptions, bool useCmdShell) { var settings = new DebugLaunchSettings(launchOptions); string executable, arguments; string projectFolder = Path.GetDirectoryName(UnconfiguredProject.FullPath); var configuredProject = await GetConfiguredProjectForDebugAsync().ConfigureAwait(false); // If no working directory specified in the profile, we default to the one returned from GetRunnableProjectInformationAsync (if running // the project), or the project folder. string defaultWorkingDir = projectFolder; // Is this profile just running the project? If so we ignore the exe if (IsRunProjectCommand(resolvedProfile)) { // Can't run a class library directly if (await GetIsClassLibraryAsync().ConfigureAwait(false)) { throw new Exception(VSResources.ProjectNotRunnableDirectly); } // Get the executable to run, the arguments and the default working directory var runData = await GetRunnableProjectInformationAsync(configuredProject).ConfigureAwait(false); executable = runData.Item1; arguments = runData.Item2; if (!string.IsNullOrWhiteSpace(runData.Item3)) { defaultWorkingDir = runData.Item3; } if (!string.IsNullOrWhiteSpace(resolvedProfile.CommandLineArgs)) { arguments = arguments + " " + resolvedProfile.CommandLineArgs; } } else { executable = resolvedProfile.ExecutablePath; arguments = resolvedProfile.CommandLineArgs; } string workingDir; if (string.IsNullOrWhiteSpace(resolvedProfile.WorkingDirectory)) { workingDir = defaultWorkingDir; } else { // If the working directory is not rooted we assume it is relative to the project directory if (Path.IsPathRooted(resolvedProfile.WorkingDirectory)) { workingDir = resolvedProfile.WorkingDirectory; } else { workingDir = Path.GetFullPath(Path.Combine(projectFolder, resolvedProfile.WorkingDirectory)); } } // IF the executable is not rooted, we want to make is relative to the workingDir unless is doesn't contain // any path elements. In that case we are going to assume it is on the path if (!string.IsNullOrWhiteSpace(executable)) { if (!Path.IsPathRooted(executable) && executable.IndexOf(Path.DirectorySeparatorChar) != -1) { executable = Path.GetFullPath(Path.Combine(workingDir, executable)); } } // Now validate the executable path and working directory exist ValidateSettings(executable, workingDir, resolvedProfile.Name); GetExeAndArguments(useCmdShell, executable, arguments, out string finalExecutable, out string finalArguments); // Apply environment variables. if (resolvedProfile.EnvironmentVariables != null && resolvedProfile.EnvironmentVariables.Count > 0) { foreach (var kvp in resolvedProfile.EnvironmentVariables) { settings.Environment[kvp.Key] = kvp.Value; } } settings.Executable = finalExecutable; settings.Arguments = finalArguments; settings.CurrentDirectory = workingDir; settings.LaunchOperation = DebugLaunchOperation.CreateProcess; settings.LaunchDebugEngineGuid = await GetDebuggingEngineAsync(configuredProject).ConfigureAwait(false); settings.LaunchOptions = launchOptions | DebugLaunchOptions.StopDebuggingOnEnd; if (settings.Environment.Count > 0) { settings.LaunchOptions = settings.LaunchOptions | DebugLaunchOptions.MergeEnvironment; } return(settings); }
/// <summary> /// This provider handles running the Project and empty commandName (this generally just runs the executable) /// </summary> public bool SupportsProfile(ILaunchProfile profile) { return(string.IsNullOrWhiteSpace(profile.CommandName) || profile.CommandName.Equals(LaunchSettingsProvider.RunProjectCommandName, StringComparison.OrdinalIgnoreCase) || profile.CommandName.Equals(LaunchSettingsProvider.RunExecutableCommandName, StringComparison.OrdinalIgnoreCase)); }
public static IWritableLaunchProfile ToWritableLaunchProfile(this ILaunchProfile curProfile) { return(new WritableLaunchProfile(curProfile)); }
public Task OnBeforeLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile, IReadOnlyList <IDebugLaunchSettings> debugLaunchSettings) => Task.CompletedTask;
/// <summary> /// This is called on F5 to return the list of debug targets. What we return depends on the type /// of project. /// </summary> private async Task <DebugLaunchSettings> GetConsoleTargetForProfile(ILaunchProfile resolvedProfile, DebugLaunchOptions launchOptions, bool validateSettings) { var settings = new DebugLaunchSettings(launchOptions); string?executable, arguments; string projectFolder = Path.GetDirectoryName(_project.UnconfiguredProject.FullPath); ConfiguredProject?configuredProject = await GetConfiguredProjectForDebugAsync(); Assumes.NotNull(configuredProject); // If no working directory specified in the profile, we default to output directory. If for some reason the output directory // is not specified, fall back to the project folder. string defaultWorkingDir = await GetOutputDirectoryAsync(configuredProject); if (string.IsNullOrEmpty(defaultWorkingDir)) { defaultWorkingDir = projectFolder; } else { if (!Path.IsPathRooted(defaultWorkingDir)) { defaultWorkingDir = _fileSystem.GetFullPath(Path.Combine(projectFolder, defaultWorkingDir)); } // If the directory at OutDir doesn't exist, fall back to the project folder if (!_fileSystem.DirectoryExists(defaultWorkingDir)) { defaultWorkingDir = projectFolder; } } // Is this profile just running the project? If so we ignore the exe if (IsRunProjectCommand(resolvedProfile)) { // Get the executable to run, the arguments and the default working directory string workingDirectory; (executable, arguments, workingDirectory) = await GetRunnableProjectInformationAsync(configuredProject, validateSettings); if (!string.IsNullOrWhiteSpace(workingDirectory)) { defaultWorkingDir = workingDirectory; } if (!string.IsNullOrWhiteSpace(resolvedProfile.CommandLineArgs)) { arguments = arguments + " " + resolvedProfile.CommandLineArgs; } } else { executable = resolvedProfile.ExecutablePath; arguments = resolvedProfile.CommandLineArgs; } string workingDir; if (Strings.IsNullOrWhiteSpace(resolvedProfile.WorkingDirectory)) { workingDir = defaultWorkingDir; } else { // If the working directory is not rooted we assume it is relative to the project directory workingDir = _fileSystem.GetFullPath(Path.Combine(projectFolder, resolvedProfile.WorkingDirectory.Replace("/", "\\"))); } // IF the executable is not rooted, we want to make is relative to the workingDir unless is doesn't contain // any path elements. In that case we are going to assume it is in the current directory of the VS process, or on // the environment path. If we can't find it, we just launch it as before. if (!Strings.IsNullOrWhiteSpace(executable)) { executable = executable.Replace("/", "\\"); if (Path.GetPathRoot(executable) == "\\") { // Root of current drive executable = _fileSystem.GetFullPath(executable); } else if (!Path.IsPathRooted(executable)) { if (executable.Contains("\\")) { // Combine with the working directory used by the profile executable = _fileSystem.GetFullPath(Path.Combine(workingDir, executable)); } else { // Try to resolve against the current working directory (for compat) and failing that, the environment path. string exeName = executable.EndsWith(".exe", StringComparisons.Paths) ? executable : executable + ".exe"; string fullPath = _fileSystem.GetFullPath(exeName); if (_fileSystem.FileExists(fullPath)) { executable = fullPath; } else { string?fullPathFromEnv = GetFullPathOfExeFromEnvironmentPath(exeName); if (fullPathFromEnv != null) { executable = fullPathFromEnv; } } } } } if (validateSettings) { ValidateSettings(executable, workingDir, resolvedProfile.Name); } // Apply environment variables. if (resolvedProfile.EnvironmentVariables != null && !resolvedProfile.EnvironmentVariables.IsEmpty) { foreach ((string key, string value) in resolvedProfile.EnvironmentVariables) { settings.Environment[key] = value; } } settings.LaunchOperation = DebugLaunchOperation.CreateProcess; settings.LaunchDebugEngineGuid = await GetDebuggingEngineAsync(configuredProject); if (resolvedProfile.IsNativeDebuggingEnabled()) { settings.AdditionalDebugEngines.Add(DebuggerEngines.NativeOnlyEngine); } if (resolvedProfile.IsSqlDebuggingEnabled()) { settings.AdditionalDebugEngines.Add(DebuggerEngines.SqlEngine); } if (settings.Environment.Count > 0) { settings.LaunchOptions |= DebugLaunchOptions.MergeEnvironment; } bool useCmdShell = false; if (await IsConsoleAppAsync()) { if (await IsIntegratedConsoleEnabledAsync()) { settings.LaunchOptions |= DebugLaunchOptions.IntegratedConsole; } useCmdShell = UseCmdShellForConsoleLaunch(resolvedProfile, settings.LaunchOptions); } GetExeAndArguments(useCmdShell, executable, arguments, out string?finalExecutable, out string?finalArguments); settings.Executable = finalExecutable; settings.Arguments = finalArguments; settings.CurrentDirectory = workingDir; settings.Project = _unconfiguredProjectVsServices.VsHierarchy; if (resolvedProfile.IsRemoteDebugEnabled()) { settings.RemoteMachine = resolvedProfile.RemoteDebugMachine(); string?remoteAuthenticationMode = resolvedProfile.RemoteAuthenticationMode(); if (!Strings.IsNullOrEmpty(remoteAuthenticationMode)) { IRemoteAuthenticationProvider?remoteAuthenticationProvider = _remoteDebuggerAuthenticationService.FindProviderForAuthenticationMode(remoteAuthenticationMode); if (remoteAuthenticationProvider != null) { settings.PortSupplierGuid = remoteAuthenticationProvider.PortSupplierGuid; } } } return(settings); }
/// <summary> /// Called just after the launch to do additional work (put up ui, do special configuration etc). /// </summary> public Task OnAfterLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) { throw new InvalidOperationException($"Wrong overload of {nameof(OnAfterLaunchAsync)} called."); }
/// <summary> /// Returns the provider which knows how to launch the profile type. /// </summary> public async Task <IDebugProfileLaunchTargetsProvider?> GetLaunchTargetsProviderAsync(ILaunchProfile profile) { // WORKAROUND: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1152611 await _threadingService.SwitchToUIThread(); // We search through the imports in order to find the one which supports the profile foreach (Lazy <IDebugProfileLaunchTargetsProvider, IOrderPrecedenceMetadataView> provider in LaunchTargetsProviders) { if (provider.Value.SupportsProfile(profile)) { return(provider.Value); } } return(null); }
/// <summary> /// This is called on F5/Ctrl-F5 to return the list of debug targets.What we return depends on the type /// of project. /// </summary> public async Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile) { List <DebugLaunchSettings> launchSettings = new List <DebugLaunchSettings>(); // Resolve the tokens in the profile ILaunchProfile resolvedProfile = await TokenReplacer.ReplaceTokensInProfileAsync(activeProfile).ConfigureAwait(false); // For "run project", we want to launch the process via the command shell when not debugging, except when this debug session is being // launched for profiling. bool useCmdShell = IsRunProjectCommand(resolvedProfile) && (launchOptions & (DebugLaunchOptions.NoDebug | DebugLaunchOptions.Profiling)) == DebugLaunchOptions.NoDebug; var consoleTarget = await GetConsoleTargetForProfile(resolvedProfile, launchOptions, useCmdShell).ConfigureAwait(false); launchSettings.Add(consoleTarget); return(launchSettings.ToArray()); }
public async Task <bool> CanBeStartupProjectAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) { if (IsRunProjectCommand(profile)) { // If the profile uses the "Project" command, check that the project specifies // something we can run. ConfiguredProject?configuredProject = await GetConfiguredProjectForDebugAsync(); Assumes.NotNull(configuredProject); Assumes.Present(configuredProject.Services.ProjectPropertiesProvider); IProjectProperties properties = configuredProject.Services.ProjectPropertiesProvider.GetCommonProperties(); string?runCommand = await GetTargetCommandAsync(properties, validateSettings : true); if (string.IsNullOrWhiteSpace(runCommand)) { return(false); } } // Otherwise, the profile must be using the "Executable" command in which case it // can always be a start-up project. return(true); }
/// <summary> /// This is called on F5 to return the list of debug targets. What we return depends on the type /// of project. /// </summary> private async Task <DebugLaunchSettings> GetConsoleTargetForProfile(ILaunchProfile resolvedProfile, DebugLaunchOptions launchOptions, bool useCmdShell) { var settings = new DebugLaunchSettings(launchOptions); string executable, arguments; string projectFolder = Path.GetDirectoryName(UnconfiguredProject.FullPath); var configuredProject = await GetConfiguredProjectForDebugAsync().ConfigureAwait(false); // If no working directory specified in the profile, we default to the one returned from GetRunnableProjectInformationAsync (if running // the project), or the project folder. string defaultWorkingDir = projectFolder; // Is this profile just running the project? If so we ignore the exe if (IsRunProjectCommand(resolvedProfile)) { // Can't run a class library directly if (await GetIsClassLibraryAsync().ConfigureAwait(false)) { throw new Exception(VSResources.ProjectNotRunnableDirectly); } // Get the executable to run, the arguments and the default working directory var runData = await GetRunnableProjectInformationAsync(configuredProject).ConfigureAwait(false); executable = runData.Item1; arguments = runData.Item2; if (!string.IsNullOrWhiteSpace(runData.Item3)) { defaultWorkingDir = runData.Item3; } if (!string.IsNullOrWhiteSpace(resolvedProfile.CommandLineArgs)) { arguments = arguments + " " + resolvedProfile.CommandLineArgs; } } else { executable = resolvedProfile.ExecutablePath; arguments = resolvedProfile.CommandLineArgs; } string workingDir; if (string.IsNullOrWhiteSpace(resolvedProfile.WorkingDirectory)) { workingDir = defaultWorkingDir; } else { // If the working directory is not rooted we assume it is relative to the project directory workingDir = TheFileSystem.GetFullPath(Path.Combine(projectFolder, resolvedProfile.WorkingDirectory.Replace("/", "\\"))); } // IF the executable is not rooted, we want to make is relative to the workingDir unless is doesn't contain // any path elements. In that case we are going to assume it is in the current directory of the VS process, or on // the environment path. If we can't find it, we just launch it as before. if (!string.IsNullOrWhiteSpace(executable)) { executable = executable.Replace("/", "\\"); if (Path.GetPathRoot(executable) == "\\") { // Root of current drive executable = TheFileSystem.GetFullPath(executable); } else if (!Path.IsPathRooted(executable)) { if (executable.Contains("\\")) { // Combine with the working directory used by the profile executable = TheFileSystem.GetFullPath(Path.Combine(workingDir, executable)); } else { // Try to resolve against the current working directory (for compat) and failing that, the environment path. var exeName = executable.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)? executable : executable + ".exe"; var fullPath = TheFileSystem.GetFullPath(exeName); if (TheFileSystem.FileExists(fullPath)) { executable = fullPath; } else { fullPath = GetFullPathOfExeFromEnvironmentPath(exeName); if (fullPath != null) { executable = fullPath; } } } } } // Now validate the executable path and working directory exist ValidateSettings(executable, workingDir, resolvedProfile.Name); GetExeAndArguments(useCmdShell, executable, arguments, out string finalExecutable, out string finalArguments); // Apply environment variables. if (resolvedProfile.EnvironmentVariables != null && resolvedProfile.EnvironmentVariables.Count > 0) { foreach (var kvp in resolvedProfile.EnvironmentVariables) { settings.Environment[kvp.Key] = kvp.Value; } } settings.Executable = finalExecutable; settings.Arguments = finalArguments; settings.CurrentDirectory = workingDir; settings.LaunchOperation = DebugLaunchOperation.CreateProcess; settings.LaunchDebugEngineGuid = await GetDebuggingEngineAsync(configuredProject).ConfigureAwait(false); if (resolvedProfile.NativeDebuggingIsEnabled()) { settings.AdditionalDebugEngines.Add(DebuggerEngines.NativeOnlyEngine); } if (settings.Environment.Count > 0) { settings.LaunchOptions = settings.LaunchOptions | DebugLaunchOptions.MergeEnvironment; } return(settings); }
/// <summary> /// This is called on F5/Ctrl-F5 to return the list of debug targets. What we return depends on the type /// of project. /// </summary> public async Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile) => await QueryDebugTargetsAsync(launchOptions, activeProfile, validateSettings : false) ?? throw new Exception(VSResources.ProjectNotRunnableDirectly);
/// <summary> /// Called just prior to launch to do additional work (put up ui, do special configuration etc). /// </summary> public Task OnBeforeLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) { return(Task.CompletedTask); }
/// <summary> /// Returns <see langword="null"/> if the debug launch settings are <see langword="null"/>. Otherwise, the list of debug launch settings. /// </summary> private async Task <IReadOnlyList <IDebugLaunchSettings>?> QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile, bool validateSettings) { // Resolve the tokens in the profile ILaunchProfile resolvedProfile = await _tokenReplacer.ReplaceTokensInProfileAsync(activeProfile); DebugLaunchSettings?consoleTarget = await GetConsoleTargetForProfileAsync(resolvedProfile, launchOptions, validateSettings); return(consoleTarget == null ? null : new[] { consoleTarget }); }
/// <summary> /// Called just prior to launch to do additional work (put up ui, do special configuration etc). /// </summary> public Task OnAfterLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) { // Nothing to do here return(Task.CompletedTask); }
private static bool IsRunProjectCommand(ILaunchProfile profile) => string.Equals(profile.CommandName, LaunchSettingsProvider.RunProjectCommandName, StringComparisons.LaunchProfileCommandNames);
/// <summary> /// Helper returns true if this is a profile which should be persisted. Filters out noaction profiles /// </summary> private bool ProfileShouldBePersisted(ILaunchProfile profile) { return(!string.Equals(profile.CommandName, ErrorProfileCommandName)); }
/// <summary> /// This is called on F5 to return the list of debug targets. What we return depends on the type /// of project. /// </summary> /// <returns><see langword="null"/> if the runnable project information is <see langword="null"/>. Otherwise, the debug launch settings.</returns> internal async Task <DebugLaunchSettings?> GetConsoleTargetForProfileAsync(ILaunchProfile resolvedProfile, DebugLaunchOptions launchOptions, bool validateSettings) { var settings = new DebugLaunchSettings(launchOptions); string?executable, arguments; string projectFolder = Path.GetDirectoryName(_project.UnconfiguredProject.FullPath) ?? string.Empty; ConfiguredProject?configuredProject = await GetConfiguredProjectForDebugAsync(); Assumes.NotNull(configuredProject); // If no working directory specified in the profile, we default to output directory. If for some reason the output directory // is not specified, fall back to the project folder. string defaultWorkingDir = await GetOutputDirectoryAsync(configuredProject); if (string.IsNullOrEmpty(defaultWorkingDir)) { defaultWorkingDir = projectFolder; } else { if (!Path.IsPathRooted(defaultWorkingDir)) { defaultWorkingDir = _fileSystem.GetFullPath(Path.Combine(projectFolder, defaultWorkingDir)); } // If the directory at OutDir doesn't exist, fall back to the project folder if (!_fileSystem.DirectoryExists(defaultWorkingDir)) { defaultWorkingDir = projectFolder; } } string?commandLineArgs = resolvedProfile.CommandLineArgs? .Replace("\r\n", " ") .Replace("\r", " ") .Replace("\n", " ") .Replace("\\r\\n", "\r\n") .Replace("\\n", "\n"); // Is this profile just running the project? If so we ignore the exe if (IsRunProjectCommand(resolvedProfile)) { // Get the executable to run, the arguments and the default working directory (string Command, string Arguments, string WorkingDirectory)? runnableProjectInfo = await GetRunnableProjectInformationAsync(configuredProject, validateSettings); if (runnableProjectInfo == null) { return(null); } string workingDirectory; (executable, arguments, workingDirectory) = runnableProjectInfo.Value; if (!string.IsNullOrWhiteSpace(workingDirectory)) { defaultWorkingDir = workingDirectory; } if (!string.IsNullOrWhiteSpace(commandLineArgs)) { arguments = arguments + " " + commandLineArgs; } } else { executable = resolvedProfile.ExecutablePath; arguments = commandLineArgs; } string workingDir; if (Strings.IsNullOrWhiteSpace(resolvedProfile.WorkingDirectory)) { workingDir = defaultWorkingDir; } else { // If the working directory is not rooted we assume it is relative to the project directory workingDir = _fileSystem.GetFullPath(Path.Combine(projectFolder, resolvedProfile.WorkingDirectory.Replace("/", "\\"))); } // IF the executable is not rooted, we want to make is relative to the workingDir unless is doesn't contain // any path elements. In that case we are going to assume it is in the current directory of the VS process, or on // the environment path. If we can't find it, we just launch it as before. if (!Strings.IsNullOrWhiteSpace(executable)) { executable = executable.Replace("/", "\\"); if (Path.GetPathRoot(executable) == "\\") { // Root of current drive executable = _fileSystem.GetFullPath(executable); } else if (!Path.IsPathRooted(executable)) { if (executable.Contains("\\")) { // Combine with the working directory used by the profile executable = _fileSystem.GetFullPath(Path.Combine(workingDir, executable)); } else { // Try to resolve against the current working directory (for compat) and failing that, the environment path. string exeName = executable.EndsWith(".exe", StringComparisons.Paths) ? executable : executable + ".exe"; string fullPath = _fileSystem.GetFullPath(exeName); if (_fileSystem.FileExists(fullPath)) { executable = fullPath; } else { string?fullPathFromEnv = GetFullPathOfExeFromEnvironmentPath(exeName); if (fullPathFromEnv != null) { executable = fullPathFromEnv; } } } } } if (validateSettings) { ValidateSettings(executable, workingDir, resolvedProfile.Name); } // Apply environment variables. foreach ((string key, string value) in resolvedProfile.EnumerateEnvironmentVariables()) { settings.Environment[key] = value; } settings.LaunchOperation = DebugLaunchOperation.CreateProcess; settings.LaunchDebugEngineGuid = await GetDebuggingEngineAsync(configuredProject); if (resolvedProfile.IsNativeDebuggingEnabled()) { settings.AdditionalDebugEngines.Add(DebuggerEngines.NativeOnlyEngine); } if (resolvedProfile.IsSqlDebuggingEnabled()) { settings.AdditionalDebugEngines.Add(DebuggerEngines.SqlEngine); } bool useCmdShell = false; if (await _outputTypeChecker.IsConsoleAsync()) { if (await IsIntegratedConsoleEnabledAsync()) { settings.LaunchOptions |= DebugLaunchOptions.IntegratedConsole; } useCmdShell = UseCmdShellForConsoleLaunch(resolvedProfile, settings.LaunchOptions); } GetExeAndArguments(useCmdShell, executable, arguments, out string?finalExecutable, out string?finalArguments); settings.Executable = finalExecutable; settings.Arguments = finalArguments; settings.CurrentDirectory = workingDir; settings.Project = _unconfiguredProjectVsServices.VsHierarchy; if (resolvedProfile.IsRemoteDebugEnabled()) { settings.RemoteMachine = resolvedProfile.RemoteDebugMachine(); string?remoteAuthenticationMode = resolvedProfile.RemoteAuthenticationMode(); if (!Strings.IsNullOrEmpty(remoteAuthenticationMode)) { IRemoteAuthenticationProvider?remoteAuthenticationProvider = _remoteDebuggerAuthenticationService.FindProviderForAuthenticationMode(remoteAuthenticationMode); if (remoteAuthenticationProvider != null) { settings.PortSupplierGuid = remoteAuthenticationProvider.PortSupplierGuid; } } } // WebView2 debugging is only supported for Project and Executable commands if (resolvedProfile.IsJSWebView2DebuggingEnabled() && (IsRunExecutableCommand(resolvedProfile) || IsRunProjectCommand(resolvedProfile))) { // If JS Debugger is selected, we would need to change the launch debugger to that one settings.LaunchDebugEngineGuid = DebuggerEngines.JavaScriptForWebView2Engine; // Create the launch params needed for the JS debugger var debuggerLaunchOptions = new JObject( new JProperty("type", "pwa-msedge"), new JProperty("runtimeExecutable", finalExecutable), new JProperty("webRoot", workingDir), // We use the Working Directory debugging option as the WebRoot, to map the urls to files on disk new JProperty("useWebView", true), new JProperty("runtimeArgs", finalArguments) ); settings.Options = JsonConvert.SerializeObject(debuggerLaunchOptions); } if (await HotReloadShouldBeEnabledAsync(resolvedProfile, launchOptions) && await _hotReloadSessionManager.Value.TryCreatePendingSessionAsync(settings.Environment)) { // Enable XAML Hot Reload settings.Environment["ENABLE_XAML_DIAGNOSTICS_SOURCE_INFO"] = "1"; } if (settings.Environment.Count > 0) { settings.LaunchOptions |= DebugLaunchOptions.MergeEnvironment; } return(settings); }
private async Task <IReadOnlyList <IDebugLaunchSettings> > QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile activeProfile, bool validateSettings) { var launchSettings = new List <DebugLaunchSettings>(); // Resolve the tokens in the profile ILaunchProfile resolvedProfile = await _tokenReplacer.ReplaceTokensInProfileAsync(activeProfile); DebugLaunchSettings consoleTarget = await GetConsoleTargetForProfile(resolvedProfile, launchOptions, validateSettings); launchSettings.Add(consoleTarget); return(launchSettings.ToArray()); }
internal static bool IsSnapshotDebuggerProfile(this ILaunchProfile launchProfile) { return(StringComparer.OrdinalIgnoreCase.Equals(launchProfile?.CommandName, LaunchProfileInitializer.LaunchProfileCommandName)); }