public ServiceInstallerExecutor Create() { var configuration = new InstallerContext(_options.Assemblies); var executor = new ServiceInstallerExecutor(configuration, _options.Installers); return(executor); }
public override Task Prepare(InstallerContext context) { _nameSelectionModel = context.ServiceScope.ServiceProvider.GetRequiredService <NameSelectionModel>(); Content = context.ServiceScope.ServiceProvider.GetRequiredService <NameSelection>(); return(Task.CompletedTask); }
/// <summary>Get the possible game paths to update.</summary> /// <param name="toolkit">The mod toolkit.</param> /// <param name="context">The installer context.</param> private IEnumerable <DirectoryInfo> DetectGameFolders(ModToolkit toolkit, InstallerContext context) { HashSet <string> foundPaths = new HashSet <string>(); // game folder which contains the installer, if any { DirectoryInfo curPath = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; while (curPath?.Parent != null) // must be in a folder (not at the root) { if (context.LooksLikeGameFolder(curPath)) { foundPaths.Add(curPath.FullName); yield return(curPath); break; } curPath = curPath.Parent; } } // game paths detected by toolkit foreach (DirectoryInfo dir in toolkit.GetGameFolders()) { if (foundPaths.Add(dir.FullName)) { yield return(dir); } } }
public override Task <string> RunInstall(InstallerContext context) { var service = context.CreateRunningService(); using var diag = new OpenFileDialog { AutoUpgradeEnabled = true }; if (diag.ShowDialog(new Win32Proxy(_mainWindow)) != DialogResult.OK) { _logger.LogWarning($"{service.Name}: Update File not Selected"); return(Task.FromResult("Es wurde Keine Datei fürs Update gewählt.")); } var path = diag.FileName; try { var archive = new ZipArchive(new FileStream(path, FileMode.Open)); context.MetaData[MetaKeys.UpdateFile] = path; context.MetaData[MetaKeys.ArchiveFile] = archive; _zipArchive = archive; } catch { _logger.LogWarning($"{service.Name}: Error Open Update File"); return(Task.FromResult("Die Datei konnte nicht geöffnet werden")); } return(Task.FromResult <string>(null)); }
public override async Task <string> RunInstall(InstallerContext context) { var zip = context.PackageArchive; if (zip == null) { _logger.LogWarning($"{Path.GetFileName(context.PackagePath)} is no Zip File"); return("Datei ist keine Zip Datei"); } var name = GetName(zip); if (!string.IsNullOrWhiteSpace(name)) { _logger.LogInformation($"Service Name in AppSettings Found: {name}"); context.ServiceName = name; } else { _logger.LogInformation("Awaitng Name Selection"); await _nameSelectionModel.Wait(); name = _nameSelectionModel.NameText; } if (string.IsNullOrWhiteSpace(name)) { _logger.LogWarning("No Name Selected"); return("Kein korrekter name wurde angegeben"); } if (_serviceSettings.RunningServices.Select(rs => rs.Name).Contains(name)) { return("Name schon Vergeben"); } context.ServiceName = name; _logger.LogInformation($"{context.ServiceName}: Try Find Exe Name"); var exeName = GetExeName(context.PackageArchive); if (string.IsNullOrEmpty(exeName)) { _logger.LogInformation($"{context.ServiceName}: Search for Exe in Package"); exeName = context.PackageArchive.Entries.FirstOrDefault(e => e.Name.EndsWith(".exe"))?.FullName; if (string.IsNullOrEmpty(exeName)) { _logger.LogWarning($"{context.ServiceName}: No Exe Found"); return("Keine Ausfürbare Datei gefunden"); } } _logger.LogInformation($"{context.ServiceName}: Exe Found: {exeName}"); context.ExeName = exeName; return(null); }
public static IInstallationSource Select(InstallerContext context) { if (context.SourceLocation is string) { return(new LocalSource()); } return(EmptySource.Instnace); }
public override async Task Prepare(InstallerContext context) { var dispatcher = context.ServiceScope.ServiceProvider.GetRequiredService <Dispatcher>(); Content = await dispatcher.InvokeAsync(() => new TextBlock { TextAlignment = TextAlignment.Center, TextWrapping = TextWrapping.Wrap, Text = $"Daten werden für {context.ServiceName} Kopiert" }); }
public Status ValidateInput(InstallerContext context) { try { ZipFile.OpenRead((string)context.SourceLocation).Dispose(); return(new Status.Success(null)); } catch (Exception e) { return(new Status.Failure(e)); } }
public override Task <string> RunInstall(InstallerContext context) { if (!context.MetaData.TryGetTypedValue(MetaKeys.ArchiveFile, out ZipArchive zipArchive)) { return(Task.FromResult("Zip Erchive nicht gefunden")); } DeleteTemp(); zipArchive.ExtractToDirectory(_tempPath); context.MetaData[MetaKeys.TempLocation] = _tempPath; return(Task.FromResult <string>(null)); }
public Task <Status> CopyTo(InstallerContext context, string target) { return(Task.Run <Status>(() => { try { ZipFile.ExtractToDirectory((string)context.SourceLocation, target, context.Override); return new Status.Success(null); } catch (Exception e) { return new Status.Failure(e); } })); }
public Status ValidateInput(InstallerContext context) { try { if (ZipFile.CheckZip((string)context.SourceLocation)) { return(new Status.Success(null)); } return(new Status.Failure(new ZipException("Inconsistent Zip Dictionary"))); } catch (Exception e) { return(new Status.Failure(e)); } }
public Task <Status> CopyTo(InstallerContext context, string target) { return(Task.Run <Status>(() => { try { using var zip = ZipFile.Read((string)context.SourceLocation); zip.ExtractAll(target, ExtractExistingFileAction.OverwriteSilently); return new Status.Success(null); } catch (Exception e) { return new Status.Failure(e); } })); }
public override async Task <string> RunInstall(InstallerContext context) { Content = "Service wird Gestoppt..."; var service = context.CreateRunningService(); if (service.ServiceStade == ServiceStade.Running) { if (!await _processManager.Stop(service, 10_000)) { _logger.LogWarning($"{service.Name}: Stopping failed"); return("Das Stoppen des Services ist Fehlgeschlagen"); } } return(null); }
private async void InstallerWindow_OnLoaded(object sender, RoutedEventArgs e) { try { using var scope = _serviceScopeFactory.CreateScope(); var installerProcedure = scope.ServiceProvider.GetRequiredService <InstallerProcedure>(); if (Update) { installerProcedure.InitUpdate(scope.ServiceProvider); } else { installerProcedure.InitInstall(scope.ServiceProvider); } await _dispatcher.InvokeAsync(() => DataContext = installerProcedure); using var context = Update ? InstallerContext.CreateFrom(RunningService, scope) : new InstallerContext(scope, Path); await Task.Delay(2_000); var error = await installerProcedure.Install(context); Error = error; if (string.IsNullOrEmpty(error)) { await Dispatcher.InvokeAsync(() => DialogResult = true); RunningService = context.CreateRunningService(); } else { await Dispatcher.InvokeAsync(() => DialogResult = false); } } catch (Exception exception) { Error = exception.Message; await Dispatcher.InvokeAsync(() => DialogResult = false); } }
public override Task <string> RunInstall(InstallerContext context) { var path = Path.Combine("Apps", context.ServiceName).ToApplicationPath(); if (!Directory.Exists(path)) { _logger.LogInformation($"{context.ServiceName}: Create Service Directory"); Directory.CreateDirectory(path); } context.PackageArchive.ExtractToDirectory(path, true); _logger.LogInformation($"{context.ServiceName}: Extraction Compled"); context.InstalledPath = path; return(Task.FromResult <string>(null)); }
public Status ValidateInput(InstallerContext name) => new Status.Failure(new NotImplementedException());
public Task <Status> PreperforCopy(InstallerContext context) => Task.FromResult <Status>(new Status.Success(null));
/// <summary>Interactively locate the game install path to update.</summary> /// <param name="toolkit">The mod toolkit.</param> /// <param name="context">The installer context.</param> /// <param name="specifiedPath">The path specified as a command-line argument (if any), which should override automatic path detection.</param> private DirectoryInfo InteractivelyGetInstallPath(ModToolkit toolkit, InstallerContext context, string specifiedPath) { // use specified path if (specifiedPath != null) { var dir = new DirectoryInfo(specifiedPath); if (!dir.Exists) { this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't exist."); return(null); } if (!context.LooksLikeGameFolder(dir)) { this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't contain the Stardew Valley executable."); return(null); } return(dir); } // use game folder which contains the installer, if any { DirectoryInfo curPath = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; while (curPath?.Parent != null) // must be in a folder (not at the root) { if (context.LooksLikeGameFolder(curPath)) { return(curPath); } curPath = curPath.Parent; } } // use an installed path DirectoryInfo[] defaultPaths = toolkit.GetGameFolders().ToArray(); if (defaultPaths.Any()) { // only one path if (defaultPaths.Length == 1) { return(defaultPaths.First()); } // let user choose path Console.WriteLine(); this.PrintInfo("Found multiple copies of the game:"); for (int i = 0; i < defaultPaths.Length; i++) { this.PrintInfo($"[{i + 1}] {defaultPaths[i].FullName}"); } Console.WriteLine(); string[] validOptions = Enumerable.Range(1, defaultPaths.Length).Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray(); string choice = this.InteractivelyChoose("Where do you want to add/remove SMAPI? Type the number next to your choice, then press enter.", validOptions); int index = int.Parse(choice, CultureInfo.InvariantCulture) - 1; return(defaultPaths[index]); } // ask user this.PrintInfo("Oops, couldn't find the game automatically."); while (true) { // get path from user this.PrintInfo($"Type the file path to the game directory (the one containing '{context.ExecutableName}'), then press enter."); string path = Console.ReadLine()?.Trim(); if (string.IsNullOrWhiteSpace(path)) { this.PrintInfo(" You must specify a directory path to continue."); continue; } // normalize path path = context.IsWindows ? path.Replace("\"", "") // in Windows, quotes are used to escape spaces and aren't part of the file path : path.Replace("\\ ", " "); // in Linux/Mac, spaces in paths may be escaped if copied from the command line if (path.StartsWith("~/")) { string home = Environment.GetEnvironmentVariable("HOME") ?? Environment.GetEnvironmentVariable("USERPROFILE"); path = Path.Combine(home, path.Substring(2)); } // get directory if (File.Exists(path)) { path = Path.GetDirectoryName(path); } DirectoryInfo directory = new DirectoryInfo(path); // validate path if (!directory.Exists) { this.PrintInfo(" That directory doesn't seem to exist."); continue; } if (!context.LooksLikeGameFolder(directory)) { this.PrintInfo(" That directory doesn't contain a Stardew Valley executable."); continue; } // looks OK this.PrintInfo(" OK!"); return(directory); } }
/// <summary>Run the install or uninstall script.</summary> /// <param name="args">The command line arguments.</param> /// <remarks> /// Initialization flow: /// 1. Collect information (mainly OS and install path) and validate it. /// 2. Ask the user whether to install or uninstall. /// /// Uninstall logic: /// 1. On Linux/Mac: if a backup of the launcher exists, delete the launcher and restore the backup. /// 2. Delete all files and folders in the game directory matching one of the values returned by <see cref="GetUninstallPaths"/>. /// /// Install flow: /// 1. Run the uninstall flow. /// 2. Copy the SMAPI files from package/Windows or package/Mono into the game directory. /// 3. On Linux/Mac: back up the game launcher and replace it with the SMAPI launcher. (This isn't possible on Windows, so the user needs to configure it manually.) /// 4. Create the 'Mods' directory. /// 5. Copy the bundled mods into the 'Mods' directory (deleting any existing versions). /// 6. Move any mods from app data into game's mods directory. /// </remarks> public void Run(string[] args) { /********* ** Step 1: initial setup *********/ /**** ** Get basic info & set window title ****/ ModToolkit toolkit = new ModToolkit(); var context = new InstallerContext(); Console.Title = $"SMAPI {context.GetInstallerVersion()} installer on {context.Platform} {context.PlatformName}"; Console.WriteLine(); /**** ** Check if correct installer ****/ #if SMAPI_FOR_WINDOWS if (context.IsUnix) { this.PrintError($"This is the installer for Windows. Run the 'install on {context.Platform}.{(context.Platform == Platform.Mac ? "command" : "sh")}' file instead."); Console.ReadLine(); return; } #else if (context.IsWindows) { this.PrintError($"This is the installer for Linux/Mac. Run the 'install on Windows.exe' file instead."); Console.ReadLine(); return; } #endif /**** ** Check Windows dependencies ****/ if (context.IsWindows) { // .NET Framework 4.5+ if (!context.HasNetFramework45()) { this.PrintError(context.CanInstallLatestNetFramework() ? "Please install the latest version of .NET Framework before installing SMAPI." : "Please install .NET Framework 4.5 before installing SMAPI." ); this.PrintError("See the download page at https://www.microsoft.com/net/download/framework for details."); Console.ReadLine(); return; } if (!context.HasXna()) { this.PrintError("You don't seem to have XNA Framework installed. Please run the game at least once before installing SMAPI, so it can perform its first-time setup."); Console.ReadLine(); return; } } /**** ** read command-line arguments ****/ // get action from CLI bool installArg = args.Contains("--install"); bool uninstallArg = args.Contains("--uninstall"); if (installArg && uninstallArg) { this.PrintError("You can't specify both --install and --uninstall command-line flags."); Console.ReadLine(); return; } // get game path from CLI string gamePathArg = null; { int pathIndex = Array.LastIndexOf(args, "--game-path") + 1; if (pathIndex >= 1 && args.Length >= pathIndex) { gamePathArg = args[pathIndex]; } } /********* ** Step 2: choose a theme (can't auto-detect on Linux/Mac) *********/ MonitorColorScheme scheme = MonitorColorScheme.AutoDetect; if (context.IsUnix) { /**** ** print header ****/ this.PrintPlain("Hi there! I'll help you install or remove SMAPI. Just a few questions first."); this.PrintPlain("----------------------------------------------------------------------------"); Console.WriteLine(); /**** ** show theme selector ****/ // get theme writers var lightBackgroundWriter = new ColorfulConsoleWriter(context.Platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.LightBackground)); var darkBackgroundWriter = new ColorfulConsoleWriter(context.Platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.DarkBackground)); // print question this.PrintPlain("Which text looks more readable?"); Console.WriteLine(); Console.Write(" [1] "); lightBackgroundWriter.WriteLine("Dark text on light background", ConsoleLogLevel.Info); Console.Write(" [2] "); darkBackgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info); Console.WriteLine(); // handle choice string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" }); switch (choice) { case "1": scheme = MonitorColorScheme.LightBackground; this.ConsoleWriter = lightBackgroundWriter; break; case "2": scheme = MonitorColorScheme.DarkBackground; this.ConsoleWriter = darkBackgroundWriter; break; default: throw new InvalidOperationException($"Unexpected action key '{choice}'."); } } Console.Clear(); /********* ** Step 3: find game folder *********/ InstallerPaths paths; { /**** ** print header ****/ this.PrintInfo("Hi there! I'll help you install or remove SMAPI. Just a few questions first."); this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}"); this.PrintDebug("----------------------------------------------------------------------------"); Console.WriteLine(); /**** ** collect details ****/ // get game path this.PrintInfo("Where is your game folder?"); DirectoryInfo installDir = this.InteractivelyGetInstallPath(toolkit, context, gamePathArg); if (installDir == null) { this.PrintError("Failed finding your game path."); Console.ReadLine(); return; } // get folders DirectoryInfo bundleDir = new DirectoryInfo(this.BundlePath); paths = new InstallerPaths(bundleDir, installDir, context.ExecutableName); } Console.Clear(); /********* ** Step 4: validate assumptions *********/ if (!File.Exists(paths.ExecutablePath)) { this.PrintError("The detected game install path doesn't contain a Stardew Valley executable."); Console.ReadLine(); return; } /********* ** Step 5: ask what to do *********/ ScriptAction action; { /**** ** print header ****/ this.PrintInfo("Hi there! I'll help you install or remove SMAPI. Just one question first."); this.PrintDebug($"Game path: {paths.GamePath}"); this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}"); this.PrintDebug("----------------------------------------------------------------------------"); Console.WriteLine(); /**** ** ask what to do ****/ if (installArg) { action = ScriptAction.Install; } else if (uninstallArg) { action = ScriptAction.Uninstall; } else { this.PrintInfo("What do you want to do?"); Console.WriteLine(); this.PrintInfo("[1] Install SMAPI."); this.PrintInfo("[2] Uninstall SMAPI."); Console.WriteLine(); string choice = this.InteractivelyChoose("Type 1 or 2, then press enter.", new[] { "1", "2" }); switch (choice) { case "1": action = ScriptAction.Install; break; case "2": action = ScriptAction.Uninstall; break; default: throw new InvalidOperationException($"Unexpected action key '{choice}'."); } } } Console.Clear(); /********* ** Step 6: apply *********/ { /**** ** print header ****/ this.PrintInfo($"That's all I need! I'll {action.ToString().ToLower()} SMAPI now."); this.PrintDebug($"Game path: {paths.GamePath}"); this.PrintDebug($"Color scheme: {this.GetDisplayText(scheme)}"); this.PrintDebug("----------------------------------------------------------------------------"); Console.WriteLine(); /**** ** Back up user settings ****/ if (File.Exists(paths.ApiUserConfigPath)) { File.Copy(paths.ApiUserConfigPath, paths.BundleApiUserConfigPath); } /**** ** Always uninstall old files ****/ // restore game launcher if (context.IsUnix && File.Exists(paths.UnixBackupLauncherPath)) { this.PrintDebug("Removing SMAPI launcher..."); this.InteractivelyDelete(paths.UnixLauncherPath); File.Move(paths.UnixBackupLauncherPath, paths.UnixLauncherPath); } // remove old files string[] removePaths = this.GetUninstallPaths(paths.GameDir, paths.ModsDir) .Where(path => Directory.Exists(path) || File.Exists(path)) .ToArray(); if (removePaths.Any()) { this.PrintDebug(action == ScriptAction.Install ? "Removing previous SMAPI files..." : "Removing SMAPI files..."); foreach (string path in removePaths) { this.InteractivelyDelete(path); } } // move global save data folder (changed in 3.2) { string dataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley"); DirectoryInfo oldDir = new DirectoryInfo(Path.Combine(dataPath, "Saves", ".smapi")); DirectoryInfo newDir = new DirectoryInfo(Path.Combine(dataPath, ".smapi")); if (oldDir.Exists) { if (newDir.Exists) { this.InteractivelyDelete(oldDir.FullName); } else { oldDir.MoveTo(newDir.FullName); } } } /**** ** Install new files ****/ if (action == ScriptAction.Install) { // copy SMAPI files to game dir this.PrintDebug("Adding SMAPI files..."); foreach (FileSystemInfo sourceEntry in paths.BundleDir.EnumerateFileSystemInfos().Where(this.ShouldCopy)) { this.InteractivelyDelete(Path.Combine(paths.GameDir.FullName, sourceEntry.Name)); this.RecursiveCopy(sourceEntry, paths.GameDir); } // replace mod launcher (if possible) if (context.IsUnix) { this.PrintDebug("Safely replacing game launcher..."); // back up & remove current launcher if (File.Exists(paths.UnixLauncherPath)) { if (!File.Exists(paths.UnixBackupLauncherPath)) { File.Move(paths.UnixLauncherPath, paths.UnixBackupLauncherPath); } else { this.InteractivelyDelete(paths.UnixLauncherPath); } } // add new launcher File.Move(paths.UnixSmapiLauncherPath, paths.UnixLauncherPath); // mark file executable // (MSBuild doesn't keep permission flags for files zipped in a build task.) // (Note: exclude from Windows build because antivirus apps can flag the process start code as suspicious.) #if !SMAPI_FOR_WINDOWS new Process { StartInfo = new ProcessStartInfo { FileName = "chmod", Arguments = $"755 \"{paths.UnixLauncherPath}\"", CreateNoWindow = true } }.Start(); #endif } // create mods directory (if needed) if (!paths.ModsDir.Exists) { this.PrintDebug("Creating mods directory..."); paths.ModsDir.Create(); } // add or replace bundled mods DirectoryInfo bundledModsDir = new DirectoryInfo(Path.Combine(paths.BundlePath, "Mods")); if (bundledModsDir.Exists && bundledModsDir.EnumerateDirectories().Any()) { this.PrintDebug("Adding bundled mods..."); ModFolder[] targetMods = toolkit.GetModFolders(paths.ModsPath).ToArray(); foreach (ModFolder sourceMod in toolkit.GetModFolders(bundledModsDir.FullName)) { // validate source mod if (sourceMod.Manifest == null) { this.PrintWarning($" ignored invalid bundled mod {sourceMod.DisplayName}: {sourceMod.ManifestParseError}"); continue; } if (!this.BundledModIDs.Contains(sourceMod.Manifest.UniqueID)) { this.PrintWarning($" ignored unknown '{sourceMod.DisplayName}' mod in the installer folder. To add mods, put them here instead: {paths.ModsPath}"); continue; } // find target folder ModFolder targetMod = targetMods.FirstOrDefault(p => p.Manifest?.UniqueID?.Equals(sourceMod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase) == true); DirectoryInfo defaultTargetFolder = new DirectoryInfo(Path.Combine(paths.ModsPath, sourceMod.Directory.Name)); DirectoryInfo targetFolder = targetMod?.Directory ?? defaultTargetFolder; this.PrintDebug(targetFolder.FullName == defaultTargetFolder.FullName ? $" adding {sourceMod.Manifest.Name}..." : $" adding {sourceMod.Manifest.Name} to {Path.Combine(paths.ModsDir.Name, PathUtilities.GetRelativePath(paths.ModsPath, targetFolder.FullName))}..." ); // remove existing folder if (targetFolder.Exists) { this.InteractivelyDelete(targetFolder.FullName); } // copy files this.RecursiveCopy(sourceMod.Directory, paths.ModsDir, filter: this.ShouldCopy); } } // set SMAPI's color scheme if defined if (scheme != MonitorColorScheme.AutoDetect) { string text = File .ReadAllText(paths.ApiConfigPath) .Replace(@"""UseScheme"": ""AutoDetect""", $@"""UseScheme"": ""{scheme}"""); File.WriteAllText(paths.ApiConfigPath, text); } // remove obsolete appdata mods this.InteractivelyRemoveAppDataMods(paths.ModsDir, bundledModsDir); } } Console.WriteLine(); Console.WriteLine(); /********* ** Step 7: final instructions *********/ if (context.IsWindows) { if (action == ScriptAction.Install) { this.PrintSuccess("SMAPI is installed! If you use Steam, set your launch options to enable achievements (see smapi.io/install):"); this.PrintSuccess($" \"{Path.Combine(paths.GamePath, "StardewModdingAPI.exe")}\" %command%"); Console.WriteLine(); this.PrintSuccess("If you don't use Steam, launch StardewModdingAPI.exe in your game folder to play with mods."); } else { this.PrintSuccess("SMAPI is removed! If you configured Steam to launch SMAPI, don't forget to clear your launch options."); } } else { this.PrintSuccess(action == ScriptAction.Install ? "SMAPI is installed! Launch the game the same way as before to play with mods." : "SMAPI is removed! Launch the game the same way as before to play without mods." ); } Console.ReadKey(); }
public string ToZipFile(InstallerContext context) => (string)context.SourceLocation;
public override Task Prepare(InstallerContext context) { Content = "Update wird Extrahiert"; return(Task.CompletedTask); }
public override Task Rollback(InstallerContext context) { Directory.Delete(context.InstalledPath, true); return(Task.CompletedTask); }
public override Task Prepare(InstallerContext context) { Content = "Update Packet Wählen"; return(base.Prepare(context)); }
public Task <Status> PreperforCopy(InstallerContext context) => Task.FromResult <Status>(new Status.Failure(new NotImplementedException()));
public override Task Prepare(InstallerContext context) { Content = "Service wird Gestoppt..."; return(Task.CompletedTask); }
public void CleanUp(InstallerContext context) { }
public Task <Status> CopyTo(InstallerContext context, string target) => Task.FromResult <Status>(new Status.Failure(new NotImplementedException()));
/// <summary>Interactively locate the game install path to update.</summary> /// <param name="toolkit">The mod toolkit.</param> /// <param name="context">The installer context.</param> /// <param name="specifiedPath">The path specified as a command-line argument (if any), which should override automatic path detection.</param> private DirectoryInfo InteractivelyGetInstallPath(ModToolkit toolkit, InstallerContext context, string specifiedPath) { // use specified path if (specifiedPath != null) { string errorPrefix = $"You specified --game-path \"{specifiedPath}\", but"; var dir = new DirectoryInfo(specifiedPath); if (!dir.Exists) { this.PrintError($"{errorPrefix} that folder doesn't exist."); return(null); } switch (context.GetGameFolderType(dir)) { case GameFolderType.Valid: return(dir); case GameFolderType.Legacy154OrEarlier: this.PrintWarning($"{errorPrefix} that directory seems to have Stardew Valley 1.5.4 or earlier."); this.PrintWarning("Please update your game to the latest version to use SMAPI."); return(null); case GameFolderType.LegacyCompatibilityBranch: this.PrintWarning($"{errorPrefix} that directory seems to have the Stardew Valley legacy 'compatibility' branch."); this.PrintWarning("Unfortunately SMAPI is only compatible with the modern version of the game."); this.PrintWarning("Please update your game to the main branch to use SMAPI."); return(null); case GameFolderType.NoGameFound: this.PrintWarning($"{errorPrefix} that directory doesn't contain a Stardew Valley executable."); return(null); default: this.PrintWarning($"{errorPrefix} that directory doesn't seem to contain a valid game install."); return(null); } } // let user choose detected path DirectoryInfo[] defaultPaths = this.DetectGameFolders(toolkit, context).ToArray(); if (defaultPaths.Any()) { this.PrintInfo("Where do you want to add or remove SMAPI?"); Console.WriteLine(); for (int i = 0; i < defaultPaths.Length; i++) { this.PrintInfo($"[{i + 1}] {defaultPaths[i].FullName}"); } this.PrintInfo($"[{defaultPaths.Length + 1}] Enter a custom game path."); Console.WriteLine(); string[] validOptions = Enumerable.Range(1, defaultPaths.Length + 1).Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray(); string choice = this.InteractivelyChoose("Type the number next to your choice, then press enter.", validOptions); int index = int.Parse(choice, CultureInfo.InvariantCulture) - 1; if (index < defaultPaths.Length) { return(defaultPaths[index]); } } else { this.PrintInfo("Oops, couldn't find the game automatically."); } // let user enter manual path while (true) { // get path from user Console.WriteLine(); this.PrintInfo($"Type the file path to the game directory (the one containing '{Constants.GameDllName}'), then press enter."); string path = Console.ReadLine()?.Trim(); if (string.IsNullOrWhiteSpace(path)) { this.PrintWarning("You must specify a directory path to continue."); continue; } // normalize path path = context.IsWindows ? path.Replace("\"", "") // in Windows, quotes are used to escape spaces and aren't part of the file path : path.Replace("\\ ", " "); // in Linux/macOS, spaces in paths may be escaped if copied from the command line if (path.StartsWith("~/")) { string home = Environment.GetEnvironmentVariable("HOME") ?? Environment.GetEnvironmentVariable("USERPROFILE"); path = Path.Combine(home, path.Substring(2)); } // get directory if (File.Exists(path)) { path = Path.GetDirectoryName(path); } DirectoryInfo directory = new DirectoryInfo(path); // validate path if (!directory.Exists) { this.PrintWarning("That directory doesn't seem to exist."); continue; } switch (context.GetGameFolderType(directory)) { case GameFolderType.Valid: this.PrintInfo(" OK!"); return(directory); case GameFolderType.Legacy154OrEarlier: this.PrintWarning("That directory seems to have Stardew Valley 1.5.4 or earlier."); this.PrintWarning("Please update your game to the latest version to use SMAPI."); continue; case GameFolderType.LegacyCompatibilityBranch: this.PrintWarning("That directory seems to have the Stardew Valley legacy 'compatibility' branch."); this.PrintWarning("Unfortunately SMAPI is only compatible with the modern version of the game."); this.PrintWarning("Please update your game to the main branch to use SMAPI."); continue; case GameFolderType.NoGameFound: this.PrintWarning("That directory doesn't contain a Stardew Valley executable."); continue; default: this.PrintWarning("That directory doesn't seem to contain a valid game install."); continue; } } }
public string ToZipFile(InstallerContext context) => throw new NotImplementedException();
/// <summary>Interactively locate the game install path to update.</summary> /// <param name="toolkit">The mod toolkit.</param> /// <param name="context">The installer context.</param> /// <param name="specifiedPath">The path specified as a command-line argument (if any), which should override automatic path detection.</param> private DirectoryInfo InteractivelyGetInstallPath(ModToolkit toolkit, InstallerContext context, string specifiedPath) { // use specified path if (specifiedPath != null) { var dir = new DirectoryInfo(specifiedPath); if (!dir.Exists) { this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't exist."); return(null); } if (!context.LooksLikeGameFolder(dir)) { this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't contain the Secrets of Grindea executable."); return(null); } return(dir); } // let user choose detected path DirectoryInfo[] defaultPaths = this.DetectGameFolders(toolkit, context).ToArray(); if (defaultPaths.Any()) { this.PrintInfo("Where do you want to add or remove SoGMAPI?"); Console.WriteLine(); for (int i = 0; i < defaultPaths.Length; i++) { this.PrintInfo($"[{i + 1}] {defaultPaths[i].FullName}"); } this.PrintInfo($"[{defaultPaths.Length + 1}] Enter a custom game path."); Console.WriteLine(); string[] validOptions = Enumerable.Range(1, defaultPaths.Length + 1).Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray(); string choice = this.InteractivelyChoose("Type the number next to your choice, then press enter.", validOptions); int index = int.Parse(choice, CultureInfo.InvariantCulture) - 1; if (index < defaultPaths.Length) { return(defaultPaths[index]); } } else { this.PrintInfo("Oops, couldn't find the game automatically."); } // let user enter manual path while (true) { // get path from user Console.WriteLine(); this.PrintInfo($"Type the file path to the game directory (the one containing '{context.ExecutableName}'), then press enter."); string path = Console.ReadLine()?.Trim(); if (string.IsNullOrWhiteSpace(path)) { this.PrintWarning("You must specify a directory path to continue."); continue; } // normalize path path = context.IsWindows ? path.Replace("\"", "") // in Windows, quotes are used to escape spaces and aren't part of the file path : path.Replace("\\ ", " "); // in Linux/macOS, spaces in paths may be escaped if copied from the command line if (path.StartsWith("~/")) { string home = Environment.GetEnvironmentVariable("HOME") ?? Environment.GetEnvironmentVariable("USERPROFILE"); path = Path.Combine(home, path.Substring(2)); } // get directory if (File.Exists(path)) { path = Path.GetDirectoryName(path); } DirectoryInfo directory = new DirectoryInfo(path); // validate path if (!directory.Exists) { this.PrintWarning("That directory doesn't seem to exist."); continue; } if (!context.LooksLikeGameFolder(directory)) { this.PrintWarning("That directory doesn't contain a Secrets of Grindea executable."); continue; } // looks OK this.PrintInfo(" OK!"); return(directory); } }