Electron-simple-updater supports appimage Linux Auto-updates, could this be ported to electron-builder?
Planned. There are a lot of more important issues.
Also check AppImageUpdate for binary delta updates (= users only download a few MB rather than the whole thing each time).
Do we an ETA for this ?
Probably this week (issues processed by user donations/requests/votes :)). But cannot promise anything.
Do you need help with this?
Is there any plan or work in progress?
I could help, but I don't want to duplicate work by not taking into account anything you may have already done.
+1 on the above, I'd be happy to help.
How can we help ? What is the plan ?
me too
Happy to help as well π·
Since there seems to be high demand for AppImage updates, I'd like to offer my help too.
Update information that is needed for binary delta updates is described in the spec at
https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information
Of course this could be implemented from scratch, but the easier route would probably be to just use appimagetool
which has all the needed capabilities already built in.
Since @develar wants to allow macOS and Windows users to generate Linux AppImages, a good first step would be to get appimagetool
and its dependencies like mksquashfs
and zsyncmake
compiled for those platforms. https://github.com/AppImage/AppImageKit/
Volunteers, anyone?
Again, happy to help (but I don't run macOS or Windows at the moment). If you have questions, AppImage developers are on #AppImage on irc.freenode.net.
By the way, if you are wondering what I mean by "binary delta updates", you can see it in action in this video:
Next week differential updates will be finished for NSIS and I will be free from obligations. So, I will do support auto updates for Linux, as all you waiting it for a long time.
To make clear β AppImage is awesome. It is not archaic delta updates as Squirrel.Windows support. No, no. It saves hours and hours of developer time (yes, I am tired to answer to WTF, what remote releases I should use?). It is differential update. As Appx format in the Windows Store.
It saves bytes for developer because no need to download old release to build block map for a new release. It is very important for CI servers (no previous cache).
It saves bytes for client, because block map for one release is fully applicable for any release. Full update will be never downloaded again.
It saves developer time β nothing is added to existing workflow. Nothing to test. Nothing to deploy.
Yes β Google uses delta updates for Chrome. But what is good for a big company is not always good for a generic use case and often doesn't work. You want to develop your app, not to be release engineer. That's why Microsoft uses differential updates instead of delta for Windows Store.
So, stay tuned. Differential update for Windows will be in one week, for Linux β September.
Didn't know that differential updates for UWP apps existed, but zsync (what powers AppImageUpdate) has been around forever and has been put to good use e.g., for Ubuntu ISOs for a long time.
@probonopd if I understand correctly, zsync builds blockmap for the whole zip file. Not for files in zip. As appx or our nsis does.
In the case of AppImage, it would build it for the whole AppImage = ISO9660 or squashfs file.
99% that auto-update for Linux will use official AppImage solution, but not NSIS like solution. Yes β it will be cool to use LZMA instead of ZIP for AppImage to reduce size (~50%, "30-70%"), but there is a key difference β Linux kernel natively and transparently supports ZIP and so, AppImage zip is not just an intermediate container to unpack (as for portable
windows target).
And we don't use zsync for NSIS, not only because lack of zsyncmake (https://github.com/salesforce/zsync4j β so, we can port it to node), but because AppX solution, I think, works better (we should operate by file, not the whole packed ZIP with lzma compression). Of course, AppX solution is just a variant of zsync idea (and our client will looks like as zsync client, but modify file not in the local file system, but file in the zip fs).
99% that auto-update for Linux will use official AppImage solution
You may be interested to hear that @teras has successfully built appimagetool
for macOS. See https://github.com/AppImage/AppImageKit/pull/466 which will be merged soon.
Status: Delta updates for Windows is ready to use (https://github.com/electron-userland/electron-builder/releases/tag/v19.28.4). But after my vacation (21 September) I will fix another issue (because donated and so, has higher priority) and finally will implement auto-updates for Linux.
Hi, what's up on this feature @develar?
Status: work started (task #832 is done).
cc @TheAssassin
I am going to use NSIS implementation of differential update instead of AppImage.
zsync-curl
approach is not suitable for electron-builder users. Exactly the same reason why our improved and fixed auto update on macOS was not implemented on Squirrel.Mac side β it is not suitable for Electron app users. Better to implement once for all platforms. And only, only low-level specific code should be implemented platform-specific.Problem for now, is that NSIS currently uses static slicing, instead of dynamic sized chunks based on hashed content (content defined chunking). It works ok if blockmap computed per-file, but not good in case of AppImage, where zsync applied to whole AppImage file. In any case I need to fix it for NSIS (because of huge Electron executable (80 MB, changed dramatically after code sign)).
Decision is not final, depends on experiment results (how good is our differential updating compared to zsync). Great news is that this feature received donation, and so, I will work on it exclusively :)
@develar Great to hear you're going full-throttle on this! I don't know enough about the technology involved to weigh in but I'm sure you'll make the right decisions! Keep up the good work!
@develar is there a description of how NSIS differential updates work? Do you think it might be possible and worthwhile to make NSIS differential updates an option officially supported in the AppImage standard? (Not promising anything, just trying to understand the pros and cons.)
Especially, how do NSIS differential updates know the URL to "update themselves" from?
And, does the application author have to specifically produce delta files from each version to each version or does it work similar to zsync where you don't have to do this?
how do NSIS differential updates know the URL to "update themselves" from?
Note: Bintray is not described in this overview, because not suitable for a lot of users due to unacceptable pricing and so, not fully supported and not recommended by electron-builder anymore.
electron-builder generates app-update.yml
as part of the app (resources/app-update.yml
).
There are several publish providers β Bintray, Generic, GitHub (maybe private), S3 and DigitalOcean Spaces.
For example, if you use GitHub:
owner: develar
repo: onshape-desktop-shell
provider: github
electron-builder generates and uploads update meta files. For generic
provider you need to upload files somehow.
For example, latest.yml
for Windows nsis-web
target (default nsis
target currently doesn't support differential update, but planned):
version: 1.0.1
releaseDate: '2017-10-09T06:41:39.325Z'
path: Test App ΓW Web Setup 1.0.1.exe
sha512: >-
CTmj9nrloxLX03YuHHRODw0DwN5HL41zD0CAqKYcgyXnXzJ106QNRmuyKN7HoDYKjfmec1gv3Vh0tNVEDHmdCg==
packages:
x64:
file: TestApp-1.0.1-x64.nsis.7z
size: 34454700
sha512: >-
SOBydGzu9nmMAK85T/kGAJGMgzHUJ+wLDhhW6CxCkfpujWolFKEKadkMMpi9jZ0VBtNvFHe59orzyBiFbhzI3w==
headerSize: 9982
blockMapSize: 13408
sha2: 9144ef58410cd6b2dd7fd0c4b9467e4cf2fc37d1bbb3155d6a4731f40ce7a975
Here
sha2
because of backward compatibility.sha512
is used to allow users to host updates on cheap HTTP instead of HTTPS (only update meta files must be served using HTTPS). Also, for package files, to ensure file integrity (if differential updater will produce incorrect file by error) and identity (because for blocks md5
is used).headerSize
- size of 7z archive header (to simplify updater, header is uncompressed (-mhc=off
))blockMapSize
- size of package file block map (it is like zsync control file).path
- The relative path (by default) or full URL (can be manually edited to use absolute URLs (e.g. if you decided to migrate from S3 to Spaces)) to installer/package file (one web installer automatically select appropriate arch).Block map data is appended to the end of 7z archive as raw deflate compressed data (deflate, because only this compression method is supported by NodeJS natively). So, no additional file. Block map contains checksums not for the whole distributable file, but per application file (LZMA2 compressed data, solid archive is not used). And currently, static slicing is used (as in the AppX, and it is bad), not content defined (as in the zsync).
latest.yml
- here latest
it is a channel name by default. If you publish 1.0.0-beta
, prerelease component will be used as channel name β beta.yml
will be generated/uploaded. You can also set generateUpdatesFilesForAllChannels
to true
and electron-builder will produce additional required channel files (e.g. for beta
also alpha
will be generated/uploaded, for latest
both alpha
and beta
).
electron-updater downloads latest.yml
(app-update.yml
is used to configure publish provider). Where latest
it is the channel name by default. Can be set to any other channel name (except GitHub, where prerelease concept is used instead).
For public GitHub atom feed is used to construct the channel file URL.
Update is downloaded and installed depends on current version, downgrade policy, channel (allowPrerelease
in case of GitHub) and staged rollouts (e.g. update will be not performed if user not belongs to confirmative bucket).
In short β NSIS differential update equals to zsync (again, currently, content defined chunking is not implemented, but will be β "depends on experiment results (how good is our differential updating compared to zsync").
So, as you can see, the only advantage of using zsync for us β content defined chunking. But in any case it should be implemented for NSIS, so it is not considered as "reinvent the wheel" :)
Also, and it is also important, our chunker understands the data. Block map computed per application file (7z format supported for now, in the future we can do the same for squashfs image). It is why initially NSIS chunked was implemented using static slicing :)
@develar Quick question: will this work for other distribution formats as well, like Debian packages?
@MaKleSoft AppX, Snap, Debian, rpm, pacman and so on are out of scope because you should use OS to update them. That's why AppImage is a default target β because it works on all Linux distro and updatable on all Linux too.
@develar Got it. Thanks for the quick response!
@develar are you going to write the entire updater code in JS to make it portable, or are you building something subprocess based (e.g., calling NSIS processes)? I'm not quite sure what you're building.
@TheAssassin electron-updater differential updater for Windows Web Installer is already implemented and works in production.
download full web-installer (~400 KB).
electron-updater (JS code) reconstruct package file in a 7z format:
n
lzma2 compressed blocks, where n
is a number of files) downloaded using differential update. Opposite to zsync, updater has blockmaps ("zsync control files") not only for the new package file (located in the end of file (7z format allows to put any data after header, the same, I hope, will allow AppImage (not yet investigated))), but for old too (on install, block map copied to installed app directory).and then simply calls downloaded installer (step 1) with --package-file=${packagePath}
The same will be implemented (if zsync will be not better (delta)) in case of AppImage (step 1 is missed, step 3 replaced to "integrate into system (new icons and so)").
Our CDC (content defined chunking) works ideally. In general, delta update size equals to n * dictSize
where n
it is a number of changed blocks (block size is equals to dict size). So, in case if NSIS, minimal delta size is 3-4 MB. Because of superb LZMA compression (https://github.com/electron-userland/electron-builder/releases/tag/v19.36.0).
For AppImage we don't use xz
compression. Because XZ is much worse than 7z. Under the hood both uses LZMA2, but... filters, filters, filters... XZ is bad not only in terms of compression quality, but in terms of compression speed too (it the reason why we never use it even for xz files (deb) and instead delegates to 7z).
And in any case problem is that decompression of xz is slow and it leads to slow startup of app. Not often noticeable. And definitely, we don't want to compromise AppImage. You still can set in the appImage
option compression
to maximum
(but please note β it doesn't make a lot of sense (only 1.5 MB in our tests)) β electron-builder doesn't restrict you to do so and doesn't check it at all β so, it is allowed to build one version with one compression and another version with another compression.
So, by default gzip compression is used. It is why Windows installer has size 34 MB, but Linux AppImage 52 MB. But because of that delta update size is very small β minimal ~100 KB.
File file has 10 changed blocks
Full: 51,738.34 KB, To download: 117.4 KB (0%)
Our one-click method autoUpdater.checkForUpdatesAndNotify()
now supports Linux.
So, would you say we shuold look into NSIS instead of zsync for AppImage in general?
electron-builder 19.37.0
electron-updater 2.12.0
Both versions are next
.
checkForUpdatesAndNotify
checks that APPIMAGE
env is set, otherwise warning printed. So, it is safe to call this method if other distributable formats are also used.
βFile fileβ in the log not a typo :) Just because the whole AppImage added to block map as file named βfileβ :)
AutoUpdater now works great with AppImage except for one minor thing - the downloaded AppImage needs to be manually made executable (using chmod a+x
). While this isn't a big deal, it could confuse non-savvy users. It would be nice if after copying the latest AppImage file it was made executable automatically.
It would be nice if after copying the latest AppImage file it was made executable automatically.
It is already executable. https://github.com/electron-userland/electron-builder/commit/247c18af95d165ebdb6c434f7765493a9ad6b4a7#diff-0bb16ebe6bbc7bee3f53626ef72f6660R114
I have checked updater manualyl, not only using integration tests. Please provide steps to reproduce and file new issue.
Hmmm... that's interesting. Not sure why but I got it working using the checkForUpdatesAndNotify()
method. Before I was using checkForUpdates()
and listening to update-downloaded
event. Now the only thing that remains is that the old file is not deleted/replaced. Do the name of the new AppImage has to be same as that of the old one
as in the code below? https://github.com/electron-userland/electron-builder/blob/247c18af95d165ebdb6c434f7765493a9ad6b4a7/packages/electron-updater/src/AppImageUpdater.ts#L105
Keep in mind β some breaking change may be done https://github.com/electron-userland/electron-builder/issues/2216
I'm not sure if this is the place for asking this.
I'm implementing all the events (update-available
, update-downloaded
and download-progress
, etc) to make the update process more friendly to my users.
I've made a progress bar which is working great on Windows with NSIS, but the event download-progress
is never emitted on AppImage.
Is it supposed to be working or this is the expected behavior?
Thanks!
Most helpful comment
Status: work started (task #832 is done).