/// <returns> /// If the profile does not exist, returns <see langword="null"/>. Otherwise, returns the value /// of the property if the property is not defined, or <see langword="null"/> otherwise. The /// standard properties are always considered to be defined. /// </returns> public async Task <string?> GetUnevaluatedPropertyValueAsync(string propertyName) { ILaunchSettings snapshot = await _launchSettingsProvider.WaitForFirstSnapshot(); ILaunchProfile?profile = snapshot.Profiles.FirstOrDefault(p => StringComparers.LaunchProfileNames.Equals(p.Name, _context.ItemName)); if (profile is null) { return(null); } return(propertyName switch { CommandNamePropertyName => profile.CommandName ?? string.Empty, ExecutablePathPropertyName => profile.ExecutablePath ?? string.Empty, CommandLineArgumentsPropertyName => profile.CommandLineArgs ?? string.Empty, WorkingDirectoryPropertyName => profile.WorkingDirectory ?? string.Empty, LaunchBrowserPropertyName => profile.LaunchBrowser ? "true" : "false", LaunchUrlPropertyName => profile.LaunchUrl ?? string.Empty, EnvironmentVariablesPropertyName => LaunchProfileEnvironmentVariableEncoding.Format(profile), _ => GetExtensionPropertyValue(propertyName, profile, snapshot.GlobalSettings) });
public Task AddOrUpdateGlobalSettingAsync(string settingName, object settingContent) { // Updates need to be sequenced return(_sequentialTaskQueue.ExecuteTask(async() => { ILaunchSettings currentSettings = await GetSnapshotThrowIfErrors(); ImmutableDictionary <string, object> globalSettings = ImmutableStringDictionary <object> .EmptyOrdinal; if (currentSettings.GlobalSettings.TryGetValue(settingName, out object currentValue)) { globalSettings = currentSettings.GlobalSettings.Remove(settingName); } else { globalSettings = currentSettings.GlobalSettings; } bool saveToDisk = !settingContent.IsInMemoryObject() || (currentValue != null && !currentValue.IsInMemoryObject()); var newSnapshot = new LaunchSettings(currentSettings.Profiles, globalSettings.Add(settingName, settingContent), currentSettings.ActiveProfile?.Name); await UpdateAndSaveSettingsInternalAsync(newSnapshot, saveToDisk); })); }
public WritableLaunchSettings(ILaunchSettings settings) { if (settings.Profiles != null) { foreach (ILaunchProfile profile in settings.Profiles) { Profiles.Add(new WritableLaunchProfile(profile)); } } // For global settings we want to make new copies of each entry so that the snapshot remains immutable. If the object implements // ICloneable that is used, otherwise, it is serialized back to json, and a new object rehydrated from that if (settings.GlobalSettings != null) { var jsonSerializerSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }; foreach ((string key, object value) in settings.GlobalSettings) { if (value is ICloneable cloneableObject) { GlobalSettings.Add(key, cloneableObject.Clone()); } else { string jsonString = JsonConvert.SerializeObject(value, Formatting.Indented, jsonSerializerSettings); object clonedObject = JsonConvert.DeserializeObject(jsonString, value.GetType()); GlobalSettings.Add(key, clonedObject); } } } if (settings.ActiveProfile != null) { ActiveProfile = Profiles.FirstOrDefault((profile) => LaunchProfile.IsSameProfileName(profile.Name, settings.ActiveProfile.Name)); } }
public override Task <string?> OnSetPropertyValueAsync(string unevaluatedPropertyValue, IProjectProperties defaultProperties, IReadOnlyDictionary <string, string>?dimensionalConditions = null) { _projectThreadingService.RunAndForget(async() => { ILaunchSettings launchSettings = await _launchSettingsProvider.WaitForFirstSnapshot(Timeout.Infinite); var writableLaunchSettings = launchSettings.ToWritableLaunchSettings(); var activeProfile = writableLaunchSettings.ActiveProfile; if (activeProfile != null) { UpdateActiveLaunchProfile(activeProfile, unevaluatedPropertyValue); await _launchSettingsProvider.UpdateAndSaveSettingsAsync(writableLaunchSettings.ToLaunchSettings()); } }, options: ForkOptions.HideLocks, unconfiguredProject: _project); // We've intercepted the "set" operation and redirected it to the launch settings. // Return "null" to indicate that the value should _not_ be set in the project file // as well. return(Task.FromResult <string?>(null)); }
private async Task <string> GetPropertyValueAsync() { ILaunchSettings launchSettings = await _launchSettingsProvider.WaitForFirstSnapshot(); string?commandName = launchSettings.ActiveProfile?.CommandName; if (commandName == null) { return(string.Empty); } ConfiguredProject?configuredProject = await _project.GetSuggestedConfiguredProjectAsync(); IPropertyPagesCatalogProvider?catalogProvider = configuredProject?.Services.PropertyPagesCatalog; if (catalogProvider == null) { return(string.Empty); } IPropertyPagesCatalog catalog = await catalogProvider.GetCatalogAsync(PropertyPageContexts.Project); foreach (string schemaName in catalog.GetPropertyPagesSchemas()) { Rule?rule = catalog.GetSchema(schemaName); if (rule != null && string.Equals(rule.PageTemplate, "CommandNameBasedDebugger", StringComparison.OrdinalIgnoreCase) && rule.Metadata.TryGetValue("CommandName", out object pageCommandNameObj) && pageCommandNameObj is string pageCommandName && pageCommandName.Equals(commandName)) { return(schemaName); } } return(string.Empty); }
/// <summary> /// Re-applies in-memory profiles to the newly created snapshot. Note that we don't want to merge in the error /// profile /// </summary> protected void MergeExistingInMemoryProfiles(LaunchSettingsData newSnapshot, ILaunchSettings prevSnapshot) { for (int i = 0; i < prevSnapshot.Profiles.Count; i++) { var profile = prevSnapshot.Profiles[i]; if (profile.IsInMemoryObject() && !string.Equals(profile.CommandName, ErrorProfileCommandName)) { // Does it already have one with this name? if (newSnapshot.Profiles.FirstOrDefault(p => LaunchProfile.IsSameProfileName(p.Name, profile.Name)) == null) { // Create a new one from the existing in-memory profile and insert it in the same location, or the end if it // is beyond the end of the list if (i > newSnapshot.Profiles.Count) { newSnapshot.Profiles.Add(LaunchProfileData.FromILaunchProfile(profile)); } else { newSnapshot.Profiles.Insert(i, LaunchProfileData.FromILaunchProfile(profile)); } } } } }
/// <summary> /// Saves the launch settings to the launch settings file. Adds an errorstring and throws if an exception. Note /// that the caller is responsible for checking out the file /// </summary> protected async Task SaveSettingsToDiskAsync(ILaunchSettings newSettings) { // Clear stale errors since we are saving ClearErrors(); var serializationData = GetSettingsToSerialize(newSettings); string fileName = await _launchSettingsFilePath.GetValueAsync() .ConfigureAwait(false); try { await EnsureSettingsFolderAsync().ConfigureAwait(false); // We don't want to write null values. We want to keep the file as small as possible JsonSerializerSettings settings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }; string jsonString = JsonConvert.SerializeObject(serializationData, Formatting.Indented, settings); IgnoreFileChanges = true; FileManager.WriteAllText(fileName, jsonString); // Update the last write time LastSettingsFileSyncTime = FileManager.LastFileWriteTime(fileName); } catch (Exception ex) { string err = string.Format(Resources.ErrorWritingDebugSettings, fileName, ex.Message); LogError(err, false); throw; } finally { IgnoreFileChanges = false; } }
/// <summary> /// Retrieves the property specified by <paramref name="propertyName"/> from the /// given <see cref="ILaunchSettings"/>. /// </summary> /// <returns> /// The value of the property if it is found in the <paramref name="launchSettings"/>; /// otherwise a default value or <see langword="null"/> if there is no applicable default. /// </returns> /// <exception cref="InvalidOperationException"> /// Thrown if the given <paramref name="propertyName"/> is not known (that is, it is /// not declared in the implementor's <see cref="ExportInterceptingPropertyValueProviderAttribute"/>). /// </exception> public abstract string?GetPropertyValue(string propertyName, ILaunchSettings launchSettings);
private async Task <string> GetPropertyValueAsync() { ILaunchSettings launchSettings = await _launchSettingsProvider.WaitForFirstSnapshot(Timeout.Infinite); return(GetValueFromLaunchSettings(launchSettings.ActiveProfile)); }
public static IWritableLaunchSettings ToWritableLaunchSettings(this ILaunchSettings curSettings) { return(new WritableLaunchSettings(curSettings)); }
public Task UpdateAndSaveSettingsInternalAsyncTest(ILaunchSettings curSettings, bool persistToDisk) { return(UpdateAndSaveSettingsInternalAsync(curSettings, persistToDisk)); }
protected static void MergeExistingInMemoryGlobalSettings(LaunchSettingsData newSnapshot, ILaunchSettings prevSnapshot) { if (prevSnapshot.GlobalSettings != null) { foreach ((string key, object value) in prevSnapshot.GlobalSettings) { if (value.IsInMemoryObject()) { if (newSnapshot.OtherSettings == null) { newSnapshot.OtherSettings = new Dictionary <string, object> { [key] = value }; } else if (!newSnapshot.OtherSettings.TryGetValue(key, out _)) { newSnapshot.OtherSettings[key] = value; } } } } }
public Task SaveSettingsToDiskAsyncTest(ILaunchSettings curSettings) { return(SaveSettingsToDiskAsync(curSettings)); }
internal virtual void InitializeDebugTargetsCore(ILaunchSettings profiles) { IWritableLaunchSettings newSettings = profiles.ToWritableLaunchSettings(); // Since this get's reentered if the user saves or the user switches active profiles. if (CurrentLaunchSettings != null && !CurrentLaunchSettings.SettingsDiffer(newSettings)) { return; } try { // This should never change the dirty state when loading the dialog PushIgnoreEvents(); // Remember the current selection string curProfileName = SelectedDebugProfile?.Name; // Update the set of settings and generate a property change so the list of profiles gets updated. Note that we always // clear the active profile on the CurrentLaunchSettings so that when we do set one and property changed event is set CurrentLaunchSettings = newSettings; CurrentLaunchSettings.ActiveProfile = null; // Reload the launch profiles collection LaunchProfiles.Clear(); foreach (IWritableLaunchProfile profile in CurrentLaunchSettings.Profiles) { LaunchProfiles.Add(profile); } // When loading new profiles we need to clear the launch type. This is so the external changes cause the current // active provider to be refreshed _selectedLaunchType = null; NotifyProfileCollectionChanged(); // If we have a selection, we want to leave it as is if (curProfileName == null || newSettings.Profiles.Find(p => LaunchProfile.IsSameProfileName(p.Name, curProfileName)) == null) { // Note that we have to be careful since the collection can be empty. if (profiles.ActiveProfile != null && !string.IsNullOrEmpty(profiles.ActiveProfile.Name)) { SelectedDebugProfile = LaunchProfiles.Single(p => LaunchProfile.IsSameProfileName(p.Name, profiles.ActiveProfile.Name)); } else { if (LaunchProfiles.Count > 0) { SelectedDebugProfile = LaunchProfiles[0]; } else { SetEnvironmentGrid(null); } } } else { SelectedDebugProfile = LaunchProfiles.Single(p => LaunchProfile.IsSameProfileName(p.Name, curProfileName)); } } finally { PopIgnoreEvents(); _firstSnapshotCompleteSource?.TrySetResult(); _debugTargetsCoreInitialized = true; } }
/// <summary> /// Handles the core logic of retrieving the property. /// </summary> /// <remarks> /// Since we're redirecting the properties through the <see cref="ILaunchSettingsProvider"/> /// there's no distinction between "evaluated" and "unevaluated" properties, so /// we handle both in the same way. /// </remarks> private async Task <string> GetPropertyValueAsync() { ILaunchSettings launchSettings = await _launchSettings.WaitForFirstSnapshot(); return(launchSettings.ActiveProfile?.Name ?? string.Empty); }
public void SaveSettingsToDiskTest(ILaunchSettings curSettings) { SaveSettingsToDisk(curSettings); }
private async Task <string> GetPropertyValueAsync(string propertyName) { ILaunchSettings launchSettings = await _launchSettingsProvider.WaitForFirstSnapshot(Timeout.Infinite); return(GetPropertyValue(propertyName, launchSettings) ?? string.Empty); }
public WorkItemTracker(IAzureService azureService, ILaunchSettings launchSettings) { this.azureService = azureService; this.launchSettings = launchSettings; }
/// <summary> /// Called whenever the debug targets change. Note that after a save this function will be /// called. It looks for changes and applies them to the UI as needed. Switching profiles /// will also cause this to change as the active profile is stored in profiles snaphost. /// </summary> internal virtual void InitializeDebugTargetsCore(ILaunchSettings profiles) { bool profilesChanged = true; bool IISSettingsChanged = true; // Since this get's reentered if the user saves or the user switches active profiles. if (DebugProfiles != null) { profilesChanged = profiles.ProfilesAreDifferent(DebugProfiles.Select(p => (ILaunchProfile)p).ToList()); if (!profilesChanged && !IISSettingsChanged) { return; } } try { // This should never change the dirty state PushIgnoreEvents(); if (profilesChanged) { // Remember the current selection string curProfileName = SelectedDebugProfile == null ? null : SelectedDebugProfile.Name; // Load debug profiles var debugProfiles = new ObservableCollection <LaunchProfile>(); foreach (var profile in profiles.Profiles) { // Don't show the dummy NoAction profile if (profile.CommandName != ProfileCommandNames.NoAction) { var newProfile = new LaunchProfile(profile); debugProfiles.Add(newProfile); } } DebugProfiles = debugProfiles; // If we have a selection, we want to leave it as is if (curProfileName == null || profiles.Profiles.FirstOrDefault(p => { return(LaunchProfile.IsSameProfileName(p.Name, curProfileName)); }) == null) { // Note that we have to be careful since the collection can be empty. if (!string.IsNullOrEmpty(profiles.ActiveProfile.Name)) { SelectedDebugProfile = DebugProfiles.Where((p) => LaunchProfile.IsSameProfileName(p.Name, profiles.ActiveProfile.Name)).Single(); } else { if (debugProfiles.Count > 0) { SelectedDebugProfile = debugProfiles[0]; } else { SetEnvironmentGrid(null); } } } else { SelectedDebugProfile = DebugProfiles.Where((p) => LaunchProfile.IsSameProfileName(p.Name, curProfileName)).Single(); } } } finally { PopIgnoreEvents(); } }
public TestAssembly(ILaunchSettings launchSettings) { this.assemblyPath = launchSettings.Arguments.AssemblyPath; this.testStrategy = launchSettings.Arguments.TestStratgey; }
// Wrappers to call protected members public void SetCurrentSnapshot(ILaunchSettings profiles) { CurrentSnapshot = profiles; }
/// <summary> /// Helper function to set the new snapshot and post the changes to consumers. /// </summary> protected void FinishUpdate(ILaunchSettings newSnapshot) { CurrentSnapshot = newSnapshot; _broadcastBlock?.Post(newSnapshot); }
protected async Task UpdateProfilesAsync(string activeProfile) { try { // If no active profile specified, try to get one if (activeProfile == null) { ProjectDebugger props = await _commonProjectServices.ActiveConfiguredProjectProperties.GetProjectDebuggerPropertiesAsync(); if (await props.ActiveDebugProfile.GetValueAsync() is IEnumValue activeProfileVal) { activeProfile = activeProfileVal.Name; } } LaunchSettingsData launchSettingData = await GetLaunchSettingsAsync(); // If there are no profiles, we will add a default profile to run the project. W/o it our debugger // won't be called on F5 and the user will see a poor error message if (launchSettingData.Profiles.Count == 0) { launchSettingData.Profiles.Add(new LaunchProfileData() { Name = Path.GetFileNameWithoutExtension(_commonProjectServices.Project.FullPath), CommandName = RunProjectCommandName }); } // If we have a previous snapshot merge in in-memory profiles ILaunchSettings prevSnapshot = CurrentSnapshot; if (prevSnapshot != null) { MergeExistingInMemoryProfiles(launchSettingData, prevSnapshot); MergeExistingInMemoryGlobalSettings(launchSettingData, prevSnapshot); } var newSnapshot = new LaunchSettings(launchSettingData, activeProfile); await FinishUpdateAsync(newSnapshot, ensureProfileProperty : true); } catch (Exception ex) { // Errors are added as error list entries. We don't want to throw out of here // However, if we have never created a snapshot it means there is some error in the file and we want // to have the user see that, so we add a dummy profile which will bind to an existing debugger which will // display the error when run if (CurrentSnapshot == null) { var errorProfile = new LaunchProfile() { Name = Resources.NoActionProfileName, CommandName = ErrorProfileCommandName, DoNotPersist = true }; errorProfile.OtherSettings = ImmutableStringDictionary <object> .EmptyOrdinal.Add("ErrorString", ex.Message); var snapshot = new LaunchSettings(new List <ILaunchProfile>() { errorProfile }, null, errorProfile.Name); await FinishUpdateAsync(snapshot, ensureProfileProperty : false); } } }
/// <summary> /// Re-applies in-memory global options to the newly created snapshot /// </summary> protected static void MergeExistingInMemoryGlobalSettings(LaunchSettingsData newSnapshot, ILaunchSettings prevSnapshot) { if (prevSnapshot.GlobalSettings != null) { foreach (KeyValuePair <string, object> kvp in prevSnapshot.GlobalSettings) { if (kvp.Value.IsInMemoryObject()) { if (newSnapshot.OtherSettings == null) { newSnapshot.OtherSettings = new Dictionary <string, object> { [kvp.Key] = kvp.Value }; } else if (!newSnapshot.OtherSettings.TryGetValue(kvp.Key, out object existingValue)) { newSnapshot.OtherSettings[kvp.Key] = kvp.Value; } } } } }
public Task UpdateAndSaveSettingsAsync(ILaunchSettings newSettings) { // Updates need to be sequenced. Do not call this version from within an ExecuteTask as it // will deadlock return(_sequentialTaskQueue.ExecuteTask(() => UpdateAndSaveSettingsInternalAsync(newSettings))); }
public Executor(ITestPlansController testPlansController, ITestAssembly testAssembly, ILaunchSettings launchSettings) { this.testPlansController = testPlansController; this.testAssembly = testAssembly; this.launchSettings = launchSettings; }