Proxy support for extensions (fix #69)

This commit is contained in:
Benjamin Pasero
2015-11-20 10:32:20 +01:00
parent 171f2c1008
commit e57d6db414
4 changed files with 80 additions and 47 deletions

View File

@@ -123,7 +123,7 @@ function main(ipcServer: Server, userEnv: IEnv): void {
lifecycle.manager.ready();
// Load settings
settings.manager.load();
settings.manager.loadSync();
// Propagate to clients
windows.manager.ready(userEnv);

View File

@@ -20,8 +20,8 @@ export class SettingsManager extends UserSettings {
});
}
public load(): boolean {
const settingsChanged = super.load();
public loadSync(): boolean {
const settingsChanged = super.loadSync();
// Store into global so that any renderer can access the value with remote.getGlobal()
if (settingsChanged) {

View File

@@ -12,7 +12,9 @@ import path = require('path');
import json = require('vs/base/common/json');
import objects = require('vs/base/common/objects');
import {EventProvider} from 'vs/base/common/eventProvider';
import {TPromise} from 'vs/base/common/winjs.base';
import {EventSource} from 'vs/base/common/eventSource';
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
export interface ISettings {
settings: any;
@@ -33,7 +35,7 @@ export class UserSettings {
private _onChange: EventSource<(settings: ISettings) => void>;
constructor(appSettingsPath:string, appKeybindingsPath: string) {
constructor(appSettingsPath: string, appKeybindingsPath: string) {
this.appSettingsPath = appSettingsPath;
this.appKeybindingsPath = appKeybindingsPath;
this._onChange = new EventSource<(settings: ISettings) => void>();
@@ -41,16 +43,45 @@ export class UserSettings {
this.registerWatchers();
}
public static getValue(contextService: IWorkspaceContextService, key: string, fallback?: any): TPromise<any> {
return new TPromise((c, e) => {
const appSettingsPath = contextService.getConfiguration().env.appSettingsPath;
fs.readFile(appSettingsPath, (error /* ignore */, fileContents) => {
let root = {};
let content = fileContents && fileContents.toString();
if (!content) {
content = '{}';
}
try {
let contents = json.parse(content) || {};
for (let key in contents) {
UserSettings.setNode(root, key, contents[key]);
}
return c(UserSettings.doGetValue(root, key, fallback));
} catch (error) {
return c(UserSettings.doGetValue(root, key, fallback)); // parse error
}
});
});
}
public get onChange(): EventProvider<(settings: ISettings) => void> {
return this._onChange.value;
}
public getValue(key: string, fallback?: any): any {
return UserSettings.doGetValue(this.globalSettings.settings, key, fallback);
}
private static doGetValue(globalSettings: any, key: string, fallback?: any): any {
if (!key) {
return fallback;
}
let value = this.globalSettings.settings;
let value = globalSettings;
let parts = key.split('\.');
while (parts.length && value) {
@@ -77,7 +108,7 @@ export class UserSettings {
this.timeoutHandle = global.setTimeout(() => {
// Reload
let didChange = this.load();
let didChange = this.loadSync();
// Emit event
if (didChange) {
@@ -87,8 +118,8 @@ export class UserSettings {
}, UserSettings.CHANGE_BUFFER_DELAY);
}
public load(): boolean {
let loadedSettings = this.doLoad();
public loadSync(): boolean {
let loadedSettings = this.doLoadSync();
if (!objects.equals(loadedSettings, this.globalSettings)) {
// Keep in class
@@ -100,40 +131,17 @@ export class UserSettings {
return false; // no changed value
}
private doLoad(): ISettings {
let settings = this.doLoadSettings();
private doLoadSync(): ISettings {
let settings = this.doLoadSettingsSync();
return {
settings: settings.contents,
settingsParseErrors: settings.parseErrors,
keybindings: this.doLoadKeybindings()
keybindings: this.doLoadKeybindingsSync()
};
}
private doLoadSettings(): { contents: any; parseErrors?: string[]; } {
function setNode(root: any, key: string, value: any): any {
let segments = key.split('.');
let last = segments.pop();
let curr = root;
segments.forEach((s) => {
let obj = curr[s];
switch (typeof obj) {
case 'undefined':
obj = curr[s] = {};
break;
case 'object':
break;
default:
console.log('Conflicting user settings: ' + key + ' at ' + s + ' with ' + JSON.stringify(obj));
}
curr = obj;
});
curr[last] = value;
}
private doLoadSettingsSync(): { contents: any; parseErrors?: string[]; } {
try {
let root = {};
let content = '{}';
@@ -145,7 +153,7 @@ export class UserSettings {
let contents = json.parse(content) || {};
for (let key in contents) {
setNode(root, key, contents[key]);
UserSettings.setNode(root, key, contents[key]);
}
return {
contents: root
@@ -159,7 +167,28 @@ export class UserSettings {
}
}
private doLoadKeybindings(): any {
private static setNode(root: any, key: string, value: any): any {
let segments = key.split('.');
let last = segments.pop();
let curr = root;
segments.forEach((s) => {
let obj = curr[s];
switch (typeof obj) {
case 'undefined':
obj = curr[s] = {};
break;
case 'object':
break;
default:
console.log('Conflicting user settings: ' + key + ' at ' + s + ' with ' + JSON.stringify(obj));
}
curr = obj;
});
curr[last] = value;
}
private doLoadKeybindingsSync(): any {
try {
return json.parse(fs.readFileSync(this.appKeybindingsPath).toString());
} catch (error) {

View File

@@ -16,10 +16,11 @@ import { assign } from 'vs/base/common/objects';
import { extract, buffer } from 'vs/base/node/zip';
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import { IExtensionsService, IExtension, IExtensionManifest, IGalleryInformation } from 'vs/workbench/parts/extensions/common/extensions';
import { download } from 'vs/base/node/request';
import { download, getProxyAgent, getSystemProxyAgent } from 'vs/base/node/request';
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
import { Limiter } from 'vs/base/common/async';
import Event, { Emitter } from 'vs/base/common/event';
import { UserSettings } from 'vs/workbench/node/userSettings';
function parseManifest(raw: string): TPromise<IExtensionManifest> {
return new Promise((c, e) => {
@@ -120,15 +121,18 @@ export class ExtensionsService implements IExtensionsService {
const extensionPath = path.join(this.extensionsPath, `${ extension.publisher }.${ extension.name }`);
const manifestPath = path.join(extensionPath, 'package.json');
return download(zipPath, { url })
.then(() => validate(zipPath, extension))
.then(manifest => { this._onInstallExtension.fire(manifest); return manifest; })
.then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest))
.then(manifest => {
manifest = assign({ __metadata: galleryInformation }, manifest);
return pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'));
})
.then(() => { this._onDidInstallExtension.fire(extension); return extension; });
return UserSettings.getValue(this.contextService, 'http.proxy').then((httpProxySettings) => {
const getAgent = url => httpProxySettings ? getProxyAgent(url, httpProxySettings) : getSystemProxyAgent(url);
return download(zipPath, { url: url, agent: getAgent(url) })
.then(() => validate(zipPath, extension))
.then(manifest => { this._onInstallExtension.fire(manifest); return manifest; })
.then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest))
.then(manifest => {
manifest = assign({ __metadata: galleryInformation }, manifest);
return pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'));
})
.then(() => { this._onDidInstallExtension.fire(extension); return extension; });
});
}
private installFromZip(zipPath: string): TPromise<IExtension> {