Add flags for customizing user data dir and extensions dir (#420)

* Add flags for customizing extensions directory

* Update @coder/nbin
This commit is contained in:
Kyle Carberry 2019-04-03 17:07:47 -05:00 committed by Asher
parent c607015a26
commit 4af84fcaf6
12 changed files with 73 additions and 14 deletions

View File

@ -271,6 +271,7 @@ export class Client {
workingDirectory: init.getWorkingDirectory(), workingDirectory: init.getWorkingDirectory(),
os: protoToOperatingSystem(init.getOperatingSystem()), os: protoToOperatingSystem(init.getOperatingSystem()),
shell: init.getShell(), shell: init.getShell(),
extensionsDirectory: init.getExtensionsDirectory(),
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(), builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
}; };
this.initDataEmitter.emit(this._initData); this.initDataEmitter.emit(this._initData);

View File

@ -23,6 +23,7 @@ export interface InitData {
readonly homeDirectory: string; readonly homeDirectory: string;
readonly tmpDirectory: string; readonly tmpDirectory: string;
readonly shell: string; readonly shell: string;
readonly extensionsDirectory: string;
readonly builtInExtensionsDirectory: string; readonly builtInExtensionsDirectory: string;
} }

View File

@ -14,6 +14,7 @@ export interface ServerOptions {
readonly dataDirectory: string; readonly dataDirectory: string;
readonly cacheDirectory: string; readonly cacheDirectory: string;
readonly builtInExtensionsDirectory: string; readonly builtInExtensionsDirectory: string;
readonly extensionsDirectory: string;
readonly fork?: ForkProvider; readonly fork?: ForkProvider;
} }
@ -93,6 +94,7 @@ export class Server {
initMsg.setDataDirectory(this.options.dataDirectory); initMsg.setDataDirectory(this.options.dataDirectory);
initMsg.setWorkingDirectory(this.options.workingDirectory); initMsg.setWorkingDirectory(this.options.workingDirectory);
initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory); initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory);
initMsg.setExtensionsDirectory(this.options.extensionsDirectory);
initMsg.setHomeDirectory(os.homedir()); initMsg.setHomeDirectory(os.homedir());
initMsg.setTmpDirectory(os.tmpdir()); initMsg.setTmpDirectory(os.tmpdir());
initMsg.setOperatingSystem(platformToProto(os.platform())); initMsg.setOperatingSystem(platformToProto(os.platform()));

View File

@ -41,4 +41,5 @@ message WorkingInit {
OperatingSystem operating_system = 5; OperatingSystem operating_system = 5;
string shell = 6; string shell = 6;
string builtin_extensions_dir = 7; string builtin_extensions_dir = 7;
string extensions_directory = 8;
} }

View File

