Check for IDE update at startup (#797)

* Remove check for updates on startup setting

* Remove useless exported function

* Update template-package.json used to package IDE

* Add function to get channel file during packaging step

* Add updates check

* move ide updater on backend

* configure updater options

* add auto update preferences

* TMP check updates on start and download

* index on check-update-startup: fcb8f6e TMP check updates on start and download

* set version to skip on local storage

* add IDE setting to toggle update check on start-up

* comment out check for updates on startup and auto update settings

* Update Theia to 1.22.1

* updated CI

* download changelog and show it in IDE updater dialog

* remove useless file

* remove useless code

* add i18n to updater dialog

* fix i18n

* refactor UpdateInfo typing

* add macos zip to artifacts

* Simply use `--ignore-engines`

* Use correct --ignore-engines

* Fix semver#valid call

* Use C++17

* updated documentation

* add update channel preference

* update updater url

* updated documentation

* Fix the C++ version

* Build flag for cpp

* add disclaimer with correct node version

* Update `electron-builder`

* Fix `Electron.Menu` issue

* Skip electron rebuild

* Rebuild native dependencies beforehand

* Use resolutions section

* Update template-package.json as well

* move ide-updater to electron application

* refactor ide-updater service

* update yarn.lock

* update i18n

* Revert "Add gRPC user agent (#834)"

This reverts commit 5ab3a747a6.

* fix ide download url

* update latest file in CI

* fix i18n check

Co-authored-by: Silvano Cerza <silvanocerza@gmail.com>
Co-authored-by: Francesco Stasi <f.stasi@me.com>
Co-authored-by: Mark Sujew <msujew@yahoo.de>
This commit is contained in:
Alberto Iannaccone
2022-02-15 18:01:19 +01:00
committed by GitHub
parent 9ecff86bbe
commit f660058c75
30 changed files with 1915 additions and 346 deletions

View File

@@ -70,11 +70,11 @@ export abstract class GrpcClientProvider<C> {
protected abstract close(client: C): void;
protected get channelOptions(): Record<string, unknown> {
const pjson = require('../../package.json') || { "version": "0.0.0" }
const pjson = require('../../package.json') || { version: '0.0.0' };
return {
'grpc.max_send_message_length': 512 * 1024 * 1024,
'grpc.max_receive_message_length': 512 * 1024 * 1024,
'grpc.primary_user_agent': `arduino-ide/${pjson.version}`
'grpc.primary_user_agent': `arduino-ide/${pjson.version}`,
};
}
}

View File

@@ -0,0 +1,128 @@
import { injectable } from '@theia/core/shared/inversify';
import { UpdateInfo, CancellationToken, autoUpdater } from 'electron-updater';
import fetch, { Response } from 'node-fetch';
import { UpdateChannel } from '../../browser/arduino-preferences';
import {
IDEUpdater,
IDEUpdaterClient,
} from '../../common/protocol/ide-updater';
const CHANGELOG_BASE_URL = 'https://downloads.arduino.cc/arduino-ide/changelog';
const IDE_DOWNLOAD_BASE_URL = 'https://downloads.arduino.cc/arduino-ide';
@injectable()
export class IDEUpdaterImpl implements IDEUpdater {
private updater = autoUpdater;
private cancellationToken?: CancellationToken;
protected theiaFEClient?: IDEUpdaterClient;
protected clients: Array<IDEUpdaterClient> = [];
init(channel: UpdateChannel) {
this.updater.channel = channel;
this.updater.setFeedURL({
provider: 'generic',
url: `${IDE_DOWNLOAD_BASE_URL}/${
channel === UpdateChannel.Nightly ? 'nightly' : ''
}`,
channel,
});
this.updater.on('checking-for-update', (e) =>
this.clients.forEach((c) => c.notifyCheckingForUpdate(e))
);
this.updater.on('update-available', (e) =>
this.clients.forEach((c) => c.notifyUpdateAvailable(e))
);
this.updater.on('update-not-available', (e) =>
this.clients.forEach((c) => c.notifyUpdateNotAvailable(e))
);
this.updater.on('download-progress', (e) =>
this.clients.forEach((c) => c.notifyDownloadProgressChanged(e))
);
this.updater.on('update-downloaded', (e) =>
this.clients.forEach((c) => c.notifyDownloadFinished(e))
);
this.updater.on('error', (e) =>
this.clients.forEach((c) => c.notifyError(e))
);
}
setClient(client: IDEUpdaterClient | undefined): void {
if (client) this.clients.push(client);
}
async checkForUpdates(): Promise<UpdateInfo | void> {
const {
updateInfo,
cancellationToken,
} = await this.updater.checkForUpdates();
this.cancellationToken = cancellationToken;
if (
this.updater.currentVersion.compare(updateInfo.version) === -1 ||
true
) {
/*
'latest.txt' points to the latest changelog that has been generated by the CI,
so we need to make a first GET request to get the filename of the changelog
and a second GET to the actual changelog file
*/
try {
let response: Response | null = await fetch(
`${CHANGELOG_BASE_URL}/latest.txt`
);
const latestChangelogFileName = response.ok
? await response.text()
: null;
response = latestChangelogFileName
? await fetch(`${CHANGELOG_BASE_URL}/${latestChangelogFileName}`)
: null;
const changelog = response?.ok ? await response?.text() : null;
// We only want to see the release notes of newer versions
const currentVersionIndex = changelog?.indexOf(
`\r\n\r\n---\r\n\r\n## ${this.updater.currentVersion}\r\n\r\n`
);
const newChangelog =
currentVersionIndex && currentVersionIndex > 0
? changelog?.slice(0, currentVersionIndex)
: changelog;
updateInfo.releaseNotes = newChangelog;
} catch {
/*
if the request for the changelog fails, we'll just avoid to show it
to the user, but we will still show the update info
*/
}
return updateInfo;
}
}
async downloadUpdate(): Promise<void> {
try {
await this.updater.downloadUpdate(this.cancellationToken);
} catch (e) {
if (e.message === 'cancelled') return;
throw e;
}
}
stopDownload(): void {
this.cancellationToken?.cancel();
}
quitAndInstall(): void {
this.updater.quitAndInstall();
}
disconnectClient(client: IDEUpdaterClient): void {
const index = this.clients.indexOf(client);
if (index !== -1) {
this.clients.splice(index, 1);
}
}
dispose(): void {
this.clients.forEach(this.disconnectClient.bind(this));
}
}