SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { EventEmitter } from 'events';
import { isString } from 'vs/base/common/types';
import { Promise } from 'vs/base/common/winjs.base';
import { asJson } from 'vs/base/node/request';
import { IRequestService } from 'vs/platform/request/node/request';
import { IAutoUpdater } from 'vs/platform/update/common/update';
import product from 'vs/platform/node/product';
interface IUpdate {
url: string;
name: string;
releaseNotes?: string;
version: string;
productVersion: string;
hash: string;
}
export class LinuxAutoUpdaterImpl extends EventEmitter implements IAutoUpdater {
private url: string;
private currentRequest: Promise;
constructor(
@IRequestService private requestService: IRequestService
) {
super();
this.url = null;
this.currentRequest = null;
}
setFeedURL(url: string): void {
this.url = url;
}
checkForUpdates(): void {
if (!this.url) {
throw new Error('No feed url set.');
}
if (this.currentRequest) {
return;
}
this.emit('checking-for-update');
this.currentRequest = this.requestService.request({ url: this.url })
.then<IUpdate>(asJson)
.then(update => {
if (!update || !update.url || !update.version || !update.productVersion) {
this.emit('update-not-available');
} else {
this.emit('update-available', null, product.downloadUrl, update.productVersion);
}
})
.then(null, e => {
if (isString(e) && /^Server returned/.test(e)) {
return;
}
this.emit('update-not-available');
this.emit('error', e);
})
.then(() => this.currentRequest = null);
}
quitAndInstall(): void {
// noop
}
}

View File

@@ -0,0 +1,140 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as path from 'path';
import * as pfs from 'vs/base/node/pfs';
import { checksum } from 'vs/base/node/crypto';
import { EventEmitter } from 'events';
import { tmpdir } from 'os';
import { spawn } from 'child_process';
import { mkdirp } from 'vs/base/node/extfs';
import { isString } from 'vs/base/common/types';
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import { download, asJson } from 'vs/base/node/request';
import { IRequestService } from 'vs/platform/request/node/request';
import { IAutoUpdater } from 'vs/platform/update/common/update';
import product from 'vs/platform/node/product';
interface IUpdate {
url: string;
name: string;
releaseNotes?: string;
version: string;
productVersion: string;
hash: string;
}
export class Win32AutoUpdaterImpl extends EventEmitter implements IAutoUpdater {
private url: string = null;
private currentRequest: Promise = null;
private updatePackagePath: string = null;
constructor(
@IRequestService private requestService: IRequestService
) {
super();
}
get cachePath(): TPromise<string> {
const result = path.join(tmpdir(), `vscode-update-${process.arch}`);
return new TPromise<string>((c, e) => mkdirp(result, null, err => err ? e(err) : c(result)));
}
setFeedURL(url: string): void {
this.url = url;
}
checkForUpdates(): void {
if (!this.url) {
throw new Error('No feed url set.');
}
if (this.currentRequest) {
return;
}
this.emit('checking-for-update');
this.currentRequest = this.requestService.request({ url: this.url })
.then<IUpdate>(asJson)
.then(update => {
if (!update || !update.url || !update.version) {
this.emit('update-not-available');
return this.cleanup();
}
this.emit('update-available');
return this.cleanup(update.version).then(() => {
return this.getUpdatePackagePath(update.version).then(updatePackagePath => {
return pfs.exists(updatePackagePath).then(exists => {
if (exists) {
return TPromise.as(updatePackagePath);
}
const url = update.url;
const hash = update.hash;
const downloadPath = `${updatePackagePath}.tmp`;
return this.requestService.request({ url })
.then(context => download(downloadPath, context))
.then(hash ? () => checksum(downloadPath, update.hash) : () => null)
.then(() => pfs.rename(downloadPath, updatePackagePath))
.then(() => updatePackagePath);
});
}).then(updatePackagePath => {
this.updatePackagePath = updatePackagePath;
this.emit('update-downloaded',
{},
update.releaseNotes,
update.productVersion,
new Date(),
this.url
);
});
});
})
.then(null, e => {
if (isString(e) && /^Server returned/.test(e)) {
return;
}
this.emit('update-not-available');
this.emit('error', e);
})
.then(() => this.currentRequest = null);
}
private getUpdatePackagePath(version: string): TPromise<string> {
return this.cachePath.then(cachePath => path.join(cachePath, `CodeSetup-${product.quality}-${version}.exe`));
}
private cleanup(exceptVersion: string = null): Promise {
const filter = exceptVersion ? one => !(new RegExp(`${product.quality}-${exceptVersion}\\.exe$`).test(one)) : () => true;
return this.cachePath
.then(cachePath => pfs.readdir(cachePath)
.then(all => Promise.join(all
.filter(filter)
.map(one => pfs.unlink(path.join(cachePath, one)).then(null, () => null))
))
);
}
quitAndInstall(): void {
if (!this.updatePackagePath) {
return;
}
spawn(this.updatePackagePath, ['/silent', '/mergetasks=runcode,!desktopicon,!quicklaunchicon'], {
detached: true,
stdio: ['ignore', 'ignore', 'ignore']
});
}
}

