mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-03 09:35:40 -05:00
Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)
This commit is contained in:
@@ -99,6 +99,10 @@ export const enum ConfigurationScope {
|
||||
* Resource specific configuration, which can be configured in the user, workspace or folder settings.
|
||||
*/
|
||||
RESOURCE,
|
||||
/**
|
||||
* Machine specific configuration that can also be configured in workspace or folder settings.
|
||||
*/
|
||||
MACHINE_OVERRIDABLE,
|
||||
}
|
||||
|
||||
export interface IConfigurationPropertySchema extends IJSONSchema {
|
||||
|
||||
@@ -20,7 +20,7 @@ export class DownloadService implements IDownloadService {
|
||||
) { }
|
||||
|
||||
async download(resource: URI, target: URI, cancellationToken: CancellationToken = CancellationToken.None): Promise<void> {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
if (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote) {
|
||||
await this.fileService.copy(resource, target);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ export interface IExtensionManagementService {
|
||||
|
||||
zip(extension: ILocalExtension): Promise<URI>;
|
||||
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier>;
|
||||
getManifest(vsix: URI): Promise<IExtensionManifest>;
|
||||
install(vsix: URI): Promise<ILocalExtension>;
|
||||
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension>;
|
||||
uninstall(extension: ILocalExtension, force?: boolean): Promise<void>;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
|
||||
return URI.revive(transformer ? transformer.transformIncoming(uri) : uri);
|
||||
@@ -62,6 +62,7 @@ export class ExtensionManagementChannel implements IServerChannel {
|
||||
case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer));
|
||||
case 'unzip': return this.service.unzip(transformIncomingURI(args[0], uriTransformer), args[1]);
|
||||
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer));
|
||||
case 'getManifest': return this.service.getManifest(transformIncomingURI(args[0], uriTransformer));
|
||||
case 'installFromGallery': return this.service.installFromGallery(args[0]);
|
||||
case 'uninstall': return this.service.uninstall(transformIncomingExtension(args[0], uriTransformer), args[1]);
|
||||
case 'reinstallFromGallery': return this.service.reinstallFromGallery(transformIncomingExtension(args[0], uriTransformer));
|
||||
@@ -99,6 +100,10 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
|
||||
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix])).then(local => transformIncomingExtension(local, null));
|
||||
}
|
||||
|
||||
getManifest(vsix: URI): Promise<IExtensionManifest> {
|
||||
return Promise.resolve(this.channel.call<IExtensionManifest>('getManifest', [vsix]));
|
||||
}
|
||||
|
||||
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
|
||||
return Promise.resolve(this.channel.call<ILocalExtension>('installFromGallery', [extension])).then(local => transformIncomingExtension(local, null));
|
||||
}
|
||||
|
||||
@@ -164,6 +164,12 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
return this.install(zipLocation, type).then(local => local.identifier);
|
||||
}
|
||||
|
||||
async getManifest(vsix: URI): Promise<IExtensionManifest> {
|
||||
const downloadLocation = await this.downloadVsix(vsix);
|
||||
const zipPath = path.resolve(downloadLocation.fsPath);
|
||||
return getManifest(zipPath);
|
||||
}
|
||||
|
||||
private collectFiles(extension: ILocalExtension): Promise<IFile[]> {
|
||||
|
||||
const collectFilesFromDirectory = async (dir: string): Promise<string[]> => {
|
||||
|
||||
@@ -71,7 +71,7 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine
|
||||
result.workspaces.push({ folderUri: URI.file(workspace) });
|
||||
} else if (isLegacySerializedWorkspace(workspace)) {
|
||||
result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } });
|
||||
} else if (isUriComponents(window)) {
|
||||
} else if (isUriComponents(workspace)) {
|
||||
// added by 1.26-insiders
|
||||
result.workspaces.push({ folderUri: URI.revive(<UriComponents>workspace) });
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
|
||||
export class BrowserLifecycleService extends AbstractLifecycleService {
|
||||
|
||||
@@ -22,10 +23,10 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
window.onbeforeunload = () => this.beforeUnload();
|
||||
addDisposableListener(window, EventType.BEFORE_UNLOAD, () => this.onBeforeUnload());
|
||||
}
|
||||
|
||||
private beforeUnload(): string | null {
|
||||
private onBeforeUnload(): string | null {
|
||||
let veto = false;
|
||||
|
||||
// Before Shutdown
|
||||
@@ -34,7 +35,7 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
|
||||
if (value === true) {
|
||||
veto = true;
|
||||
} else if (value instanceof Promise && !veto) {
|
||||
console.warn(new Error('Long running onBeforeShutdown currently not supported'));
|
||||
console.warn(new Error('Long running onBeforeShutdown currently not supported in the web'));
|
||||
veto = true;
|
||||
}
|
||||
},
|
||||
@@ -49,11 +50,14 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
|
||||
// No Veto: continue with Will Shutdown
|
||||
this._onWillShutdown.fire({
|
||||
join() {
|
||||
console.warn(new Error('Long running onWillShutdown currently not supported'));
|
||||
console.warn(new Error('Long running onWillShutdown currently not supported in the web'));
|
||||
},
|
||||
reason: ShutdownReason.QUIT
|
||||
});
|
||||
|
||||
// Finally end with Shutdown event
|
||||
this._onShutdown.fire();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/node/menubar';
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels';
|
||||
import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IHistoryMainService } from 'vs/platform/history/common/history';
|
||||
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IStateService } from 'vs/platform/state/common/state';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/node/menubar';
|
||||
import { Menubar } from 'vs/platform/menubar/electron-main/menubar';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IMenubarService } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenubarService } from 'vs/platform/menubar/node/menubar';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export class MenubarChannel implements IServerChannel {
|
||||
|
||||
@@ -11,6 +11,7 @@ export const IOpenerService = createDecorator<IOpenerService>('openerService');
|
||||
|
||||
export interface IOpener {
|
||||
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
||||
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface IOpenerService {
|
||||
@@ -29,18 +30,11 @@ export interface IOpenerService {
|
||||
* @return A promise that resolves when the opening is done.
|
||||
*/
|
||||
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Opens a URL externally.
|
||||
*
|
||||
* @param url A resource to open externally.
|
||||
*/
|
||||
openExternal(resource: URI): Promise<boolean>;
|
||||
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const NullOpenerService: IOpenerService = Object.freeze({
|
||||
_serviceBrand: undefined,
|
||||
registerOpener() { return { dispose() { } }; },
|
||||
open() { return Promise.resolve(false); },
|
||||
openExternal() { return Promise.resolve(false); }
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
||||
private workspaceStorageFile: URI;
|
||||
|
||||
private initializePromise: Promise<void>;
|
||||
private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.saveState(), 5000));
|
||||
private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.collectState(), 5000));
|
||||
|
||||
get hasPendingUpdate(): boolean {
|
||||
return this.globalStorageDatabase.hasPendingUpdate || this.workspaceStorageDatabase.hasPendingUpdate;
|
||||
@@ -57,14 +57,19 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
||||
this.periodicSaveScheduler.schedule();
|
||||
}
|
||||
|
||||
private saveState(): void {
|
||||
private collectState(): void {
|
||||
runWhenIdle(() => {
|
||||
|
||||
// this event will potentially cause new state to be stored
|
||||
// since new state will only be created while the document
|
||||
// has focus, one optimization is to not run this when the
|
||||
// document has no focus, assuming that state has not changed
|
||||
if (document.hasFocus()) {
|
||||
//
|
||||
// another optimization is to not collect more state if we
|
||||
// have a pending update already running which indicates
|
||||
// that the connection is either slow or disconnected and
|
||||
// thus unhealthy.
|
||||
if (document.hasFocus() && !this.hasPendingUpdate) {
|
||||
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
|
||||
}
|
||||
|
||||
@@ -197,7 +202,7 @@ export class FileStorageDatabase extends Disposable implements IStorageDatabase
|
||||
this._register(this.fileService.watch(this.file));
|
||||
this._register(this.fileService.onFileChanges(e => {
|
||||
if (document.hasFocus()) {
|
||||
return; // ignore changes from ourselves by checking for focus
|
||||
return; // optimization: ignore changes from ourselves by checking for focus
|
||||
}
|
||||
|
||||
if (!e.contains(this.file, FileChangeType.UPDATED)) {
|
||||
@@ -251,15 +256,17 @@ export class FileStorageDatabase extends Disposable implements IStorageDatabase
|
||||
|
||||
await this.pendingUpdate;
|
||||
|
||||
this._hasPendingUpdate = true;
|
||||
this.pendingUpdate = (async () => {
|
||||
try {
|
||||
this._hasPendingUpdate = true;
|
||||
|
||||
await this.fileService.writeFile(this.file, VSBuffer.fromString(JSON.stringify(mapToSerializable(items))));
|
||||
|
||||
this.pendingUpdate = this.fileService.writeFile(this.file, VSBuffer.fromString(JSON.stringify(mapToSerializable(items))))
|
||||
.then(() => {
|
||||
this.ensureWatching(); // now that the file must exist, ensure we watch it for changes
|
||||
})
|
||||
.finally(() => {
|
||||
} finally {
|
||||
this._hasPendingUpdate = false;
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
return this.pendingUpdate;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { StorageMainService, IStorageChangeEvent } from 'vs/platform/storage/node/storageMainService';
|
||||
import { IStorageChangeEvent, IStorageMainService } from 'vs/platform/storage/node/storageMainService';
|
||||
import { IUpdateRequest, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/parts/storage/common/storage';
|
||||
import { mapToSerializable, serializableToMap, values } from 'vs/base/common/map';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
@@ -38,7 +38,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
|
||||
|
||||
constructor(
|
||||
private logService: ILogService,
|
||||
private storageMainService: StorageMainService
|
||||
private storageMainService: IStorageMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -203,4 +203,4 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
|
||||
|
||||
dispose(this.onDidChangeItemsOnMainListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,16 @@ export interface IStorageMainService {
|
||||
*/
|
||||
readonly onWillSaveState: Event<void>;
|
||||
|
||||
/**
|
||||
* Access to all cached items of this storage service.
|
||||
*/
|
||||
readonly items: Map<string, string>;
|
||||
|
||||
/**
|
||||
* Required call to ensure the service can be used.
|
||||
*/
|
||||
initialize(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Retrieve an element stored with the given key from storage. Use
|
||||
* the provided defaultValue if the element is null or undefined.
|
||||
|
||||
@@ -16,18 +16,19 @@ import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtil
|
||||
|
||||
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> {
|
||||
const result: { [name: string]: string | undefined; } = Object.create(null);
|
||||
const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!;
|
||||
const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!;
|
||||
const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!;
|
||||
|
||||
/**
|
||||
* Note: In the web, session date information is fetched from browser storage, so these dates are tied to a specific
|
||||
* browser and not the machine overall.
|
||||
*/
|
||||
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.firstSessionDate'] = firstSessionDate;
|
||||
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.lastSessionDate'] = lastSessionDate || '';
|
||||
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
|
||||
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['common.instanceId'] = instanceId;
|
||||
// __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||
result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority);
|
||||
|
||||
|
||||
@@ -27,12 +27,16 @@ export class RelayURLService extends URLService implements IURLHandler {
|
||||
openerService.registerOpener(this);
|
||||
}
|
||||
|
||||
async open(uri: URI): Promise<boolean> {
|
||||
if (uri.scheme !== product.urlProtocol) {
|
||||
async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
|
||||
if (options && options.openExternal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await this.urlService.open(uri);
|
||||
if (resource.scheme !== product.urlProtocol) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await this.urlService.open(resource);
|
||||
}
|
||||
|
||||
handleURL(uri: URI): Promise<boolean> {
|
||||
|
||||
@@ -240,6 +240,8 @@ export interface IWindowService {
|
||||
closeWorkspace(): Promise<void>;
|
||||
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
|
||||
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
||||
// rationale: will eventually move to electron-browser
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
toggleFullScreen(target?: HTMLElement): Promise<void>;
|
||||
setRepresentedFilename(fileName: string): Promise<void>;
|
||||
getRecentlyOpened(): Promise<IRecentlyOpened>;
|
||||
|
||||
@@ -343,11 +343,12 @@ suite('WorkspacesMainService', () => {
|
||||
const untitledTwo = await createWorkspace([os.tmpdir(), process.cwd()]);
|
||||
assert.ok(fs.existsSync(untitledTwo.configPath.fsPath));
|
||||
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
|
||||
const untitledHome = dirname(dirname(untitledTwo.configPath));
|
||||
const beforeGettingUntitledWorkspaces = fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'));
|
||||
untitled = service.getUntitledWorkspacesSync();
|
||||
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
|
||||
if (untitled.length === 1) {
|
||||
const untitledHome = dirname(dirname(untitledTwo.configPath));
|
||||
assert.fail(`Unexpected workspaces count of 1 (expected 2), all workspaces:\n ${fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'))}`);
|
||||
assert.fail(`Unexpected workspaces count of 1 (expected 2), all workspaces:\n ${fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'))}, before getUntitledWorkspacesSync: ${beforeGettingUntitledWorkspaces}`);
|
||||
}
|
||||
assert.equal(2, untitled.length);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user