@ -132,6 +132,9 @@ export class WorkingInit extends jspb.Message {
getBuiltinExtensionsDir(): string; getBuiltinExtensionsDir(): string;
setBuiltinExtensionsDir(value: string): void; setBuiltinExtensionsDir(value: string): void;
getExtensionsDirectory(): string;
setExtensionsDirectory(value: string): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): WorkingInit.AsObject; toObject(includeInstance?: boolean): WorkingInit.AsObject;
static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject; static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
@ -151,6 +154,7 @@ export namespace WorkingInit {
operatingSystem: WorkingInit.OperatingSystem, operatingSystem: WorkingInit.OperatingSystem,
shell: string, shell: string,
builtinExtensionsDir: string, builtinExtensionsDir: string,
extensionsDirectory: string,
} }
export enum OperatingSystem { export enum OperatingSystem {

View File

@ -794,7 +794,8 @@ proto.WorkingInit.toObject = function(includeInstance, msg) {
workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""), workingDirectory: jspb.Message.getFieldWithDefault(msg, 4, ""),
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0), operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
shell: jspb.Message.getFieldWithDefault(msg, 6, ""), 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) { if (includeInstance) {
@ -859,6 +860,10 @@ proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) {
var value = /** @type {string} */ (reader.readString()); var value = /** @type {string} */ (reader.readString());
msg.setBuiltinExtensionsDir(value); msg.setBuiltinExtensionsDir(value);
break; break;
case 8:
var value = /** @type {string} */ (reader.readString());
msg.setExtensionsDirectory(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@ -937,6 +942,13 @@ proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
f 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); goog.object.extend(exports, proto);

View File

@ -9,7 +9,7 @@
"build:binary": "ts-node scripts/nbin.ts" "build:binary": "ts-node scripts/nbin.ts"
}, },
"dependencies": { "dependencies": {
"@coder/nbin": "^1.0.4", "@coder/nbin": "^1.0.5",
"commander": "^2.19.0", "commander": "^2.19.0",
"express": "^4.16.4", "express": "^4.16.4",
"express-static-gzip": "^1.1.3", "express-static-gzip": "^1.1.3",

View File

@ -21,7 +21,9 @@ commander.version(process.env.VERSION || "development")
.description("Run VS Code on a remote server.") .description("Run VS Code on a remote server.")
.option("--cert <value>") .option("--cert <value>")
.option("--cert-key <value>") .option("--cert-key <value>")
.option("-d, --data-dir <value>", "Customize where user-data is stored.") .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("--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("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
.option("-o, --open", "Open in the browser on startup.", false) .option("-o, --open", "Open in the browser on startup.", false)
.option("-p, --port <number>", "Port to bind on.", 8443) .option("-p, --port <number>", "Port to bind on.", 8443)
@ -51,6 +53,9 @@ const bold = (text: string | number): string | number => {
readonly host: string; readonly host: string;
readonly port: number; readonly port: number;
readonly userDataDir?: string;
readonly extensionsDir?: string;
readonly dataDir?: string; readonly dataDir?: string;
readonly password?: string; readonly password?: string;
readonly open?: boolean; readonly open?: boolean;
@ -67,7 +72,8 @@ const bold = (text: string | number): string | number => {
const noAuthValue = (commander as any).auth; const noAuthValue = (commander as any).auth;
options.noAuth = !noAuthValue; 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()); const workingDir = path.resolve(args[0] || process.cwd());
if (!fs.existsSync(dataDir)) { if (!fs.existsSync(dataDir)) {
@ -81,6 +87,7 @@ const bold = (text: string | number): string | number => {
await Promise.all([ await Promise.all([
fse.mkdirp(cacheHome), fse.mkdirp(cacheHome),
fse.mkdirp(dataDir), fse.mkdirp(dataDir),
fse.mkdirp(extensionsDir),
fse.mkdirp(workingDir), 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"}`); 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 // TODO: fill in appropriate doc url
logger.info("Additional documentation: http://github.com/codercom/code-server"); 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)); logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
const sharedProcess = new SharedProcess(dataDir, builtInExtensionsDir); const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
const sendSharedProcessReady = (socket: WebSocket): void => { const sendSharedProcessReady = (socket: WebSocket): void => {
const active = new SharedProcessActive(); const active = new SharedProcessActive();
active.setSocketPath(sharedProcess.socketPath); active.setSocketPath(sharedProcess.socketPath);
@ -196,6 +208,7 @@ const bold = (text: string | number): string | number => {
} }
}, },
serverOptions: { serverOptions: {
extensionsDirectory: extensionsDir,
builtInExtensionsDirectory: builtInExtensionsDir, builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir, dataDirectory: dataDir,
workingDirectory: workingDir, workingDirectory: workingDir,

View File

@ -38,6 +38,7 @@ export class SharedProcess {
public constructor( public constructor(
private readonly userDataDir: string, private readonly userDataDir: string,
private readonly extensionsDir: string,
private readonly builtInExtensionsDir: string, private readonly builtInExtensionsDir: string,
) { ) {
this.retry.run(); this.retry.run();
@ -95,10 +96,8 @@ export class SharedProcess {
this.activeProcess.kill(); this.activeProcess.kill();
} }
const extensionsDir = path.join(this.userDataDir, "extensions");
const backupsDir = path.join(this.userDataDir, "Backups"); const backupsDir = path.join(this.userDataDir, "Backups");
await Promise.all([ await Promise.all([
fse.mkdirp(extensionsDir),
fse.mkdirp(backupsDir), fse.mkdirp(backupsDir),
]); ]);
@ -141,7 +140,7 @@ export class SharedProcess {
args: { args: {
"builtin-extensions-dir": this.builtInExtensionsDir, "builtin-extensions-dir": this.builtInExtensionsDir,
"user-data-dir": this.userDataDir, "user-data-dir": this.userDataDir,
"extensions-dir": extensionsDir, "extensions-dir": this.extensionsDir,
}, },
logLevel: this.logger.level, logLevel: this.logger.level,
sharedIPCHandle: this.socketPath, sharedIPCHandle: this.socketPath,

View File

@ -7,10 +7,10 @@
resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8" resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8"
integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA== integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA==
"@coder/nbin@^1.0.4": "@coder/nbin@^1.0.5":
version "1.0.4" version "1.0.5"
resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.4.tgz#13a3d110fe116ed5d5fdbd1384f0335745dfd859" resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.5.tgz#6a9e9982eb179d6bcc9c2e7dfebb608b7c4605d9"
integrity sha512-mtd5hzPHWBwKpTCYdJdLdiY4CFCEb8HUtv3NgH8SSLFiPDwY7H1UlpqeamIty27NZ+9NLnrBd/DfaE3aVo7rxQ== integrity sha512-rai1/WgvH2j8SlRweOSk0JmrAzBx8bc22P+pThnPHj5terd0GScshqNR3EIoL/cdC2Ii4wjfOYodYbl/QynYGg==
dependencies: dependencies:
"@coder/logger" "^1.0.3" "@coder/logger" "^1.0.3"
fs-extra "^7.0.1" fs-extra "^7.0.1"

View File

@ -8,7 +8,7 @@ export class EnvironmentService extends environment.EnvironmentService {
} }
public get extensionsPath(): string { public get extensionsPath(): string {
return path.join(paths.getAppDataPath(), "extensions"); return paths.getExtensionsDirectory();
} }
} }

View File

@ -4,6 +4,7 @@ class Paths {
private _appData: string | undefined; private _appData: string | undefined;
private _defaultUserData: string | undefined; private _defaultUserData: string | undefined;
private _socketPath: string | undefined; private _socketPath: string | undefined;
private _extensionsDirectory: string | undefined;
private _builtInExtensionsDirectory: string | undefined; private _builtInExtensionsDirectory: string | undefined;
private _workingDirectory: string | undefined; private _workingDirectory: string | undefined;
@ -31,6 +32,14 @@ class Paths {
return this._socketPath; 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 { public get builtInExtensionsDirectory(): string {
if (!this._builtInExtensionsDirectory) { if (!this._builtInExtensionsDirectory) {
throw new Error("trying to access builtin extensions directory before it has been set"); 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._appData = data.dataDirectory;
this._defaultUserData = data.dataDirectory; this._defaultUserData = data.dataDirectory;
this._socketPath = sharedData.socketPath; this._socketPath = sharedData.socketPath;
this._extensionsDirectory = data.extensionsDirectory;
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory; this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
this._workingDirectory = data.workingDirectory; this._workingDirectory = data.workingDirectory;
} }
@ -61,5 +71,6 @@ export const _paths = new Paths();
export const getAppDataPath = (): string => _paths.appData; export const getAppDataPath = (): string => _paths.appData;
export const getDefaultUserDataPath = (): string => _paths.defaultUserData; export const getDefaultUserDataPath = (): string => _paths.defaultUserData;
export const getWorkingDirectory = (): string => _paths.workingDirectory; export const getWorkingDirectory = (): string => _paths.workingDirectory;
export const getExtensionsDirectory = (): string => _paths.extensionsDirectory;
export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory; export const getBuiltInExtensionsDirectory = (): string => _paths.builtInExtensionsDirectory;
export const getSocketPath = (): string => _paths.socketPath; export const getSocketPath = (): string => _paths.socketPath;