diff --git a/packages/protocol/src/browser/client.ts b/packages/protocol/src/browser/client.ts index b420a863..3a78e787 100644 --- a/packages/protocol/src/browser/client.ts +++ b/packages/protocol/src/browser/client.ts @@ -271,6 +271,7 @@ export class Client { workingDirectory: init.getWorkingDirectory(), os: protoToOperatingSystem(init.getOperatingSystem()), shell: init.getShell(), + extensionsDirectory: init.getExtensionsDirectory(), builtInExtensionsDirectory: init.getBuiltinExtensionsDir(), }; this.initDataEmitter.emit(this._initData); diff --git a/packages/protocol/src/common/connection.ts b/packages/protocol/src/common/connection.ts index 0c53817a..f4f60ded 100644 --- a/packages/protocol/src/common/connection.ts +++ b/packages/protocol/src/common/connection.ts @@ -23,6 +23,7 @@ export interface InitData { readonly homeDirectory: string; readonly tmpDirectory: string; readonly shell: string; + readonly extensionsDirectory: string; readonly builtInExtensionsDirectory: string; } diff --git a/packages/protocol/src/node/server.ts b/packages/protocol/src/node/server.ts index 7c0de701..0f24cd58 100644 --- a/packages/protocol/src/node/server.ts +++ b/packages/protocol/src/node/server.ts @@ -14,6 +14,7 @@ export interface ServerOptions { readonly dataDirectory: string; readonly cacheDirectory: string; readonly builtInExtensionsDirectory: string; + readonly extensionsDirectory: string; readonly fork?: ForkProvider; } @@ -93,6 +94,7 @@ export class Server { initMsg.setDataDirectory(this.options.dataDirectory); initMsg.setWorkingDirectory(this.options.workingDirectory); initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory); + initMsg.setExtensionsDirectory(this.options.extensionsDirectory); initMsg.setHomeDirectory(os.homedir()); initMsg.setTmpDirectory(os.tmpdir()); initMsg.setOperatingSystem(platformToProto(os.platform())); diff --git a/packages/protocol/src/proto/client.proto b/packages/protocol/src/proto/client.proto index b0b5d858..4681ecf6 100644 --- a/packages/protocol/src/proto/client.proto +++ b/packages/protocol/src/proto/client.proto @@ -41,4 +41,5 @@ message WorkingInit { OperatingSystem operating_system = 5; string shell = 6; string builtin_extensions_dir = 7; + string extensions_directory = 8; } diff --git a/packages/protocol/src/proto/client_pb.d.ts b/packages/protocol/src/proto/client_pb.d.ts index 5306f7d9..9c4c1dd5 100644 --- a/packages/protocol/src/proto/client_pb.d.ts +++ b/packages/protocol/src/proto/client_pb.d.ts @@ -132,6 +132,9 @@ export class WorkingInit extends jspb.Message { getBuiltinExtensionsDir(): string; setBuiltinExtensionsDir(value: string): void; + getExtensionsDirectory(): string; + setExtensionsDirectory(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): WorkingInit.AsObject; static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject; @@ -151,6 +154,7 @@ export namespace WorkingInit { operatingSystem: WorkingInit.OperatingSystem, shell: string, builtinExtensionsDir: string, + extensionsDirectory: string, } export enum OperatingSystem { diff --git a/packages/protocol/src/proto/client_pb.js b/packages/protocol/src/proto/client_pb.js index d98a648d..20bf41ea 100644 --- a/packages/protocol/src/proto/client_pb.js +++ b/packages/protocol/src/proto/client_pb.js @@ -794,7 +794,8 @@ proto.WorkingInit.toObject = function(includeInstance, msg) { workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""), operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0), shell: jspb.Message.getFieldWithDefault(msg, 6, ""), - builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, "") + builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, ""), + extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, "") }; if (includeInstance) { @@ -859,6 +860,10 @@ proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {string} */ (reader.readString()); msg.setBuiltinExtensionsDir(value); break; + case 8: + var value = /** @type {string} */ (reader.readString()); + msg.setExtensionsDirectory(value); + break; default: reader.skipField(); break; @@ -937,6 +942,13 @@ proto.WorkingInit.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getExtensionsDirectory(); + if (f.length > 0) { + writer.writeString( + 8, + f + ); + } }; @@ -1054,4 +1066,19 @@ proto.WorkingInit.prototype.setBuiltinExtensionsDir = function(value) { }; +/** + * optional string extensions_directory = 8; + * @return {string} + */ +proto.WorkingInit.prototype.getExtensionsDirectory = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 8, "")); +}; + + +/** @param {string} value */ +proto.WorkingInit.prototype.setExtensionsDirectory = function(value) { + jspb.Message.setProto3StringField(this, 8, value); +}; + + goog.object.extend(exports, proto); diff --git a/packages/server/package.json b/packages/server/package.json index 5244242f..a20ba976 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -9,7 +9,7 @@ "build:binary": "ts-node scripts/nbin.ts" }, "dependencies": { - "@coder/nbin": "^1.0.4", + "@coder/nbin": "^1.0.5", "commander": "^2.19.0", "express": "^4.16.4", "express-static-gzip": "^1.1.3", diff --git a/packages/server/src/cli.ts b/packages/server/src/cli.ts index d2a3505b..79010628 100644 --- a/packages/server/src/cli.ts +++ b/packages/server/src/cli.ts @@ -21,7 +21,9 @@ commander.version(process.env.VERSION || "development") .description("Run VS Code on a remote server.") .option("--cert ") .option("--cert-key ") - .option("-d, --data-dir ", "Customize where user-data is stored.") + .option("-e, --extensions-dir ", "Set the root path for extensions.") + .option("-d --user-data-dir ", " Specifies the directory that user data is kept in, useful when running as root.") + .option("--data-dir ", "DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.") .option("-h, --host ", "Customize the hostname.", "0.0.0.0") .option("-o, --open", "Open in the browser on startup.", false) .option("-p, --port ", "Port to bind on.", 8443) @@ -51,6 +53,9 @@ const bold = (text: string | number): string | number => { readonly host: string; readonly port: number; + readonly userDataDir?: string; + readonly extensionsDir?: string; + readonly dataDir?: string; readonly password?: string; readonly open?: boolean; @@ -67,7 +72,8 @@ const bold = (text: string | number): string | number => { const noAuthValue = (commander as any).auth; options.noAuth = !noAuthValue; - const dataDir = path.resolve(options.dataDir || path.join(dataHome, "code-server")); + 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 workingDir = path.resolve(args[0] || process.cwd()); if (!fs.existsSync(dataDir)) { @@ -81,6 +87,7 @@ const bold = (text: string | number): string | number => { await Promise.all([ fse.mkdirp(cacheHome), fse.mkdirp(dataDir), + fse.mkdirp(extensionsDir), fse.mkdirp(workingDir), ]); @@ -144,10 +151,15 @@ const bold = (text: string | number): string | number => { } logger.info(`\u001B[1mcode-server ${process.env.VERSION ? `v${process.env.VERSION}` : "development"}`); + + if (options.dataDir) { + logger.warn('"--data-dir" is deprecated. Use "--user-data-dir" instead.'); + } + // TODO: fill in appropriate doc url logger.info("Additional documentation: http://github.com/codercom/code-server"); - logger.info("Initializing", field("data-dir", dataDir), field("working-dir", workingDir), field("log-dir", logDir)); - const sharedProcess = new SharedProcess(dataDir, builtInExtensionsDir); + 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 sendSharedProcessReady = (socket: WebSocket): void => { const active = new SharedProcessActive(); active.setSocketPath(sharedProcess.socketPath); @@ -196,6 +208,7 @@ const bold = (text: string | number): string | number => { } }, serverOptions: { + extensionsDirectory: extensionsDir, builtInExtensionsDirectory: builtInExtensionsDir, dataDirectory: dataDir, workingDirectory: workingDir, diff --git a/packages/server/src/vscode/sharedProcess.ts b/packages/server/src/vscode/sharedProcess.ts index a3c8e778..4f83ba27 100644 --- a/packages/server/src/vscode/sharedProcess.ts +++ b/packages/server/src/vscode/sharedProcess.ts @@ -38,6 +38,7 @@ export class SharedProcess { public constructor( private readonly userDataDir: string, + private readonly extensionsDir: string, private readonly builtInExtensionsDir: string, ) { this.retry.run(); @@ -95,10 +96,8 @@ export class SharedProcess { this.activeProcess.kill(); } - const extensionsDir = path.join(this.userDataDir, "extensions"); const backupsDir = path.join(this.userDataDir, "Backups"); await Promise.all([ - fse.mkdirp(extensionsDir), fse.mkdirp(backupsDir), ]); @@ -141,7 +140,7 @@ export class SharedProcess { args: { "builtin-extensions-dir": this.builtInExtensionsDir, "user-data-dir": this.userDataDir, - "extensions-dir": extensionsDir, + "extensions-dir": this.extensionsDir, }, logLevel: this.logger.level, sharedIPCHandle: this.socketPath, diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index fbff8651..a1ca67b7 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8" integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA== -"@coder/nbin@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.4.tgz#13a3d110fe116ed5d5fdbd1384f0335745dfd859" - integrity sha512-mtd5hzPHWBwKpTCYdJdLdiY4CFCEb8HUtv3NgH8SSLFiPDwY7H1UlpqeamIty27NZ+9NLnrBd/DfaE3aVo7rxQ== +"@coder/nbin@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.5.tgz#6a9e9982eb179d6bcc9c2e7dfebb608b7c4605d9" + integrity sha512-rai1/WgvH2j8SlRweOSk0JmrAzBx8bc22P+pThnPHj5terd0GScshqNR3EIoL/cdC2Ii4wjfOYodYbl/QynYGg== dependencies: "@coder/logger" "^1.0.3" fs-extra "^7.0.1" diff --git a/packages/vscode/src/fill/environmentService.ts b/packages/vscode/src/fill/environmentService.ts index c585de13..9f86d8a7 100644 --- a/packages/vscode/src/fill/environmentService.ts +++ b/packages/vscode/src/fill/environmentService.ts @@ -8,7 +8,7 @@ export class EnvironmentService extends environment.EnvironmentService { } public get extensionsPath(): string { - return path.join(paths.getAppDataPath(), "extensions"); + return paths.getExtensionsDirectory(); } } diff --git a/packages/vscode/src/fill/paths.ts b/packages/vscode/src/fill/paths.ts index 393d9861..ed284fb3 100644 --- a/packages/vscode/src/fill/paths.ts +++ b/packages/vscode/src/fill/paths.ts @@ -4,6 +4,7 @@ class Paths { private _appData: string | undefined; private _defaultUserData: string | undefined; private _socketPath: string | undefined; + private _extensionsDirectory: string | undefined; private _builtInExtensionsDirectory: string | undefined; private _workingDirectory: string | undefined; @@ -31,6 +32,14 @@ class Paths { return this._socketPath; } + public get extensionsDirectory(): string { + if (!this._extensionsDirectory) { + throw new Error("trying to access extensions directory before it has been set"); + } + + return this._extensionsDirectory; + } + public get builtInExtensionsDirectory(): string { if (!this._builtInExtensionsDirectory) { throw new Error("trying to access builtin extensions directory before it has been set"); @@ -52,6 +61,7 @@ class Paths { this._appData = data.dataDirectory; this._defaultUserData = data.dataDirectory; this._socketPath = sharedData.socketPath; + this._extensionsDirectory = data.extensionsDirectory; this._builtInExtensionsDirectory = data.builtInExtensionsDirectory; this._workingDirectory = data.workingDirectory; } @@ -61,5 +71,6 @@ export const _paths = new Paths(); export const getAppDataPath = (): string => _paths.appData; 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 getSocketPath = (): string => _paths.socketPath;