Archived
1
0

Extra extensions directories (#694)

* Allow setting paths for builtin exts and extra dirs

The extra directories aren't used yet, just available from the
environment service and to the shared process.

* Utilize extra builtin extensions path

* Utilize extra extensions directory

* Fix cached mtimes for extra extension dirs

* Simplify extension cache equality check
This commit is contained in:
Asher
2019-05-19 17:58:47 -05:00
committed by GitHub
parent 8256252967
commit aa1474b675
12 changed files with 341 additions and 13 deletions

View File

@ -278,6 +278,8 @@ export class Client {
shell: init.getShell(),
extensionsDirectory: init.getExtensionsDirectory(),
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
extraExtensionDirectories: init.getExtraExtensionDirectoriesList(),
extraBuiltinExtensionDirectories: init.getExtraBuiltinExtensionDirectoriesList(),
};
this.initDataEmitter.emit(this._initData);
break;

View File

@ -25,6 +25,8 @@ export interface InitData {
readonly shell: string;
readonly extensionsDirectory: string;
readonly builtInExtensionsDirectory: string;
readonly extraExtensionDirectories: string[];
readonly extraBuiltinExtensionDirectories: string[];
}
export interface SharedProcessData {

View File

@ -15,6 +15,8 @@ export interface ServerOptions {
readonly cacheDirectory: string;
readonly builtInExtensionsDirectory: string;
readonly extensionsDirectory: string;
readonly extraExtensionDirectories?: string[];
readonly extraBuiltinExtensionDirectories?: string[];
readonly fork?: ForkProvider;
}
@ -99,6 +101,8 @@ export class Server {
initMsg.setTmpDirectory(os.tmpdir());
initMsg.setOperatingSystem(platformToProto(os.platform()));
initMsg.setShell(os.userInfo().shell || global.process.env.SHELL || "");
initMsg.setExtraExtensionDirectoriesList(this.options.extraExtensionDirectories || []);
initMsg.setExtraBuiltinExtensionDirectoriesList(this.options.extraBuiltinExtensionDirectories || []);
const srvMsg = new ServerMessage();
srvMsg.setInit(initMsg);
connection.send(srvMsg.serializeBinary());

View File

@ -42,4 +42,6 @@ message WorkingInit {
string shell = 6;
string builtin_extensions_dir = 7;
string extensions_directory = 8;
repeated string extra_extension_directories = 9;
repeated string extra_builtin_extension_directories = 10;
}

View File

@ -135,6 +135,16 @@ export class WorkingInit extends jspb.Message {
getExtensionsDirectory(): string;
setExtensionsDirectory(value: string): void;
clearExtraExtensionDirectoriesList(): void;
getExtraExtensionDirectoriesList(): Array<string>;
setExtraExtensionDirectoriesList(value: Array<string>): void;
addExtraExtensionDirectories(value: string, index?: number): string;
clearExtraBuiltinExtensionDirectoriesList(): void;
getExtraBuiltinExtensionDirectoriesList(): Array<string>;
setExtraBuiltinExtensionDirectoriesList(value: Array<string>): void;
addExtraBuiltinExtensionDirectories(value: string, index?: number): string;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): WorkingInit.AsObject;
static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
@ -155,6 +165,8 @@ export namespace WorkingInit {
shell: string,
builtinExtensionsDir: string,
extensionsDirectory: string,
extraExtensionDirectoriesList: Array<string>,
extraBuiltinExtensionDirectoriesList: Array<string>,
}
export enum OperatingSystem {

View File

@ -72,7 +72,7 @@ if (goog.DEBUG && !COMPILED) {
* @constructor
*/
proto.WorkingInit = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
jspb.Message.initialize(this, opt_data, 0, -1, proto.WorkingInit.repeatedFields_, null);
};
goog.inherits(proto.WorkingInit, jspb.Message);
if (goog.DEBUG && !COMPILED) {
@ -759,6 +759,13 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() {
/**
* List of repeated fields within this message type.
* @private {!Array<number>}
* @const
*/
proto.WorkingInit.repeatedFields_ = [9,10];
if (jspb.Message.GENERATE_TO_OBJECT) {
@ -795,7 +802,9 @@ proto.WorkingInit.toObject = function(includeInstance, msg) {
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
shell: jspb.Message.getFieldWithDefault(msg, 6, ""),
builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, ""),
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, "")
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, ""),
extraExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 9),
extraBuiltinExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 10)
};
if (includeInstance) {
@ -864,6 +873,14 @@ proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) {
var value = /** @type {string} */ (reader.readString());
msg.setExtensionsDirectory(value);
break;
case 9:
var value = /** @type {string} */ (reader.readString());
msg.addExtraExtensionDirectories(value);
break;
case 10:
var value = /** @type {string} */ (reader.readString());
msg.addExtraBuiltinExtensionDirectories(value);
break;
default:
reader.skipField();
break;
@ -949,6 +966,20 @@ proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
f
);
}
f = message.getExtraExtensionDirectoriesList();
if (f.length > 0) {
writer.writeRepeatedString(
9,
f
);
}
f = message.getExtraBuiltinExtensionDirectoriesList();
if (f.length > 0) {
writer.writeRepeatedString(
10,
f
);
}
};
@ -1081,4 +1112,68 @@ proto.WorkingInit.prototype.setExtensionsDirectory = function(value) {
};
/**
* repeated string extra_extension_directories = 9;
* @return {!Array<string>}
*/
proto.WorkingInit.prototype.getExtraExtensionDirectoriesList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 9));
};
/** @param {!Array<string>} value */
proto.WorkingInit.prototype.setExtraExtensionDirectoriesList = function(value) {
jspb.Message.setField(this, 9, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
*/
proto.WorkingInit.prototype.addExtraExtensionDirectories = function(value, opt_index) {
jspb.Message.addToRepeatedField(this, 9, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
*/
proto.WorkingInit.prototype.clearExtraExtensionDirectoriesList = function() {
this.setExtraExtensionDirectoriesList([]);
};
/**
* repeated string extra_builtin_extension_directories = 10;
* @return {!Array<string>}
*/
proto.WorkingInit.prototype.getExtraBuiltinExtensionDirectoriesList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 10));
};
/** @param {!Array<string>} value */
proto.WorkingInit.prototype.setExtraBuiltinExtensionDirectoriesList = function(value) {
jspb.Message.setField(this, 10, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
*/
proto.WorkingInit.prototype.addExtraBuiltinExtensionDirectories = function(value, opt_index) {
jspb.Message.addToRepeatedField(this, 10, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
*/
proto.WorkingInit.prototype.clearExtraBuiltinExtensionDirectoriesList = function() {
this.setExtraBuiltinExtensionDirectoriesList([]);
};
goog.object.extend(exports, proto);

View File

@ -3,9 +3,11 @@ import { createClient } from "./helpers";
describe("Server", () => {
const dataDirectory = "/tmp/example";
const workingDirectory = "/working/dir";
const extensionsDirectory = "/tmp/example";
const builtInExtensionsDirectory = "/tmp/example";
const cacheDirectory = "/tmp/cache";
const client = createClient({
extensionsDirectory,
builtInExtensionsDirectory,
cacheDirectory,
dataDirectory,

View File

@ -16,13 +16,20 @@ import opn = require("opn");
import * as commander from "commander";
const collect = <T>(value: T, previous: T[]): T[] => {
return previous.concat(value);
};
commander.version(process.env.VERSION || "development")
.name("code-server")
.description("Run VS Code on a remote server.")
.option("--cert <value>")
.option("--cert-key <value>")
.option("-e, --extensions-dir <dir>", "Set the root path for extensions.")
.option("-d --user-data-dir <dir>", " Specifies the directory that user data is kept in, useful when running as root.")
.option("-e, --extensions-dir <dir>", "Override the main default path for user extensions.")
.option("--builtin-extensions-dir <dir>", "Override the main default path for built-in extensions.")
.option("--extra-extensions-dir [dir]", "Path to an extra user extension directory (repeatable).", collect, [])
.option("--extra-builtin-extensions-dir [dir]", "Path to an extra built-in extension directory (repeatable).", collect, [])
.option("-d --user-data-dir <dir>", "Specifies the directory that user data is kept in, useful when running as root.")
.option("--data-dir <value>", "DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.")
.option("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
.option("-o, --open", "Open in the browser on startup.", false)
@ -59,6 +66,9 @@ const bold = (text: string | number): string | number => {
readonly userDataDir?: string;
readonly extensionsDir?: string;
readonly builtinExtensionsDir?: string;
readonly extraExtensionsDir?: string[];
readonly extraBuiltinExtensionsDir?: string[];
readonly dataDir?: string;
readonly password?: string;
@ -84,6 +94,10 @@ const bold = (text: string | number): string | number => {
const dataDir = path.resolve(options.userDataDir || options.dataDir || path.join(dataHome, "code-server"));
const extensionsDir = options.extensionsDir ? path.resolve(options.extensionsDir) : path.resolve(dataDir, "extensions");
const builtInExtensionsDir = options.builtinExtensionsDir ? path.resolve(options.builtinExtensionsDir)
: path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
const extraExtensionDirs = options.extraExtensionsDir ? options.extraExtensionsDir.map((p) => path.resolve(p)) : [];
const extraBuiltinExtensionDirs = options.extraBuiltinExtensionsDir ? options.extraBuiltinExtensionsDir.map((p) => path.resolve(p)) : [];
const workingDir = path.resolve(args[0] || process.cwd());
const dependenciesDir = path.join(os.tmpdir(), "code-server/dependencies");
@ -99,8 +113,11 @@ const bold = (text: string | number): string | number => {
fse.mkdirp(cacheHome),
fse.mkdirp(dataDir),
fse.mkdirp(extensionsDir),
fse.mkdirp(builtInExtensionsDir),
fse.mkdirp(workingDir),
fse.mkdirp(dependenciesDir),
...extraExtensionDirs.map((p) => fse.mkdirp(p)),
...extraBuiltinExtensionDirs.map((p) => fse.mkdirp(p)),
]);
const unpackExecutable = (binaryName: string): void => {
@ -116,7 +133,6 @@ const bold = (text: string | number): string | number => {
// tslint:disable-next-line no-any
(<any>global).RIPGREP_LOCATION = path.join(dependenciesDir, "rg");
const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
if (options.bootstrapFork) {
const modulePath = options.bootstrapFork;
if (!modulePath) {
@ -192,7 +208,7 @@ const bold = (text: string | number): string | number => {
// TODO: fill in appropriate doc url
logger.info("Additional documentation: http://github.com/cdr/code-server");
logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir, extraExtensionDirs, extraBuiltinExtensionDirs);
const sendSharedProcessReady = (socket: WebSocket): void => {
const active = new SharedProcessActive();
active.setSocketPath(sharedProcess.socketPath);
@ -247,6 +263,8 @@ const bold = (text: string | number): string | number => {
serverOptions: {
extensionsDirectory: extensionsDir,
builtInExtensionsDirectory: builtInExtensionsDir,
extraExtensionDirectories: extraExtensionDirs,
extraBuiltinExtensionDirectories: extraBuiltinExtensionDirs,
dataDirectory: dataDir,
workingDirectory: workingDir,
cacheDirectory: cacheHome,

View File

@ -39,6 +39,8 @@ export class SharedProcess {
private readonly userDataDir: string,
private readonly extensionsDir: string,
private readonly builtInExtensionsDir: string,
private readonly extraExtensionDirs: string[],
private readonly extraBuiltinExtensionDirs: string[],
) {
this.retry.run();
}
@ -134,6 +136,8 @@ export class SharedProcess {
"builtin-extensions-dir": this.builtInExtensionsDir,
"user-data-dir": this.userDataDir,
"extensions-dir": this.extensionsDir,
"extra-extension-dirs": this.extraExtensionDirs,
"extra-builtin-extension-dirs": this.extraBuiltinExtensionDirs,
},
logLevel: this.logger.level,
sharedIPCHandle: this.socketPath,

View File

@ -12,6 +12,18 @@ export class EnvironmentService extends environment.EnvironmentService {
public get extensionsPath(): string {
return paths.getExtensionsDirectory();
}
public get builtinExtensionsPath(): string {
return paths.getBuiltInExtensionsDirectory();
}
public get extraExtensionPaths(): string[] {
return paths.getExtraExtensionDirectories();
}
public get extraBuiltinExtensionPaths(): string[] {
return paths.getExtraBuiltinExtensionDirectories();
}
}
const target = environment as typeof environment;

View File

@ -1,5 +1,8 @@
import { InitData, SharedProcessData } from "@coder/protocol";
/**
* Provides paths.
*/
class Paths {
private _appData: string | undefined;
private _defaultUserData: string | undefined;
@ -7,6 +10,8 @@ class Paths {
private _extensionsDirectory: string | undefined;
private _builtInExtensionsDirectory: string | undefined;
private _workingDirectory: string | undefined;
private _extraExtensionDirectories: string[] | undefined;
private _extraBuiltinExtensionDirectories: string[] | undefined;
public get appData(): string {
if (typeof this._appData === "undefined") {
@ -48,6 +53,22 @@ class Paths {
return this._builtInExtensionsDirectory;
}
public get extraExtensionDirectories(): string[] {
if (!this._extraExtensionDirectories) {
throw new Error("trying to access extra extension directories before they have been set");
}
return this._extraExtensionDirectories;
}
public get extraBuiltinExtensionDirectories(): string[] {
if (!this._extraBuiltinExtensionDirectories) {
throw new Error("trying to access extra builtin extension directories before they have been set");
}
return this._extraBuiltinExtensionDirectories;
}
public get workingDirectory(): string {
if (!this._workingDirectory) {
throw new Error("trying to access working directory before it has been set");
@ -56,6 +77,9 @@ class Paths {
return this._workingDirectory;
}
/**
* Initialize paths using the provided data.
*/
public initialize(data: InitData, sharedData: SharedProcessData): void {
process.env.VSCODE_LOGS = sharedData.logPath;
this._appData = data.dataDirectory;
@ -64,6 +88,8 @@ class Paths {
this._extensionsDirectory = data.extensionsDirectory;
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
this._workingDirectory = data.workingDirectory;
this._extraExtensionDirectories = data.extraExtensionDirectories;
this._extraBuiltinExtensionDirectories = data.extraBuiltinExtensionDirectories;
}
}
@ -73,4 +99,6 @@ export const getDefaultUserDataPath = (): string => _paths.defaultUserData;
export const getWorkingDirectory = (): string => _paths.workingDirectory;
export const getExtensionsDirectory = (): string => _paths.extensionsDirectory;
export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory;
export const getExtraExtensionDirectories = (): string[] => _paths.extraExtensionDirectories;
export const getExtraBuiltinExtensionDirectories = (): string[] => _paths.extraBuiltinExtensionDirectories;
export const getSocketPath = (): string => _paths.socketPath;