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

Electron-builder's installer "safe directory" issue #6885

Closed
PerfectionVR opened this issue May 25, 2022 · 2 comments
Closed

Electron-builder's installer "safe directory" issue #6885

PerfectionVR opened this issue May 25, 2022 · 2 comments
Labels

Comments

@PerfectionVR
Copy link

PerfectionVR commented May 25, 2022

We’ve chosen to use electron-builder to create the installer because it’s easy to integrate. However, there is a small, mostly-inconsequential buglet concerning how it chooses its install directory.

By default, it’ll use the productName as its leaf install directory. So you get something like %PROGRAMFILES%/${productName}.
This is fine, unless you want to install somewhere else, like %SOMEPLACE%/foo. If that directory doesn’t exist yet, everything works fine. However, on the second install, it’ll install into %SOMEPLACE%/foo/${productName}. This is because electron-builder has an empty-directory check, which will append productName to the requested directory if the latter isn’t empty.

It shouldn’t just do an ‘empty’ check, but also see if this dir is the current install dir.

The reason I stumbled on this is that I’d prefer to have the directory be named “example-project”. This can be done by using productName="example-project", but then that also shows up in the text of the installer. I’d prefer that to be “Example Project”, but then the directories get weird.

For w use “example-project”, but we would like to know how this can be resolved.

Details:

node -v # v16.15.0
yarn -v # 1.22.15

Windows

package.json

{
  "name": "example-project",
  "description": "Example Project",
  "version": "0.0.1",
  "license": "MIT",
  "scripts": {
    "build:start": "node ./scripts/run-script",
    "build:clean": "rimraf .dist",
    "build:prepare": "node ./build.prepare.js",
    "build:main": "webpack --config webpack.config.main.js --mode=production",
    "build:renderer": "webpack --config webpack.config.renderer.js --mode=development",
    "build:main:dev": "webpack --watch --mode=development --config webpack.config.main.js",
    "build:renderer:dev": "webpack serve --port 3000 --mode=development --config webpack.config.renderer.js",
    "build:compile": "yarn electron-builder",
    "build": "yarn build:clean && npm-run-all --parallel build:prepare build:main build:renderer && yarn build:compile",
    "dev": "yarn build:clean && npm-run-all --parallel build:main:dev build:renderer:dev",
    "dev:start": "nodemon --watch ./.dist/www/index.js --exec electron ./.dist/www/index.js",
  },
  "dependencies": {
    "axios": "^0.27.2",
    "lodash": "^4.17.21",
    "mobx": "^6.5.0",
    "mobx-react": "^7.4.0",
    "mobx-utils": "^6.0.5",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
  },
  "devDependencies": {
    "electron": "^18.2.4",
    "electron-builder": "^23.0.3",
  }
}

electron-build.yml

appId: 'com.example.app'
artifactName: 'ExampleSetup.${ext}'
productName: 'example-project'
copyright: '${author} All rights reserved.'
directories:
  output: './.dist/app'
  app: './.dist/www'
extraResources:
  - ./icons/**/*
icon: './icons/icon.ico'
nsis:
  allowToChangeInstallationDirectory: true
  include: 'scripts/installer.nsh'
  oneClick: false
  perMachine: true
  runAfterFinish: false
  warningsAsErrors: false # off b/c RmTrailingSlash gives a warning
  # TODO? name the uninstaller "uninstall.exe", but can't find the option for it.

scripts/installer.nsh

!define ClientRegKey "SOFTWARE\Example\Client"
!define ProductRegKey "SOFTWARE\Example\Cloud GUI"

; SP[0] in/out	path
Function RmTrailingSlash
	ClearErrors
	Exch $R1 ; <path>
	Push $R2
	
	StrCpy $R2 "$R1" "" -1 ; R2 gets the last char
	StrCmp $R2 "\" 0 NoSlash ; check if last char is '\'
		StrCpy $R2 "$R1" -1 ; last char was '\', remove it
		Goto Done
	NoSlash:
		StrCpy $R2 $R1
	Done:
	
	Exch
	Pop $R1
	Exch $R2
FunctionEnd

!macro customHeader
	;Default installation folder. May be overwritten by .onInit
	InstallDir "$PROGRAMFILES\Example\example-project"

	; InstallDirRegKey is overwritten by main electron-builder script
	;InstallDirRegKey HKCU "${ProductRegKey}" ""
!macroend

!macro customInit
	; If ProductRegKey doesn't exist but ClientRegKey does, use that as install dir.
	ReadRegStr $0 HKCU "${ProductRegKey}" ""
	${If} "$0" == ""
		ReadRegStr $0 HKCU "${ClientRegKey}" ""
		${If} "$0" != ""
			Push $0
			Call RmTrailingSlash
			Pop $0
			StrCpy $INSTDIR "$0\example-project"
		${EndIf}
	${EndIf}
!macroend

!macro customInstall
	; Write installdir to Example registry. NOTE! This is not the key that the installer uses!
	WriteRegStr HKCU "${ProductRegKey}" "" "$INSTDIR"
!macroend

!macro customUninstall
	DeleteRegKey HKCU "${ProductRegKey}"
!macroend
@github-actions github-actions bot added the nsis label May 25, 2022
@burgil
Copy link

burgil commented Jun 5, 2022

Hey, maybe we can submit a pull request about it, do you need help making one? I'm unsure what exactly we need to do but maybe that will help:

You can also specify artifactName for each option there (it's stated in the docs in a hidden way somewhere deep)

# Windows Installer configuration - https://www.electron.build/configuration/nsis
nsis:
  artifactName: "${productName}-${version}-${arch}-win-installer.${ext}"
  oneClick: false
  perMachine: true
  allowToChangeInstallationDirectory: true

it works for dmg, nsis, win, linux, mac and on the root, idk what it does but yeah I have it configured for each one using something like so:

appId: 'com.example.app'
artifactName: 'ExampleSetup.${ext}' # copied that from you

# Linux configuration - https://www.electron.build/configuration/linux
linux:
  artifactName: "marktext-${arch}.${ext}"
# Windows configuration - https://www.electron.build/configuration/win
win:
  artifactName: "${productName}-${version}-${arch}-win-portable.${ext}"
# Windows Installer configuration - https://www.electron.build/configuration/nsis
nsis:
  artifactName: "${productName}-${version}-${arch}-win-installer.${ext}"
# Mac OS configuration - https://www.electron.build/configuration/mac
mac:
  artifactName: "${productName}-${version}-${arch}-macos-portable.${ext}"
# Mac OS Installer configuration - https://www.electron.build/configuration/dmg
dmg:
  artifactName: "${productName}-${version}-${arch}-macos-installer.${ext}"

idk good luck I'm just throwing wood into the fire

@burgil
Copy link

burgil commented Jun 6, 2022

Hey, I just found something during my research that might help, been looking for this issue, here we go:
image
Source:
https://www.electron.build/configuration/nsis

Edit: So that's basically needs to be inside build/installer.nsh

More info:
image

p2004a added a commit to p2004a/electron-builder that referenced this issue Apr 20, 2023
During the first program install when the selected directory doesn't
exist it's not enforced that path contains application name as
sub-folder. On subsequent installs e.g. on update, that condition is
enforces though, which creates a new installation in sub-folder.

This tries to address electron-userland#6885
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants