2021-05-14 11:29:06 +02:00
|
|
|
import shim from '@joplin/lib/shim';
|
2023-07-27 17:05:56 +02:00
|
|
|
import Logger from '@joplin/utils/Logger';
|
2021-05-14 11:29:06 +02:00
|
|
|
import { _ } from '@joplin/lib/locale';
|
|
|
|
import bridge from './services/bridge';
|
|
|
|
import KvStore from '@joplin/lib/services/KvStore';
|
2022-05-26 16:57:44 +02:00
|
|
|
import * as ArrayUtils from '@joplin/lib/ArrayUtils';
|
2023-07-12 16:18:05 +02:00
|
|
|
import { CheckForUpdateOptions, extractVersionInfo, GitHubRelease } from './utils/checkForUpdatesUtils';
|
2018-03-14 19:23:19 +02:00
|
|
|
const packageInfo = require('./packageInfo.js');
|
2023-09-27 01:01:52 +02:00
|
|
|
import { compareVersions } from 'compare-versions';
|
2018-01-31 00:35:50 +02:00
|
|
|
|
2021-05-14 11:29:06 +02:00
|
|
|
const logger = Logger.create('checkForUpdates');
|
|
|
|
|
2018-01-31 00:35:50 +02:00
|
|
|
let checkInBackground_ = false;
|
2018-02-16 01:05:04 +02:00
|
|
|
let isCheckingForUpdate_ = false;
|
2018-01-31 00:35:50 +02:00
|
|
|
|
2018-02-16 01:05:04 +02:00
|
|
|
function onCheckStarted() {
|
2021-05-14 11:29:06 +02:00
|
|
|
logger.info('Starting...');
|
2018-02-16 01:05:04 +02:00
|
|
|
isCheckingForUpdate_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCheckEnded() {
|
2021-05-14 11:29:06 +02:00
|
|
|
logger.info('Done.');
|
2018-02-16 01:05:04 +02:00
|
|
|
isCheckingForUpdate_ = false;
|
|
|
|
}
|
|
|
|
|
2023-08-18 13:46:34 +02:00
|
|
|
async function fetchLatestReleases() {
|
|
|
|
const response = await shim.fetch('https://objects.joplinusercontent.com/r/releases');
|
2021-05-04 15:53:44 +02:00
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
const responseText = await response.text();
|
2023-01-11 20:37:22 +02:00
|
|
|
throw new Error(`Cannot get latest release info: ${responseText.substr(0, 500)}`);
|
2021-05-04 15:53:44 +02:00
|
|
|
}
|
|
|
|
|
2023-07-12 16:18:05 +02:00
|
|
|
return (await response.json()) as GitHubRelease[];
|
2018-03-14 19:23:19 +02:00
|
|
|
}
|
2018-01-31 00:35:50 +02:00
|
|
|
|
2021-05-14 11:29:06 +02:00
|
|
|
function truncateText(text: string, length: number) {
|
2019-10-12 00:44:58 +02:00
|
|
|
let truncated = text.substring(0, length);
|
|
|
|
const lastNewLine = truncated.lastIndexOf('\n');
|
|
|
|
// Cut off at a line break unless we'd be cutting off half the text
|
|
|
|
if (lastNewLine > length / 2) {
|
|
|
|
truncated = `${truncated.substring(0, lastNewLine)}\n...`;
|
|
|
|
} else {
|
|
|
|
truncated = `${truncated.trim()}...`;
|
|
|
|
}
|
|
|
|
return truncated;
|
|
|
|
}
|
|
|
|
|
2021-05-14 11:29:06 +02:00
|
|
|
async function getSkippedVersions(): Promise<string[]> {
|
|
|
|
const r = await KvStore.instance().value<string>('updateCheck::skippedVersions');
|
|
|
|
return r ? JSON.parse(r) : [];
|
|
|
|
}
|
|
|
|
|
|
|
|
async function isSkippedVersion(v: string): Promise<boolean> {
|
|
|
|
const versions = await getSkippedVersions();
|
|
|
|
return versions.includes(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function addSkippedVersion(s: string) {
|
|
|
|
let versions = await getSkippedVersions();
|
|
|
|
versions.push(s);
|
|
|
|
versions = ArrayUtils.unique(versions);
|
|
|
|
await KvStore.instance().setValue('updateCheck::skippedVersions', JSON.stringify(versions));
|
|
|
|
}
|
|
|
|
|
|
|
|
export default async function checkForUpdates(inBackground: boolean, parentWindow: any, options: CheckForUpdateOptions) {
|
2018-02-16 01:05:04 +02:00
|
|
|
if (isCheckingForUpdate_) {
|
2021-05-14 11:29:06 +02:00
|
|
|
logger.info('Skipping check because it is already running');
|
2018-02-16 01:05:04 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
onCheckStarted();
|
|
|
|
|
2018-01-31 00:35:50 +02:00
|
|
|
checkInBackground_ = inBackground;
|
|
|
|
|
2021-05-14 11:29:06 +02:00
|
|
|
logger.info(`Checking with options ${JSON.stringify(options)}`);
|
|
|
|
|
|
|
|
try {
|
2023-08-18 13:46:34 +02:00
|
|
|
const releases = await fetchLatestReleases();
|
2023-08-06 13:57:26 +02:00
|
|
|
const release = extractVersionInfo(releases, process.platform, process.arch, shim.isPortable(), options);
|
2019-01-12 01:40:05 +02:00
|
|
|
|
2021-05-14 11:29:06 +02:00
|
|
|
logger.info(`Current version: ${packageInfo.version}`);
|
|
|
|
logger.info(`Latest version: ${release.version}`);
|
|
|
|
logger.info('Is Pre-release:', release.prerelease);
|
2018-05-14 13:18:00 +02:00
|
|
|
|
2018-03-14 19:23:19 +02:00
|
|
|
if (compareVersions(release.version, packageInfo.version) <= 0) {
|
2020-03-14 01:57:34 +02:00
|
|
|
if (!checkInBackground_) {
|
2021-05-14 11:29:06 +02:00
|
|
|
await bridge().showMessageBox(_('Current version is up-to-date.'));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const shouldSkip = checkInBackground_ && await isSkippedVersion(release.version);
|
|
|
|
|
|
|
|
if (shouldSkip) {
|
|
|
|
logger.info('Not displaying notification because version has been skipped');
|
|
|
|
} else {
|
|
|
|
const fullReleaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : '';
|
|
|
|
const MAX_RELEASE_NOTES_LENGTH = 1000;
|
|
|
|
const truncateReleaseNotes = fullReleaseNotes.length > MAX_RELEASE_NOTES_LENGTH;
|
|
|
|
const releaseNotes = truncateReleaseNotes ? truncateText(fullReleaseNotes, MAX_RELEASE_NOTES_LENGTH) : fullReleaseNotes;
|
|
|
|
|
|
|
|
const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version;
|
|
|
|
|
|
|
|
const buttonIndex = await bridge().showMessageBox(parentWindow, {
|
2020-03-14 01:57:34 +02:00
|
|
|
type: 'info',
|
2021-05-14 11:29:06 +02:00
|
|
|
message: `${_('An update is available, do you want to download it now?')}`,
|
|
|
|
detail: `${_('Your version: %s', packageInfo.version)}\n${_('New version: %s', newVersionString)}${releaseNotes}`,
|
|
|
|
buttons: [_('Download'), _('Skip this version'), _('Full changelog'), _('Cancel')],
|
|
|
|
cancelId: 3,
|
2020-03-14 01:57:34 +02:00
|
|
|
});
|
2021-05-14 11:29:06 +02:00
|
|
|
|
|
|
|
if (buttonIndex === 0) {
|
2021-12-28 15:17:59 +02:00
|
|
|
void bridge().openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl);
|
2021-05-14 11:29:06 +02:00
|
|
|
} else if (buttonIndex === 1) {
|
|
|
|
await addSkippedVersion(release.version);
|
|
|
|
} else if (buttonIndex === 2) {
|
2021-12-28 15:17:59 +02:00
|
|
|
void bridge().openExternal('https://joplinapp.org/changelog/');
|
2021-05-14 11:29:06 +02:00
|
|
|
}
|
2020-03-14 01:57:34 +02:00
|
|
|
}
|
2018-03-14 19:23:19 +02:00
|
|
|
}
|
2021-05-14 11:29:06 +02:00
|
|
|
} catch (error) {
|
|
|
|
logger.error(error);
|
|
|
|
if (!checkInBackground_) await bridge().showErrorMessageBox(error.message);
|
|
|
|
} finally {
|
2018-02-16 01:05:04 +02:00
|
|
|
onCheckEnded();
|
2021-05-14 11:29:06 +02:00
|
|
|
}
|
2018-01-31 00:35:50 +02:00
|
|
|
}
|