rename `--headless` to `--no-prompt`, and parse with the other args

This commit is contained in:
Jesse Plamondon-Willard 2023-06-24 12:36:02 -04:00
parent 05695be390
commit 5196c3bad9
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
3 changed files with 51 additions and 53 deletions

View File

@ -32,7 +32,7 @@ argument | purpose
`--install` | Preselects the install action, skipping the prompt asking what the user wants to do. `--install` | Preselects the install action, skipping the prompt asking what the user wants to do.
`--uninstall` | Preselects the uninstall action, skipping the prompt asking what the user wants to do. `--uninstall` | Preselects the uninstall action, skipping the prompt asking what the user wants to do.
`--game-path "path"` | Specifies the full path to the folder containing the Stardew Valley executable, skipping automatic detection and any prompt to choose a path. If the path is not valid, the installer displays an error. `--game-path "path"` | Specifies the full path to the folder containing the Stardew Valley executable, skipping automatic detection and any prompt to choose a path. If the path is not valid, the installer displays an error.
`--headless` | Installs or Uninstalls SMAPI without any user interaction. Should only be used in scripts, tools or if you know what you're doing. `--no-prompt` | Don't let the installer wait for user input (e.g. for cases where it's being run by a script). If the installer is unable to continue without user input, it'll fail instead.
SMAPI itself recognises five arguments, but these are meant for internal use or testing, and might SMAPI itself recognises five arguments, but these are meant for internal use or testing, and might
change without warning. **On Linux/macOS**, command-line arguments won't work; see _environment change without warning. **On Linux/macOS**, command-line arguments won't work; see _environment

View File

@ -33,9 +33,6 @@ namespace StardewModdingApi.Installer
"SMAPI.ErrorHandler" "SMAPI.ErrorHandler"
}; };
/// <summary>If the installer should run headless, does not ask the user for any input when true.</summary>
private readonly bool Headless;
/// <summary>Get the absolute file or folder paths to remove when uninstalling SMAPI.</summary> /// <summary>Get the absolute file or folder paths to remove when uninstalling SMAPI.</summary>
/// <param name="installDir">The folder for Stardew Valley and SMAPI.</param> /// <param name="installDir">The folder for Stardew Valley and SMAPI.</param>
/// <param name="modsDir">The folder for SMAPI mods.</param> /// <param name="modsDir">The folder for SMAPI mods.</param>
@ -100,11 +97,10 @@ namespace StardewModdingApi.Installer
*********/ *********/
/// <summary>Construct an instance.</summary> /// <summary>Construct an instance.</summary>
/// <param name="bundlePath">The absolute path to the directory containing the files to copy into the game folder.</param> /// <param name="bundlePath">The absolute path to the directory containing the files to copy into the game folder.</param>
public InteractiveInstaller(string bundlePath, bool headless) public InteractiveInstaller(string bundlePath)
{ {
this.BundlePath = bundlePath; this.BundlePath = bundlePath;
this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform()); this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform());
this.Headless = headless;
} }
/// <summary>Run the install or uninstall script.</summary> /// <summary>Run the install or uninstall script.</summary>
@ -139,40 +135,24 @@ namespace StardewModdingApi.Installer
Console.Title = $"SMAPI {context.GetInstallerVersion()} installer on {context.Platform} {context.PlatformName}"; Console.Title = $"SMAPI {context.GetInstallerVersion()} installer on {context.Platform} {context.PlatformName}";
Console.WriteLine(); 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.");
this.AwaitConfirmation();
return;
}
#else
if (context.IsWindows)
{
this.PrintError($"This is the installer for Linux/macOS. Run the 'install on Windows.exe' file instead.");
this.AwaitConfirmation();
return;
}
#endif
/**** /****
** read command-line arguments ** read command-line arguments
****/ ****/
// get action from CLI // get input mode
bool allowUserInput = !args.Contains("--no-prompt");
// get action
bool installArg = args.Contains("--install"); bool installArg = args.Contains("--install");
bool uninstallArg = args.Contains("--uninstall"); bool uninstallArg = args.Contains("--uninstall");
if (installArg && uninstallArg) if (installArg && uninstallArg)
{ {
this.PrintError("You can't specify both --install and --uninstall command-line flags."); this.PrintError("You can't specify both --install and --uninstall command-line flags.");
this.AwaitConfirmation(); this.AwaitConfirmation(allowUserInput);
return; return;
} }
if (!installArg && !uninstallArg && Headless) if (!allowUserInput && !installArg && !uninstallArg)
{ {
this.PrintError("Either --install or --uninstall is required when running with --headless."); this.PrintError("You must specify --install or --uninstall when running with --no-prompt.");
return; return;
} }
@ -184,12 +164,31 @@ namespace StardewModdingApi.Installer
gamePathArg = args[pathIndex]; gamePathArg = args[pathIndex];
} }
/****
** 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.");
this.AwaitConfirmation(allowUserInput);
return;
}
#else
if (context.IsWindows)
{
this.PrintError($"This is the installer for Linux/macOS. Run the 'install on Windows.exe' file instead.");
this.AwaitConfirmation();
return;
}
#endif
/********* /*********
** Step 2: choose a theme (can't auto-detect on Linux/macOS) ** Step 2: choose a theme (can't auto-detect on Linux/macOS)
*********/ *********/
MonitorColorScheme scheme = MonitorColorScheme.AutoDetect; MonitorColorScheme scheme = MonitorColorScheme.AutoDetect;
if (context.IsUnix && !Headless) if (context.IsUnix && allowUserInput)
{ {
/**** /****
** print header ** print header
@ -254,7 +253,7 @@ namespace StardewModdingApi.Installer
if (installDir == null) if (installDir == null)
{ {
this.PrintError("Failed finding your game path."); this.PrintError("Failed finding your game path.");
this.AwaitConfirmation(); this.AwaitConfirmation(allowUserInput);
return; return;
} }
@ -271,7 +270,7 @@ namespace StardewModdingApi.Installer
if (!File.Exists(paths.GameDllPath)) if (!File.Exists(paths.GameDllPath))
{ {
this.PrintError("The detected game install path doesn't contain a Stardew Valley executable."); this.PrintError("The detected game install path doesn't contain a Stardew Valley executable.");
this.AwaitConfirmation(); this.AwaitConfirmation(allowUserInput);
return; return;
} }
Console.Clear(); Console.Clear();
@ -349,7 +348,7 @@ namespace StardewModdingApi.Installer
if (context.IsUnix && File.Exists(paths.BackupLaunchScriptPath)) if (context.IsUnix && File.Exists(paths.BackupLaunchScriptPath))
{ {
this.PrintDebug("Removing SMAPI launcher..."); this.PrintDebug("Removing SMAPI launcher...");
this.InteractivelyDelete(paths.VanillaLaunchScriptPath); this.InteractivelyDelete(paths.VanillaLaunchScriptPath, allowUserInput);
File.Move(paths.BackupLaunchScriptPath, paths.VanillaLaunchScriptPath); File.Move(paths.BackupLaunchScriptPath, paths.VanillaLaunchScriptPath);
} }
@ -361,7 +360,7 @@ namespace StardewModdingApi.Installer
{ {
this.PrintDebug(action == ScriptAction.Install ? "Removing previous SMAPI files..." : "Removing SMAPI files..."); this.PrintDebug(action == ScriptAction.Install ? "Removing previous SMAPI files..." : "Removing SMAPI files...");
foreach (string path in removePaths) foreach (string path in removePaths)
this.InteractivelyDelete(path); this.InteractivelyDelete(path, allowUserInput);
} }
// move global save data folder (changed in 3.2) // move global save data folder (changed in 3.2)
@ -373,7 +372,7 @@ namespace StardewModdingApi.Installer
if (oldDir.Exists) if (oldDir.Exists)
{ {
if (newDir.Exists) if (newDir.Exists)
this.InteractivelyDelete(oldDir.FullName); this.InteractivelyDelete(oldDir.FullName, allowUserInput);
else else
oldDir.MoveTo(newDir.FullName); oldDir.MoveTo(newDir.FullName);
} }
@ -388,7 +387,7 @@ namespace StardewModdingApi.Installer
this.PrintDebug("Adding SMAPI files..."); this.PrintDebug("Adding SMAPI files...");
foreach (FileSystemInfo sourceEntry in paths.BundleDir.EnumerateFileSystemInfos().Where(this.ShouldCopy)) foreach (FileSystemInfo sourceEntry in paths.BundleDir.EnumerateFileSystemInfos().Where(this.ShouldCopy))
{ {
this.InteractivelyDelete(Path.Combine(paths.GameDir.FullName, sourceEntry.Name)); this.InteractivelyDelete(Path.Combine(paths.GameDir.FullName, sourceEntry.Name), allowUserInput);
this.RecursiveCopy(sourceEntry, paths.GameDir); this.RecursiveCopy(sourceEntry, paths.GameDir);
} }
@ -403,7 +402,7 @@ namespace StardewModdingApi.Installer
if (!File.Exists(paths.BackupLaunchScriptPath)) if (!File.Exists(paths.BackupLaunchScriptPath))
File.Move(paths.VanillaLaunchScriptPath, paths.BackupLaunchScriptPath); File.Move(paths.VanillaLaunchScriptPath, paths.BackupLaunchScriptPath);
else else
this.InteractivelyDelete(paths.VanillaLaunchScriptPath); this.InteractivelyDelete(paths.VanillaLaunchScriptPath, allowUserInput);
} }
// add new launcher // add new launcher
@ -473,7 +472,7 @@ namespace StardewModdingApi.Installer
// remove existing folder // remove existing folder
if (targetFolder.Exists) if (targetFolder.Exists)
this.InteractivelyDelete(targetFolder.FullName); this.InteractivelyDelete(targetFolder.FullName, allowUserInput);
// copy files // copy files
this.RecursiveCopy(sourceMod.Directory, paths.ModsDir, filter: this.ShouldCopy); this.RecursiveCopy(sourceMod.Directory, paths.ModsDir, filter: this.ShouldCopy);
@ -491,7 +490,7 @@ namespace StardewModdingApi.Installer
#if SMAPI_DEPRECATED #if SMAPI_DEPRECATED
// remove obsolete appdata mods // remove obsolete appdata mods
this.InteractivelyRemoveAppDataMods(paths.ModsDir, bundledModsDir); this.InteractivelyRemoveAppDataMods(paths.ModsDir, bundledModsDir, allowUserInput);
#endif #endif
} }
} }
@ -522,7 +521,7 @@ namespace StardewModdingApi.Installer
); );
} }
this.AwaitConfirmation(); this.AwaitConfirmation(allowUserInput);
} }
@ -590,7 +589,8 @@ namespace StardewModdingApi.Installer
/// <summary>Interactively delete a file or folder path, and block until deletion completes.</summary> /// <summary>Interactively delete a file or folder path, and block until deletion completes.</summary>
/// <param name="path">The file or folder path.</param> /// <param name="path">The file or folder path.</param>
private void InteractivelyDelete(string path) /// <param name="allowUserInput">Whether the installer can ask for user input from the terminal.</param>
private void InteractivelyDelete(string path, bool allowUserInput)
{ {
while (true) while (true)
{ {
@ -603,7 +603,7 @@ namespace StardewModdingApi.Installer
{ {
this.PrintError($"Oops! The installer couldn't delete {path}: [{ex.GetType().Name}] {ex.Message}."); this.PrintError($"Oops! The installer couldn't delete {path}: [{ex.GetType().Name}] {ex.Message}.");
this.PrintError("Try rebooting your computer and then run the installer again. If that doesn't work, try deleting it yourself then press any key to retry."); this.PrintError("Try rebooting your computer and then run the installer again. If that doesn't work, try deleting it yourself then press any key to retry.");
this.AwaitConfirmation(); this.AwaitConfirmation(allowUserInput);
} }
} }
} }
@ -823,7 +823,8 @@ namespace StardewModdingApi.Installer
/// <summary>Interactively move mods out of the app data directory.</summary> /// <summary>Interactively move mods out of the app data directory.</summary>
/// <param name="properModsDir">The directory which should contain all mods.</param> /// <param name="properModsDir">The directory which should contain all mods.</param>
/// <param name="packagedModsDir">The installer directory containing packaged mods.</param> /// <param name="packagedModsDir">The installer directory containing packaged mods.</param>
private void InteractivelyRemoveAppDataMods(DirectoryInfo properModsDir, DirectoryInfo packagedModsDir) /// <param name="allowUserInput">Whether the installer can ask for user input from the terminal.</param>
private void InteractivelyRemoveAppDataMods(DirectoryInfo properModsDir, DirectoryInfo packagedModsDir, bool allowUserInput)
{ {
// get packaged mods to delete // get packaged mods to delete
string[] packagedModNames = packagedModsDir.GetDirectories().Select(p => p.Name).ToArray(); string[] packagedModNames = packagedModsDir.GetDirectories().Select(p => p.Name).ToArray();
@ -850,7 +851,7 @@ namespace StardewModdingApi.Installer
if (isDir && packagedModNames.Contains(entry.Name, StringComparer.OrdinalIgnoreCase)) if (isDir && packagedModNames.Contains(entry.Name, StringComparer.OrdinalIgnoreCase))
{ {
this.PrintDebug($" Deleting {entry.Name} because it's bundled into SMAPI..."); this.PrintDebug($" Deleting {entry.Name} because it's bundled into SMAPI...");
this.InteractivelyDelete(entry.FullName); this.InteractivelyDelete(entry.FullName, allowUserInput);
continue; continue;
} }
@ -916,13 +917,12 @@ namespace StardewModdingApi.Installer
}; };
} }
/// <summary>Await confirmation (pressing enter) from the User.</summary> /// <summary>Wait until the user presses enter to confirm, if user input is allowed.</summary>
private void AwaitConfirmation() /// <param name="allowUserInput">Whether the installer can ask for user input from the terminal.</param>
private void AwaitConfirmation(bool allowUserInput)
{ {
if (!this.Headless) if (allowUserInput)
{
Console.ReadLine(); Console.ReadLine();
}
} }
} }
} }

View File

@ -4,7 +4,6 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Linq;
namespace StardewModdingApi.Installer namespace StardewModdingApi.Installer
{ {
@ -48,9 +47,8 @@ namespace StardewModdingApi.Installer
// set up assembly resolution // set up assembly resolution
AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve; AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve;
var headless = args.Contains("--headless");
// launch installer // launch installer
var installer = new InteractiveInstaller(bundleDir.FullName, headless); var installer = new InteractiveInstaller(bundleDir.FullName);
try try
{ {