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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 7
0
        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"
            });
        }
Ejemplo n.º 8
0
 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));
     }
 }
Ejemplo n.º 9
0
        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));
        }
Ejemplo n.º 10
0
 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);
         }
     }));
 }
Ejemplo n.º 11
0
 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));
     }
 }
Ejemplo n.º 12
0
 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);
         }
     }));
 }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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);
            }
        }
Ejemplo n.º 15
0
        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());
Ejemplo n.º 17
0
 public Task <Status> PreperforCopy(InstallerContext context)
 => Task.FromResult <Status>(new Status.Success(null));
Ejemplo n.º 18
0
        /// <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);
            }
        }
Ejemplo n.º 19
0
        /// <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();
        }
Ejemplo n.º 20
0
 public string ToZipFile(InstallerContext context) => (string)context.SourceLocation;
Ejemplo n.º 21
0
        public override Task Prepare(InstallerContext context)
        {
            Content = "Update wird Extrahiert";

            return(Task.CompletedTask);
        }
Ejemplo n.º 22
0
        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()));
Ejemplo n.º 25
0
        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()));
Ejemplo n.º 28
0
        /// <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();
Ejemplo n.º 30
0
        /// <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);
            }
        }