private void Configure(object parameter) { // need a host in the visual tree for our dialog boxes, so it is passed as the parameter InstallationDialogs installationDialogs = new InstallationDialogs((IInputElement)parameter); // gather information about warnings and get consent to install anyway, if applicable List <StatusReportItem> items = new List <StatusReportItem>(); List <string> lines = new List <string>(); foreach (ViewportSetupFileViewModel model in CombinedMonitorSetup.Combined) { items.AddRange(GatherWarnings(model) .Where(i => i.Severity >= StatusReportItem.SeverityCode.Warning)); } if (items.Count > 0) { // need a header lines.Add("Problems will exist in the combined Monitor Setup 'Helios'"); lines.Add(""); } if (!Data.GenerateCombined) { IList <StatusReportItem> currentItems = GatherWarnings(CombinedMonitorSetup.CurrentViewportSetup) .Where(i => i.Severity >= StatusReportItem.SeverityCode.Warning) .ToList(); if (currentItems.Any()) { lines.Add("Problems will exist in the separate Monitor Setup for this Profile"); lines.Add(""); items.AddRange(currentItems); } } if (items.Any()) { string extraText = ""; if (items.Any(i => !i.Flags.HasFlag(StatusReportItem.StatusFlags.ConfigurationUpToDate))) { extraText = " The Monitor Setup may work but it will be considered out of date until you resolve these problems, so Profile Editor will continue to prompt you to generate it again."; } lines.Add($"You can generate the Monitor Setup anyway and just use it with those limitations.{extraText}"); // present InstallationPromptResult result = installationDialogs.DangerPrompt("Incomplete Monitor Setup", string.Join(Environment.NewLine, lines), items); if (result == InstallationPromptResult.Cancel) { // don't do it return; } } // install Data.Install(installationDialogs); }
public InstallationResult Install(IInstallationCallbacks2 callbacks) { ProfileManifest16 manifest = null; try { using (ZipArchive archive = ZipFile.Open(_archivePath, ZipArchiveMode.Read)) { ZipArchiveEntry manifestEntry = archive.Entries.FirstOrDefault(entry => entry.FullName.Equals(MANIFEST_PATH, StringComparison.CurrentCultureIgnoreCase)); if (manifestEntry != null) { manifest = LoadManifest(manifestEntry); if (manifest == null) { // this cannot happen because we would get a parse failure? maybe empty file? throw new Exception($"JSON manifest {MANIFEST_PATH} could not be parsed"); } // see if we are allowed to install this package if (!CheckVersionRequirements(manifest, out IList <StatusReportItem> problems)) { if (RunningVersion.IsDevelopmentPrototype || ConfigManager.SettingsManager.LoadSetting("ArchiveInstall", "VersionOverride", false)) { InstallationPromptResult result = callbacks.DangerPrompt($"{ArchivePath} Installation", "Installation requirements are not met. Do you want to install anyway?", problems); if (result == InstallationPromptResult.Cancel) { return(InstallationResult.Canceled); } } else { callbacks.Failure($"{ArchivePath} cannot be installed", "Installation requirements are not met", problems); return(InstallationResult.Canceled); } } // present welcome screen, if applicable if (!ShowWelcome(callbacks, manifest)) { callbacks.Failure($"{ArchivePath} installation canceled", "Installation canceled by user", new List <StatusReportItem>()); return(InstallationResult.Canceled); } // process selection and build exclusion list foreach (Choice choice in manifest.Choices) { // filter options based on version requirements List <StatusReportItem> details = new List <StatusReportItem>(); foreach (Option option in choice.Options) { if (!CheckVersionRequirements(option, out IList <StatusReportItem> optionDetails)) { // this option is not allowed details.AddRange(optionDetails); option.IsValid = false; option.ValidityNarrative = "Version requirements not met"; } } // check if we still have viable choices if (!choice.Options.Any()) { callbacks.Failure($"{ArchivePath} cannot be installed", "None of the options for a required choice are valid for your installation.", details); return(InstallationResult.Fatal); } // fix up dialog if not specified choice.Message = choice.Message ?? "The Profile Archive being installed contains multiple versions of some of its files. Please choose one version to install:"; // wait for response Option selected = PresentChoice(choice); // check if dialog closed or canceled if (selected == null) { return(InstallationResult.Canceled); } // process results if (selected?.PathExclusions != null) { foreach (string path in selected.PathExclusions) { _pathExclusions.Add(path); } } } } // first check if we have a whole lot of writable files, in which case ask the user if the overwrite strategy should be changed CheckForFirstArchiveInstall(archive); // now unpack everything IList <StatusReportItem> report = archive.Entries .Where(NotFilteredVerbose) .Select(Unpack) .Where(item => item != null) .ToList(); callbacks.Success($"Installed {ArchivePath}", $"Files were installed into {Anonymizer.Anonymize(ConfigManager.DocumentPath)}", report); } return(InstallationResult.Success); } catch (Exception ex) { callbacks.Failure($"Failed to install {ArchivePath}", $"Attempt to install Helios Profile from '{Anonymizer.Anonymize(_archivePath)}' failed", ReportException(ex)); return(InstallationResult.Fatal); } }
public InstallationResult Install(IInstallationCallbacks callbacks) { List <StatusReportItem> results = new List <StatusReportItem>(); bool failed = false; bool imprecise = false; // load patchExclusions from settings instead of caching them, so we don't have different code paths from elevated binary HashSet <string> patchExclusions = LoadPatchExclusions(); // simulate patches and collect any errors foreach (PatchApplication item in _destinations.Values) { if (!item.Enabled) { continue; } item.PatchExclusions = patchExclusions; foreach (StatusReportItem result in item.Patches.SimulateApply(item.Destination, patchExclusions)) { result.Log(ConfigManager.LogManager); results.Add(result); if (result.Severity >= StatusReportItem.SeverityCode.Error) { failed = true; item.Status = StatusCodes.Incompatible; } if (result.Severity >= StatusReportItem.SeverityCode.Warning) { imprecise = true; } } } if (failed) { UpdateStatus(); callbacks.Failure($"{_patchSetDescription} installation would fail", "Some patches would fail to apply. No patches have been applied.", results); return(InstallationResult.Fatal); } if (imprecise) { InstallationPromptResult response = callbacks.DangerPrompt( $"{_patchSetDescription} installation may have risks", $"{_patchSetDescription} installation can continue, but some target files have changed since these patches were created.", results); if (response == InstallationPromptResult.Cancel) { return(InstallationResult.Canceled); } } // apply patches foreach (PatchApplication item in _destinations.Values) { if (!item.Enabled) { // destination is not selected for writing continue; } // apply patches directly or via elevated process, as appropriate IList <StatusReportItem> applyResults = item.UseRemote ? item.RemoteApply() : item.Apply(); foreach (StatusReportItem result in applyResults) { result.Log(ConfigManager.LogManager); results.Add(result); if (result.Severity >= StatusReportItem.SeverityCode.Error) { failed = true; } } } UpdateStatus(); if (failed) { // XXX need to revert any patches that were installed, if we can, and add to result report callbacks.Failure($"{_patchSetDescription} installation failed", "Some patches failed to be written", results); return(InstallationResult.Fatal); } if (Status != StatusCodes.UpToDate) { // installation completed, but not everything was done callbacks.Failure($"{_patchSetDescription} installation incomplete", "Not all patches were installed", results); return(InstallationResult.Canceled); } callbacks.Success($"{_patchSetDescription} installation success", "All patches installed successfully", results); return(InstallationResult.Success); }