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,58 @@
/*---------------------------------------------------------------------------------------------
* 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 Event from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { TPromise } from 'vs/base/common/winjs.base';
export enum State {
Uninitialized,
Idle,
CheckingForUpdate,
UpdateAvailable,
UpdateDownloaded
}
export enum ExplicitState {
Implicit,
Explicit
}
export interface IRawUpdate {
releaseNotes: string;
version: string;
date: Date;
}
export interface IUpdate {
version: string;
date?: Date;
releaseNotes?: string;
url?: string;
}
export interface IAutoUpdater extends NodeJS.EventEmitter {
setFeedURL(url: string): void;
checkForUpdates(): void;
quitAndInstall(): void;
}
export const IUpdateService = createDecorator<IUpdateService>('updateService');
export interface IUpdateService {
_serviceBrand: any;
readonly onError: Event<any>;
readonly onUpdateAvailable: Event<{ url: string; version: string; }>;
readonly onUpdateNotAvailable: Event<boolean>;
readonly onUpdateReady: Event<IRawUpdate>;
readonly onStateChange: Event<State>;
readonly state: State;
checkForUpdates(explicit: boolean): TPromise<IUpdate>;
quitAndInstall(): TPromise<void>;
}

View File

@@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------------------------
* 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 { TPromise } from 'vs/base/common/winjs.base';
import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc';
import Event, { Emitter } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IUpdateService, IRawUpdate, State, IUpdate } from './update';
export interface IUpdateChannel extends IChannel {
call(command: 'event:onError'): TPromise<void>;
call(command: 'event:onUpdateAvailable'): TPromise<void>;
call(command: 'event:onUpdateNotAvailable'): TPromise<void>;
call(command: 'event:onUpdateReady'): TPromise<void>;
call(command: 'event:onStateChange'): TPromise<void>;
call(command: 'checkForUpdates', arg: boolean): TPromise<IUpdate>;
call(command: 'quitAndInstall'): TPromise<void>;
call(command: '_getInitialState'): TPromise<State>;
call(command: string, arg?: any): TPromise<any>;
}
export class UpdateChannel implements IUpdateChannel {
constructor(private service: IUpdateService) { }
call(command: string, arg?: any): TPromise<any> {
switch (command) {
case 'event:onError': return eventToCall(this.service.onError);
case 'event:onUpdateAvailable': return eventToCall(this.service.onUpdateAvailable);
case 'event:onUpdateNotAvailable': return eventToCall(this.service.onUpdateNotAvailable);
case 'event:onUpdateReady': return eventToCall(this.service.onUpdateReady);
case 'event:onStateChange': return eventToCall(this.service.onStateChange);
case 'checkForUpdates': return this.service.checkForUpdates(arg);
case 'quitAndInstall': return this.service.quitAndInstall();
case '_getInitialState': return TPromise.as(this.service.state);
}
return undefined;
}
}
export class UpdateChannelClient implements IUpdateService {
_serviceBrand: any;
private _onError = eventFromCall<any>(this.channel, 'event:onError');
get onError(): Event<any> { return this._onError; }
private _onUpdateAvailable = eventFromCall<{ url: string; version: string; }>(this.channel, 'event:onUpdateAvailable');
get onUpdateAvailable(): Event<{ url: string; version: string; }> { return this._onUpdateAvailable; }
private _onUpdateNotAvailable = eventFromCall<boolean>(this.channel, 'event:onUpdateNotAvailable');
get onUpdateNotAvailable(): Event<boolean> { return this._onUpdateNotAvailable; }
private _onUpdateReady = eventFromCall<IRawUpdate>(this.channel, 'event:onUpdateReady');
get onUpdateReady(): Event<IRawUpdate> { return this._onUpdateReady; }
private _onRemoteStateChange = eventFromCall<State>(this.channel, 'event:onStateChange');
private _onStateChange = new Emitter<State>();
get onStateChange(): Event<State> { return this._onStateChange.event; }
private _state: State = State.Uninitialized;
get state(): State { return this._state; };
constructor(private channel: IUpdateChannel) {
// always set this._state as the state changes
this.onStateChange(state => this._state = state);
channel.call('_getInitialState').done(state => {
// fire initial state
this._onStateChange.fire(state);
// fire subsequent states as they come in from remote
this._onRemoteStateChange(state => this._onStateChange.fire(state));
}, onUnexpectedError);
}
checkForUpdates(explicit: boolean): TPromise<IUpdate> {
return this.channel.call('checkForUpdates', explicit);
}
quitAndInstall(): TPromise<void> {
return this.channel.call('quitAndInstall');
}
}

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);
}
}