View File

@@ -0,0 +1,268 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as fs from 'original-fs';
import * as path from 'path';
import * as electron from 'electron';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import Event, { Emitter, once, filterEvent } from 'vs/base/common/event';
import { always, Throttler } from 'vs/base/common/async';
import { memoize } from 'vs/base/common/decorators';
import { fromEventEmitter } from 'vs/base/node/event';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Win32AutoUpdaterImpl } from './auto-updater.win32';
import { LinuxAutoUpdaterImpl } from './auto-updater.linux';
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { IRequestService } from 'vs/platform/request/node/request';
import product from 'vs/platform/node/product';
import { TPromise } from 'vs/base/common/winjs.base';
import { IUpdateService, State, IAutoUpdater, IUpdate, IRawUpdate } from 'vs/platform/update/common/update';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class UpdateService implements IUpdateService {
_serviceBrand: any;
private _state: State = State.Uninitialized;
private _availableUpdate: IUpdate = null;
private raw: IAutoUpdater;
private throttler: Throttler = new Throttler();
private _onError = new Emitter<any>();
get onError(): Event<any> { return this._onError.event; }
private _onCheckForUpdate = new Emitter<void>();
get onCheckForUpdate(): Event<void> { return this._onCheckForUpdate.event; }
private _onUpdateAvailable = new Emitter<{ url: string; version: string; }>();
get onUpdateAvailable(): Event<{ url: string; version: string; }> { return this._onUpdateAvailable.event; }
private _onUpdateNotAvailable = new Emitter<boolean>();
get onUpdateNotAvailable(): Event<boolean> { return this._onUpdateNotAvailable.event; }
private _onUpdateReady = new Emitter<IRawUpdate>();
get onUpdateReady(): Event<IRawUpdate> { return this._onUpdateReady.event; }
private _onStateChange = new Emitter<State>();
get onStateChange(): Event<State> { return this._onStateChange.event; }
@memoize
private get onRawError(): Event<string> {
return fromEventEmitter(this.raw, 'error', (_, message) => message);
}
@memoize
private get onRawUpdateNotAvailable(): Event<void> {
return fromEventEmitter<void>(this.raw, 'update-not-available');
}
@memoize
private get onRawUpdateAvailable(): Event<{ url: string; version: string; }> {
return filterEvent(fromEventEmitter(this.raw, 'update-available', (_, url, version) => ({ url, version })), ({ url }) => !!url);
}
@memoize
private get onRawUpdateDownloaded(): Event<IRawUpdate> {
return fromEventEmitter(this.raw, 'update-downloaded', (_, releaseNotes, version, date, url) => ({ releaseNotes, version, date }));
}
get state(): State {
return this._state;
}
set state(state: State) {
this._state = state;
this._onStateChange.fire(state);
}
get availableUpdate(): IUpdate {
return this._availableUpdate;
}
constructor(
@IRequestService requestService: IRequestService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IConfigurationService private configurationService: IConfigurationService,
@ITelemetryService private telemetryService: ITelemetryService
) {
if (process.platform === 'win32') {
this.raw = new Win32AutoUpdaterImpl(requestService);
} else if (process.platform === 'linux') {
this.raw = new LinuxAutoUpdaterImpl(requestService);
} else if (process.platform === 'darwin') {
this.raw = electron.autoUpdater;
} else {
return;
}
const channel = this.getUpdateChannel();
const feedUrl = this.getUpdateFeedUrl(channel);
if (!feedUrl) {
return; // updates not available
}
try {
this.raw.setFeedURL(feedUrl);
} catch (e) {
return; // application not signed
}
this.state = State.Idle;
// Start checking for updates after 30 seconds
this.scheduleCheckForUpdates(30 * 1000)
.done(null, err => console.error(err));
}
private scheduleCheckForUpdates(delay = 60 * 60 * 1000): TPromise<void> {
return TPromise.timeout(delay)
.then(() => this.checkForUpdates())
.then(update => {
if (update) {
// Update found, no need to check more
return TPromise.as(null);
}
// Check again after 1 hour
return this.scheduleCheckForUpdates(60 * 60 * 1000);
});
}
checkForUpdates(explicit = false): TPromise<IUpdate> {
return this.throttler.queue(() => this._checkForUpdates(explicit))
.then(null, err => {
if (explicit) {
this._onError.fire(err);
}
return null;
});
}
private _checkForUpdates(explicit: boolean): TPromise<IUpdate> {
if (this.state !== State.Idle) {
return TPromise.as(null);
}
this._onCheckForUpdate.fire();
this.state = State.CheckingForUpdate;
const listeners: IDisposable[] = [];
const result = new TPromise<IUpdate>((c, e) => {
once(this.onRawError)(e, null, listeners);
once(this.onRawUpdateNotAvailable)(() => c(null), null, listeners);
once(this.onRawUpdateAvailable)(({ url, version }) => url && c({ url, version }), null, listeners);
once(this.onRawUpdateDownloaded)(({ version, date, releaseNotes }) => c({ version, date, releaseNotes }), null, listeners);
this.raw.checkForUpdates();
}).then(update => {
if (!update) {
this._onUpdateNotAvailable.fire(explicit);
this.state = State.Idle;
this.telemetryService.publicLog('update:notAvailable', { explicit });
} else if (update.url) {
const data: IUpdate = {
url: update.url,
releaseNotes: '',
version: update.version,
date: new Date()
};
this._availableUpdate = data;
this._onUpdateAvailable.fire({ url: update.url, version: update.version });
this.state = State.UpdateAvailable;
this.telemetryService.publicLog('update:available', { explicit, version: update.version, currentVersion: product.commit });
} else {
const data: IRawUpdate = {
releaseNotes: update.releaseNotes,
version: update.version,
date: update.date
};
this._availableUpdate = data;
this._onUpdateReady.fire(data);
this.state = State.UpdateDownloaded;
this.telemetryService.publicLog('update:downloaded', { version: update.version });
}
return update;
}, err => {
this.state = State.Idle;
return TPromise.wrapError<IUpdate>(err);
});
return always(result, () => dispose(listeners));
}
private getUpdateChannel(): string {
const config = this.configurationService.getConfiguration<{ channel: string; }>('update');
const channel = config && config.channel;
return channel === 'none' ? null : product.quality;
}
private getUpdateFeedUrl(channel: string): string {
if (!channel) {
return null;
}
if (process.platform === 'win32' && !fs.existsSync(path.join(path.dirname(process.execPath), 'unins000.exe'))) {
return null;
}
if (!product.updateUrl || !product.commit) {
return null;
}
const platform = this.getUpdatePlatform();
return `${product.updateUrl}/api/update/${platform}/${channel}/${product.commit}`;
}
private getUpdatePlatform(): string {
if (process.platform === 'linux') {
return `linux-${process.arch}`;
}
if (process.platform === 'win32' && process.arch === 'x64') {
return 'win32-x64';
}
return process.platform;
}
quitAndInstall(): TPromise<void> {
if (!this._availableUpdate) {
return TPromise.as(null);
}
if (this._availableUpdate.url) {
electron.shell.openExternal(this._availableUpdate.url);
return TPromise.as(null);
}
this.lifecycleService.quit(true /* from update */).done(vetod => {
if (vetod) {
return;
}
// for some reason updating on Mac causes the local storage not to be flushed.
// we workaround this issue by forcing an explicit flush of the storage data.
// see also https://github.com/Microsoft/vscode/issues/172
if (process.platform === 'darwin') {
electron.session.defaultSession.flushStorageData();
}
this.raw.quitAndInstall();
});
return TPromise.as(null);
}
}