Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Report installation messages to console #847

Merged
merged 22 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions constructor/nsis/main.nsi.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ FunctionEnd
/CheckPathLength=[0|1] [default: 1]$\n\
/? (show this help message)$\n\
/S (run in CLI/headless mode)$\n\
/Q (omit CLI logging)$\n\
/Q (quiet mode, do not print output to console)$\n\
/D=[installation directory] (must be last parameter)$\n"
# There seems to be a limit to how many chars per ${Print} we can pass.
# The message will get truncated silently, no errors.
Expand All @@ -307,7 +307,7 @@ FunctionEnd
is disabled (i.e. if /InstallationType=AllUsers, then$\n\
/AddToPath=1 will be ignored)."
Abort
${EndIf}
${EndIf}

ClearErrors
${GetOptions} $ARGV "/InstallationType=" $ARGV_InstallationType
Expand Down Expand Up @@ -743,6 +743,48 @@ Function .onInit
FunctionEnd

Function un.onInit
ClearErrors
${GetParameters} $ARGV
${GetOptions} $ARGV "/?" $ARGV_Help
${IfNot} ${Errors}
SetSilent silent
${Print} "\
Uninstalls ${NAME} ${VERSION}$\n\
$\n\
USAGE$\n\
-----$\n\
$\n\
Uninstall-${NAME}.exe [options]$\n\
$\n\
OPTIONS$\n\
-------$\n\
$\n\
/? (show this help message)$\n\
/S (run in CLI/headless mode)$\n\
/Q (quiet mode, do not print output to console)$\n\
/_?=[installation directory] (must be last parameter)$\n\
$\n\
EXAMPLES$\n\
--------$\n\
$\n\
Uninstall via CLI (no GUI) from C:\${NAME}$\n\
> cmd /C START /WAIT Uninstall-${NAME}.exe /S /_?=C:\${NAME}$\n\
$\n\
Closing in 10s..."
# Give it some time so users can read it the pop-up console
# The pop-up console happens because the uninstaller copies itself to
# a temporary location because actually running, so we can't get the parent
# console handle
Sleep 10000
Abort
${EndIf}

ClearErrors
${GetOptions} $ARGV "/Q" $ARGV_QuietMode
${IfNot} ${Errors}
StrCpy $QuietMode "1"
${EndIf}

Push $0
Push $1
Push $2
Expand Down Expand Up @@ -1441,6 +1483,14 @@ Section "Uninstall"
IntOp $0 $0 + 1
goto loop_py
endloop_py:

${Print} "Done!"
${If} ${Silent}
# give it some time so users can read the last lines
${Print} "Closing in 3s..."
Sleep 3000
${EndIf}

SectionEnd

!if '@SIGNTOOL_COMMAND@' != ''
Expand Down
88 changes: 53 additions & 35 deletions docs/source/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,65 +69,83 @@ Windows installers have the following CLI options available:
- `/RegisterPython=[0|1]`: Whether to register Python as default in the Windows registry. Defaults
to `1`. This is preferred to `AddToPath`.
- `/Q` (quiet): do not report to the console in headless mode. Only relevant when used with `/S`
(see below).
(see below). Also works for the uninstallers.

You can also supply [standard NSIS flags](https://nsis.sourceforge.io/Docs/Chapter3.html#installerusage), but only _after_ the ones mentioned above:

- `/NCRC`: disables the CRC check.
- `/S` (silent): runs the installer or uninstaller in headless mode. Installers created with
`constructor 3.10` or later will report information to the active console.
`constructor 3.10` or later will report information to the active console. Note that while the
installer output will be reported in the active console, the uninstaller output will happen in
a new console. See below for different invocation examples.
- `/D` (directory): sets the default installation directory. Note that even if the path contains
spaces, it must be the last parameter used in the command line and must not contain any quotes.
Only absolute paths are supported. The uninstaller uses `_?` instead of `/D`.

### Examples:

> Note that the NSIS installers will not write any output to the terminal. You will not see any
> output, even if the installation fails. You can check the Task Manager to see if the installer is
> running, or poll the installation directory to see if the installation has finished.
### Examples

Run the installer in silent mode:
Run the installer in headless mode:

```batch
> cmd.exe /c start /wait my_installer.exe /S
`````{tab-set}
````{tab-item} CMD
```pwsh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```pwsh
```batch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used pwsh on purpose here because the batch syntax highlighting didn't shown any colours at all.

cmd.exe /C start /wait my_installer.exe /S
```

Run the installer in silent mode and install to a custom path:

```batch
> cmd.exe /c start /wait my_installer.exe /InstallationType=AllUsers /AddToPath=1 /S /D=C:\Program Files\my_app
````
````{tab-item} PowerShell
```pwsh
Start-Process -FilePath .\my_installer.exe -ArgumentList "/S" -NoNewWindow -Wait
```
````
`````

Run the uninstaller in silent mode from its original location:
Run the installer in headless mode, for all users, adding to PATH and installing to a custom path:

```batch
> cmd.exe /c start /wait "C:\Program Files\my_app\uninstaller.exe" /S _?=C:\Program Files\my_app

`````{tab-set}
````{tab-item} CMD
```pwsh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```pwsh
```batch

cmd.exe /C start /wait my_installer.exe /InstallationType=AllUsers /AddToPath=1 /S /D=C:\Program Files\my_app
```
````
````{tab-item} PowerShell
```pwsh
Start-Process -FilePath .\my_installer.exe -ArgumentList "/InstallationType=AllUsers /AddToPath=1 /S /D=C:\Program Files\my_app" -NoNewWindow -Wait
```
````
`````

:::{admonition} Stream redirection in EXE installers
:class: info
Redirect the console output to a file named `log.txt`:

When run in `/S` mode, EXE installers will output some minimal info to the console when invoked
like this:

```batch
> cmd.exe /c start /wait my_installer.exe /S
`````{tab-set}
````{tab-item} CMD
```pwsh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```pwsh
```batch

my_installer.exe /S > log.txt
```

This call waits until the installer is done. However, stream redirection won't work like this:

```batch
> cmd.exe /c start /wait my_installer.exe /S > logs.txt
> Stream redirection only works if the installer is invoked directly. Unfortunately this means that the call won't block and the installer will run in the background. If you need to block on the call, you can poll `log.txt` until you find `Done!` or `:error:`. We strongly recommend the Powershell alternative instead.
````
````{tab-item} PowerShell
```pwsh
Start-Process -FilePath .\my_installer.exe -ArgumentList "/S" -NoNewWindow -Wait -RedirectStandardOutput log.txt
```
````
`````

Stream redirection does work as expected if run directly:
Run the uninstaller in headless mode from its original location:

```batch
> my_installer.exe /S > logs.txt
`````{tab-set}
````{tab-item} CMD
```pwsh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```pwsh
```batch

cmd.exe /C start /wait C:\Program Files\my_app\uninstaller.exe /S _?=C:\Program Files\my_app
```

Unfortunately, in this case the call won't block. You will have to poll the `logs.txt` file and block until finished (e.g. you find `Done!` or `:error:`).
:::
````
````{tab-item} PowerShell
```pwsh
Start-Process -FilePath C:\Program Files\my_app\uninstaller.exe -ArgumentList "/S _?=C:\Program Files\my_app" -NoNewWindow -Wait
```
````
`````

:::{admonition} EXE installers with file logging
:class: tip
Expand Down
Loading