UNPKG

sussudio

Version:

An unofficial VS Code Internal API

178 lines (177 loc) 7.84 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { spawn } from 'child_process'; import { realpath, watch } from 'fs'; import { timeout } from "../../../base/common/async.mjs"; import { Emitter, Event } from "../../../base/common/event.mjs"; import * as path from "../../../base/common/path.mjs"; import { IEnvironmentMainService } from "../../environment/electron-main/environmentMainService.mjs"; import { ILifecycleMainService } from "../../lifecycle/electron-main/lifecycleMainService.mjs"; import { ILogService } from "../../log/common/log.mjs"; import { ITelemetryService } from "../../telemetry/common/telemetry.mjs"; import { State } from "../common/update.mjs"; let AbstractUpdateService = class AbstractUpdateService { lifecycleMainService; logService; _state = State.Uninitialized; _onStateChange = new Emitter(); onStateChange = this._onStateChange.event; get state() { return this._state; } setState(state) { this.logService.info('update#setState', state.type); this._state = state; this._onStateChange.fire(state); } constructor(lifecycleMainService, environmentMainService, logService) { this.lifecycleMainService = lifecycleMainService; this.logService = logService; if (environmentMainService.disableUpdates) { this.logService.info('update#ctor - updates are disabled'); return; } this.setState(State.Idle(this.getUpdateType())); // Start checking for updates after 30 seconds this.scheduleCheckForUpdates(30 * 1000).then(undefined, err => this.logService.error(err)); } scheduleCheckForUpdates(delay = 60 * 60 * 1000) { return timeout(delay) .then(() => this.checkForUpdates(false)) .then(() => { // Check again after 1 hour return this.scheduleCheckForUpdates(60 * 60 * 1000); }); } async checkForUpdates(explicit) { this.logService.trace('update#checkForUpdates, state = ', this.state.type); if (this.state.type !== "idle" /* StateType.Idle */) { return; } this.doCheckForUpdates(explicit); } async downloadUpdate() { this.logService.trace('update#downloadUpdate, state = ', this.state.type); if (this.state.type !== "available for download" /* StateType.AvailableForDownload */) { return; } await this.doDownloadUpdate(this.state); } doDownloadUpdate(state) { return Promise.resolve(undefined); } async applyUpdate() { this.logService.trace('update#applyUpdate, state = ', this.state.type); if (this.state.type !== "downloaded" /* StateType.Downloaded */) { return; } await this.doApplyUpdate(); } doApplyUpdate() { return Promise.resolve(undefined); } quitAndInstall() { this.logService.trace('update#quitAndInstall, state = ', this.state.type); if (this.state.type !== "ready" /* StateType.Ready */) { return Promise.resolve(undefined); } this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); this.lifecycleMainService.quit(true /* will restart */).then(vetod => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; } this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); this.doQuitAndInstall(); }); return Promise.resolve(undefined); } getUpdateType() { return 2 /* UpdateType.Snap */; } doQuitAndInstall() { // noop } async _applySpecificUpdate(packagePath) { // noop } }; AbstractUpdateService = __decorate([ __param(0, ILifecycleMainService), __param(1, IEnvironmentMainService), __param(2, ILogService) ], AbstractUpdateService); let SnapUpdateService = class SnapUpdateService extends AbstractUpdateService { snap; snapRevision; telemetryService; constructor(snap, snapRevision, lifecycleMainService, environmentMainService, logService, telemetryService) { super(lifecycleMainService, environmentMainService, logService); this.snap = snap; this.snapRevision = snapRevision; this.telemetryService = telemetryService; const watcher = watch(path.dirname(this.snap)); const onChange = Event.fromNodeEventEmitter(watcher, 'change', (_, fileName) => fileName); const onCurrentChange = Event.filter(onChange, n => n === 'current'); const onDebouncedCurrentChange = Event.debounce(onCurrentChange, (_, e) => e, 2000); const listener = onDebouncedCurrentChange(() => this.checkForUpdates(false)); lifecycleMainService.onWillShutdown(() => { listener.dispose(); watcher.close(); }); } doCheckForUpdates() { this.setState(State.CheckingForUpdates(false)); this.isUpdateAvailable().then(result => { if (result) { this.setState(State.Ready({ version: 'something', productVersion: 'something' })); } else { this.telemetryService.publicLog2('update:notAvailable', { explicit: false }); this.setState(State.Idle(2 /* UpdateType.Snap */)); } }, err => { this.logService.error(err); this.telemetryService.publicLog2('update:notAvailable', { explicit: false }); this.setState(State.Idle(2 /* UpdateType.Snap */, err.message || err)); }); } doQuitAndInstall() { this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); // Allow 3 seconds for VS Code to close spawn('sleep 3 && ' + path.basename(process.argv[0]), { shell: true, detached: true, stdio: 'ignore', }); } async isUpdateAvailable() { const resolvedCurrentSnapPath = await new Promise((c, e) => realpath(`${path.dirname(this.snap)}/current`, (err, r) => err ? e(err) : c(r))); const currentRevision = path.basename(resolvedCurrentSnapPath); return this.snapRevision !== currentRevision; } isLatestVersion() { return this.isUpdateAvailable().then(undefined, err => { this.logService.error('update#checkForSnapUpdate(): Could not get realpath of application.'); return undefined; }); } }; SnapUpdateService = __decorate([ __param(2, ILifecycleMainService), __param(3, IEnvironmentMainService), __param(4, ILogService), __param(5, ITelemetryService) ], SnapUpdateService); export { SnapUpdateService };