diff --git a/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts index fbaebf81a995..8a1b2dbbf7c2 100644 --- a/src/vs/platform/update/common/update.ts +++ b/src/vs/platform/update/common/update.ts @@ -89,4 +89,6 @@ export interface IUpdateService { downloadUpdate(): TPromise; applyUpdate(): TPromise; quitAndInstall(): TPromise; -} \ No newline at end of file + + isLatestVersion(): TPromise; +} diff --git a/src/vs/platform/update/common/updateIpc.ts b/src/vs/platform/update/common/updateIpc.ts index 2e26e13ed3d5..5138e17702ce 100644 --- a/src/vs/platform/update/common/updateIpc.ts +++ b/src/vs/platform/update/common/updateIpc.ts @@ -17,6 +17,7 @@ export interface IUpdateChannel extends IChannel { call(command: 'applyUpdate'): TPromise; call(command: 'quitAndInstall'): TPromise; call(command: '_getInitialState'): TPromise; + call(command: 'isLatestVersion'): TPromise; call(command: string, arg?: any): TPromise; } @@ -32,6 +33,7 @@ export class UpdateChannel implements IUpdateChannel { case 'applyUpdate': return this.service.applyUpdate(); case 'quitAndInstall': return this.service.quitAndInstall(); case '_getInitialState': return TPromise.as(this.service.state); + case 'isLatestVersion': return this.service.isLatestVersion(); } return undefined; } @@ -77,4 +79,8 @@ export class UpdateChannelClient implements IUpdateService { quitAndInstall(): TPromise { return this.channel.call('quitAndInstall'); } -} \ No newline at end of file + + isLatestVersion(): TPromise { + return this.channel.call('isLatestVersion'); + } +} diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index 6734f82fa366..245df1d3053f 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -14,6 +14,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IUpdateService, State, StateType, AvailableForDownload } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; +import { IRequestService } from 'vs/platform/request/node/request'; export function createUpdateURL(platform: string, quality: string): string { return `${product.updateUrl}/api/update/${platform}/${quality}/${product.commit}`; @@ -23,6 +24,8 @@ export abstract class AbstractUpdateService implements IUpdateService { _serviceBrand: any; + protected readonly url: string | undefined; + private _state: State = State.Uninitialized; private throttler: Throttler = new Throttler(); @@ -43,7 +46,8 @@ export abstract class AbstractUpdateService implements IUpdateService { @ILifecycleService private lifecycleService: ILifecycleService, @IConfigurationService protected configurationService: IConfigurationService, @IEnvironmentService private environmentService: IEnvironmentService, - @ILogService protected logService: ILogService + @IRequestService protected requestService: IRequestService, + @ILogService protected logService: ILogService, ) { if (this.environmentService.disableUpdates) { this.logService.info('update#ctor - updates are disabled'); @@ -62,7 +66,8 @@ export abstract class AbstractUpdateService implements IUpdateService { return; } - if (!this.setUpdateFeedUrl(quality)) { + this.url = this.buildUpdateFeedUrl(quality); + if (!this.url) { this.logService.info('update#ctor - updates are disabled'); return; } @@ -153,10 +158,25 @@ export abstract class AbstractUpdateService implements IUpdateService { return TPromise.as(null); } + isLatestVersion(): TPromise { + if (!this.url) { + return TPromise.as(undefined); + } + return this.requestService.request({ url: this.url }).then(context => { + // The update server replies with 204 (No Content) when no + // update is available - that's all we want to know. + if (context.res.statusCode === 204) { + return true; + } else { + return false; + } + }); + } + protected doQuitAndInstall(): void { // noop } - protected abstract setUpdateFeedUrl(quality: string): boolean; + protected abstract buildUpdateFeedUrl(quality: string): string | undefined; protected abstract doCheckForUpdates(context: any): void; } diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index a75576d9195c..81b935cf7589 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -16,6 +16,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { AbstractUpdateService, createUpdateURL } from 'vs/platform/update/electron-main/abstractUpdateService'; +import { IRequestService } from 'vs/platform/request/node/request'; export class DarwinUpdateService extends AbstractUpdateService { @@ -33,9 +34,10 @@ export class DarwinUpdateService extends AbstractUpdateService { @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, + @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleService, configurationService, environmentService, logService); + super(lifecycleService, configurationService, environmentService, requestService, logService); this.onRawError(this.onError, this, this.disposables); this.onRawUpdateAvailable(this.onUpdateAvailable, this, this.disposables); this.onRawUpdateDownloaded(this.onUpdateDownloaded, this, this.disposables); @@ -47,16 +49,16 @@ export class DarwinUpdateService extends AbstractUpdateService { this.setState(State.Idle); } - protected setUpdateFeedUrl(quality: string): boolean { + protected buildUpdateFeedUrl(quality: string): string | undefined { + const url = createUpdateURL('darwin', quality); try { - electron.autoUpdater.setFeedURL(createUpdateURL('darwin', quality)); + electron.autoUpdater.setFeedURL(url); } catch (e) { // application is very likely not signed this.logService.error('Failed to set update feed URL', e); - return false; + return undefined; } - - return true; + return url; } protected doCheckForUpdates(context: any): void { diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 12d660bb203b..224b447a94c4 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -22,22 +22,19 @@ export class LinuxUpdateService extends AbstractUpdateService { _serviceBrand: any; - private url: string | undefined; - constructor( @ILifecycleService lifecycleService: ILifecycleService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, - @IRequestService private requestService: IRequestService, + @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleService, configurationService, environmentService, logService); + super(lifecycleService, configurationService, environmentService, requestService, logService); } - protected setUpdateFeedUrl(quality: string): boolean { - this.url = createUpdateURL(`linux-${process.arch}`, quality); - return true; + protected buildUpdateFeedUrl(quality: string): string { + return createUpdateURL(`linux-${process.arch}`, quality); } protected doCheckForUpdates(context: any): void { diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 6ac195ed9de8..ae6855cf57bf 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -47,7 +47,6 @@ export class Win32UpdateService extends AbstractUpdateService { _serviceBrand: any; - private url: string | undefined; private availableUpdate: IAvailableUpdate | undefined; @memoize @@ -61,15 +60,15 @@ export class Win32UpdateService extends AbstractUpdateService { @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, - @IRequestService private requestService: IRequestService, + @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleService, configurationService, environmentService, logService); + super(lifecycleService, configurationService, environmentService, requestService, logService); } - protected setUpdateFeedUrl(quality: string): boolean { + protected buildUpdateFeedUrl(quality: string): string | undefined { if (!fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe'))) { - return false; + return undefined; } let platform = 'win32'; @@ -82,8 +81,7 @@ export class Win32UpdateService extends AbstractUpdateService { platform += '-user'; } - this.url = createUpdateURL(platform, quality); - return true; + return createUpdateURL(platform, quality); } protected doCheckForUpdates(context: any): void { diff --git a/src/vs/workbench/parts/performance/electron-browser/startupTimings.ts b/src/vs/workbench/parts/performance/electron-browser/startupTimings.ts index 74eb0b8e04c4..3f9a70df2fd1 100644 --- a/src/vs/workbench/parts/performance/electron-browser/startupTimings.ts +++ b/src/vs/workbench/parts/performance/electron-browser/startupTimings.ts @@ -21,6 +21,7 @@ import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { ILogService } from 'vs/platform/log/common/log'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IUpdateService } from 'vs/platform/update/common/update'; class StartupTimings implements IWorkbenchContribution { @@ -34,6 +35,7 @@ class StartupTimings implements IWorkbenchContribution { @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IExtensionService private readonly _extensionService: IExtensionService, + @IUpdateService private readonly _updateService: IUpdateService, ) { this._reportVariedStartupTimes().then(undefined, onUnexpectedError); @@ -87,7 +89,10 @@ class StartupTimings implements IWorkbenchContribution { this._logService.info('no standard startup: not using cached data'); return; } - + if (!await this._updateService.isLatestVersion()) { + this._logService.info('no standard startup: not running latest version'); + return; + } // wait only know so that can check the restored state as soon as possible await TPromise.join([ this._extensionService.whenInstalledExtensionsRegistered(),