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

NSIS-style update for all platforms (100% non-Squirrel) #1728

Closed
p120ph37 opened this issue Jun 22, 2017 · 11 comments
Closed

NSIS-style update for all platforms (100% non-Squirrel) #1728

p120ph37 opened this issue Jun 22, 2017 · 11 comments

Comments

@p120ph37
Copy link
Contributor

p120ph37 commented Jun 22, 2017

  • Version: 19.6.0
  • Target: nsis, pkg, appImage

The NSIS update mechanism is accomplished by simply downloading the installer, launching it, and quitting. (possibly using elevate.exe to request permissions if needed, though if installed per-user this is generally not necessary). When using the NSIS one-click installer, this is completely seamless for the user, and the new app starts up automatically after the update has finished. This also allows updates and initial-installs to use the same installer artifact, simplifying the build and hosting.

It would be nice to have this same functionality available for Mac and Linux platforms, where the installer artifact is also the update artifact, and no Squirrel trickery or .zip file is needed.

For MacOS:
The pkg target can provide a fairly streamlined installer, much like nsis, but by default it installs for all-users (this can now be adjusted per #1685 !), does not auto-start the app after install, and does require some user interaction with the UI during install. The app-auto-start can be accomplished by adding the following postinstall script:

#!/bin/bash
# Try to find installer PID so as to be able to wait for it to close.
INSTALLER_PID=`/usr/sbin/lsof -cInstaller | grep "$1" | head -1 | cut -d' ' -f2`
( # do the following without blocking the installer
    # Wait until the installer's PID is no longer present.
    while ps "$INSTALLER_PID" >/dev/null 2>&1; do sleep 0.1; done
    # Launch the app.
    /bin/launchctl asuser `id -u "$USER"` /usr/bin/open -b "$INSTALL_PKG_SESSION_ID"
) & disown $!
exit 0

And a non-interactive update-install can be launched with the following commands (it may be advisable to detect if the current app is writable by the current user, and launch the GUI installer instead if elevation is going to be needed):

electron.app.relaunch({execPath: '/usr/sbin/installer', args: [
    '-package', updateFile,
    '-target', 'CurrentUserHomeDirectory',
]);
electron.app.quit();

For Linux:
The appImage target can provide a streamlined Linux install without admin permission required. For updating an appImage installation, the following command will work if the user has permission to overwrite the exsiting file (again, it may be advisable to detect permissions and use gksudo for elevation of the cp if necessary):

var currentFile = process.env.APPIMAGE;
var updateFileEsc = updateFile.replace(/'/g, '\'\\\'\'');
var currentFileEsc = currentFile.replace(/'/g, '\'\\\'\'');
var cmd = `cp '${updateFileEsc}' '${currentFileEsc}';( exec '${currentFileEsc}' ) & disown $!`;
// relaunch won't work - see: #1727...
//electron.app.relaunch({execPath: '/bin/bash', args: ['-c', cmd]});
// ...using spawn and some bash magic instead for now.
child_process.spawn('/bin/bash', ['-c',`while ps ${process.pid} >/dev/null 2>&1; do sleep 0.1; done; ${cmd}`], {detached: true});
electron.app.quit();

(Note: due to #1727, electron.app.relaunch cannot be used to launch the update process)

You may or may not want to take this approach in electron-updater, but I figured I should share since there are probably others who could make use of this technique too. I'm using it myself in a somewhat-non-standard updater scenario that is triggered programmatically rather than monitoring a feed automatically, so I'm not actually using the electron-updater package right now - just the artifacts generated by electron-builder.

Obviously this update mechanism is not as efficient as the delta-based updates that AppImageUpdate recommends, but it supports programmatic updates, non-sequential updates, and downgrades.

Also note that updating AppImages in this way can produce confusing filenames if the original AppImage filename included a version identifier - after the upgrade, the filename will remain the same, but the contents will be from the new version.

@develar
Copy link
Member

develar commented Jun 26, 2017

I am sorry, but "Moved to backlog to keep issue list clear."

Currently, Linux updates feature is postponed, because there was donation from commercial company to implement differential update for Windows. Not in this month. But sounds goods, no doubt.

@p120ph37
Copy link
Contributor Author

That's fine. I have this implemented outside of electron-update for now. I just thought you might be interested in using this mechanism in the future.

@develar
Copy link
Member

develar commented Aug 22, 2017

Info for heroes (pkg target):

How is MacUpdater implemented now: native autoupdater is used under the hood. And native quitAndInstall is used.

It means, that you need to

  • rename MacUpdater to SquirrelMacUpdater
  • add new SimpleMacUpdater (replace Simple to some more correct name).
  • fix _load_autoUpdater function to select proper MacUpdater

In the new SimpleMacUpdater you need to do what NsisUpdater does. Currently, NsisUpdater extends AppUpdater, but some base class should be extracted (well, it can be done later by me, for simplicity and to avoid merge conflicts).

@coreybutler
Copy link

I'd just like to cast my vote for .pkg delta support in some manner. My app installation process requires creation of a shell file (my app has a GUI and CLI component) and several other small but important OS operations at the time of install/update. The DMG format simply doesn't support this on it's own.

@develar
Copy link
Member

develar commented Oct 19, 2017

It will be very easy when #2199 will be implemented.

But — some company decided to sponsor this feature but after some discussion offer was declined. Because even docker for Mac distributed as DMG. Do any required system tasks on app start. Do not think in terms of Windows world. Use electron sudo to elevate.

@coreybutler
Copy link

@develar - yes, issue #2199 was what led me here. You mentioned user demand, so I was just expressing my interest. If I were in a position to donate, I would (unfortunately I'm not). If I wind up with any spare time, I'll contribute the code myself.

I originally used sudo elevation, but it creates a poor experience for the end user. My users (about 50K of them) don't want to be prompted all the time when the install/update process can do it in a streamlined manner. It's also a better practice to isolate installer logic within the installer, as opposed to embedding everything in the Electron app.

Just because Docker uses a DMG doesn't really mean anything to me. My app isn't Docker. Using the "good enough for someone else logic" is a poor justification for doing something, but for those intent on following it, remember that Node.js uses a .pkg installer for macOS.

Anyhow, I'm not complaining... electron-builder has been helpful and I appreciate everything you've done. I run several OSS projects myself and know how demanding it is. I merely wanted to point out there's at least one user interested in a pkg implementation ;-)

@develar
Copy link
Member

develar commented Oct 20, 2017

remember that Node.js uses a .pkg installer for macOS

Because it is not app, but just installer ;) and for what if just brew install node :)

Our intention to help developers choose the right solution. If you think that pkg plays better for you — it is your choice. But unlikely this feature will be done without donation / PR.

Thanks for your comments.

@coreybutler
Copy link

Brew basically does the same thing a pkg installer does :-) A DMG is just a static disk image. Sometimes an app needs a real installation process, but I understand the gravity of how much work it will take to build a delta on a pkg based installer. Like I said, if I ever find enough time, I'll contribute the feature myself ;-)

@develar
Copy link
Member

develar commented Oct 20, 2017

Delta is not a problem — our app package builder handles any file. Problem for now only in a generic code to download and install pkg (in a way as our app Mage Wäsche recently done).

@p120ph37
Copy link
Contributor Author

p120ph37 commented Oct 20, 2017

So, are you saying that merging a variation of the technique that I described at the top of this thread into electron-builder according to the plan you outlined in #1728 (comment) would enable delta-updates via pkg?

@develar
Copy link
Member

develar commented Oct 20, 2017

@p120ph37 yes, your technique.

according to the plan you outlined in #1728 (comment)

This plan is not valid anymore since #2199 We are forced and must implement official multi-format Mac updater because of backward compatibility — old clients should be able to update. E.g. from old zip to new DMG. So, existing MacUpdater will be changed and existing meta update file will be changed to allow specify several available formats to update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants