Skip to content

Commit aa1474b

Browse files
authored
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
1 parent 8256252 commit aa1474b

File tree

12 files changed

+341
-13
lines changed

12 files changed

+341
-13
lines changed

packages/protocol/src/browser/client.ts

+2
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ export class Client {
278278
shell: init.getShell(),
279279
extensionsDirectory: init.getExtensionsDirectory(),
280280
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
281+
extraExtensionDirectories: init.getExtraExtensionDirectoriesList(),
282+
extraBuiltinExtensionDirectories: init.getExtraBuiltinExtensionDirectoriesList(),
281283
};
282284
this.initDataEmitter.emit(this._initData);
283285
break;

packages/protocol/src/common/connection.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export interface InitData {
2525
readonly shell: string;
2626
readonly extensionsDirectory: string;
2727
readonly builtInExtensionsDirectory: string;
28+
readonly extraExtensionDirectories: string[];
29+
readonly extraBuiltinExtensionDirectories: string[];
2830
}
2931

3032
export interface SharedProcessData {

packages/protocol/src/node/server.ts

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export interface ServerOptions {
1515
readonly cacheDirectory: string;
1616
readonly builtInExtensionsDirectory: string;
1717
readonly extensionsDirectory: string;
18+
readonly extraExtensionDirectories?: string[];
19+
readonly extraBuiltinExtensionDirectories?: string[];
1820
readonly fork?: ForkProvider;
1921
}
2022

@@ -99,6 +101,8 @@ export class Server {
99101
initMsg.setTmpDirectory(os.tmpdir());
100102
initMsg.setOperatingSystem(platformToProto(os.platform()));
101103
initMsg.setShell(os.userInfo().shell || global.process.env.SHELL || "");
104+
initMsg.setExtraExtensionDirectoriesList(this.options.extraExtensionDirectories || []);
105+
initMsg.setExtraBuiltinExtensionDirectoriesList(this.options.extraBuiltinExtensionDirectories || []);
102106
const srvMsg = new ServerMessage();
103107
srvMsg.setInit(initMsg);
104108
connection.send(srvMsg.serializeBinary());

packages/protocol/src/proto/client.proto

+2
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ message WorkingInit {
4242
string shell = 6;
4343
string builtin_extensions_dir = 7;
4444
string extensions_directory = 8;
45+
repeated string extra_extension_directories = 9;
46+
repeated string extra_builtin_extension_directories = 10;
4547
}

packages/protocol/src/proto/client_pb.d.ts

+12
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ export class WorkingInit extends jspb.Message {
135135
getExtensionsDirectory(): string;
136136
setExtensionsDirectory(value: string): void;
137137

138+
clearExtraExtensionDirectoriesList(): void;
139+
getExtraExtensionDirectoriesList(): Array<string>;
140+
setExtraExtensionDirectoriesList(value: Array<string>): void;
141+
addExtraExtensionDirectories(value: string, index?: number): string;
142+
143+
clearExtraBuiltinExtensionDirectoriesList(): void;
144+
getExtraBuiltinExtensionDirectoriesList(): Array<string>;
145+
setExtraBuiltinExtensionDirectoriesList(value: Array<string>): void;
146+
addExtraBuiltinExtensionDirectories(value: string, index?: number): string;
147+
138148
serializeBinary(): Uint8Array;
139149
toObject(includeInstance?: boolean): WorkingInit.AsObject;
140150
static toObject(includeInstance: boolean, msg: WorkingInit): WorkingInit.AsObject;
@@ -155,6 +165,8 @@ export namespace WorkingInit {
155165
shell: string,
156166
builtinExtensionsDir: string,
157167
extensionsDirectory: string,
168+
extraExtensionDirectoriesList: Array<string>,
169+
extraBuiltinExtensionDirectoriesList: Array<string>,
158170
}
159171

160172
export enum OperatingSystem {

packages/protocol/src/proto/client_pb.js

+97-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ if (goog.DEBUG && !COMPILED) {
7272
* @constructor
7373
*/
7474
proto.WorkingInit = function(opt_data) {
75-
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
75+
jspb.Message.initialize(this, opt_data, 0, -1, proto.WorkingInit.repeatedFields_, null);
7676
};
7777
goog.inherits(proto.WorkingInit, jspb.Message);
7878
if (goog.DEBUG && !COMPILED) {
@@ -759,6 +759,13 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() {
759759

760760

761761

762+
/**
763+
* List of repeated fields within this message type.
764+
* @private {!Array<number>}
765+
* @const
766+
*/
767+
proto.WorkingInit.repeatedFields_ = [9,10];
768+
762769

763770

764771
if (jspb.Message.GENERATE_TO_OBJECT) {
@@ -795,7 +802,9 @@ proto.WorkingInit.toObject = function(includeInstance, msg) {
795802
operatingSystem: jspb.Message.getFieldWithDefault(msg, 5, 0),
796803
shell: jspb.Message.getFieldWithDefault(msg, 6, ""),
797804
builtinExtensionsDir: jspb.Message.getFieldWithDefault(msg, 7, ""),
798-
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, "")
805+
extensionsDirectory: jspb.Message.getFieldWithDefault(msg, 8, ""),
806+
extraExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 9),
807+
extraBuiltinExtensionDirectoriesList: jspb.Message.getRepeatedField(msg, 10)
799808
};
800809

801810
if (includeInstance) {
@@ -864,6 +873,14 @@ proto.WorkingInit.deserializeBinaryFromReader = function(msg, reader) {
864873
var value = /** @type {string} */ (reader.readString());
865874
msg.setExtensionsDirectory(value);
866875
break;
876+
case 9:
877+
var value = /** @type {string} */ (reader.readString());
878+
msg.addExtraExtensionDirectories(value);
879+
break;
880+
case 10:
881+
var value = /** @type {string} */ (reader.readString());
882+
msg.addExtraBuiltinExtensionDirectories(value);
883+
break;
867884
default:
868885
reader.skipField();
869886
break;
@@ -949,6 +966,20 @@ proto.WorkingInit.serializeBinaryToWriter = function(message, writer) {
949966
f
950967
);
951968
}
969+
f = message.getExtraExtensionDirectoriesList();
970+
if (f.length > 0) {
971+
writer.writeRepeatedString(
972+
9,
973+
f
974+
);
975+
}
976+
f = message.getExtraBuiltinExtensionDirectoriesList();
977+
if (f.length > 0) {
978+
writer.writeRepeatedString(
979+
10,
980+
f
981+
);
982+
}
952983
};
953984

954985

@@ -1081,4 +1112,68 @@ proto.WorkingInit.prototype.setExtensionsDirectory = function(value) {
10811112
};
10821113

10831114

1115+
/**
1116+
* repeated string extra_extension_directories = 9;
1117+
* @return {!Array<string>}
1118+
*/
1119+
proto.WorkingInit.prototype.getExtraExtensionDirectoriesList = function() {
1120+
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 9));
1121+
};
1122+
1123+
1124+
/** @param {!Array<string>} value */
1125+
proto.WorkingInit.prototype.setExtraExtensionDirectoriesList = function(value) {
1126+
jspb.Message.setField(this, 9, value || []);
1127+
};
1128+
1129+
1130+
/**
1131+
* @param {string} value
1132+
* @param {number=} opt_index
1133+
*/
1134+
proto.WorkingInit.prototype.addExtraExtensionDirectories = function(value, opt_index) {
1135+
jspb.Message.addToRepeatedField(this, 9, value, opt_index);
1136+
};
1137+
1138+
1139+
/**
1140+
* Clears the list making it empty but non-null.
1141+
*/
1142+
proto.WorkingInit.prototype.clearExtraExtensionDirectoriesList = function() {
1143+
this.setExtraExtensionDirectoriesList([]);
1144+
};
1145+
1146+
1147+
/**
1148+
* repeated string extra_builtin_extension_directories = 10;
1149+
* @return {!Array<string>}
1150+
*/
1151+
proto.WorkingInit.prototype.getExtraBuiltinExtensionDirectoriesList = function() {
1152+
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 10));
1153+
};
1154+
1155+
1156+
/** @param {!Array<string>} value */
1157+
proto.WorkingInit.prototype.setExtraBuiltinExtensionDirectoriesList = function(value) {
1158+
jspb.Message.setField(this, 10, value || []);
1159+
};
1160+
1161+
1162+
/**
1163+
* @param {string} value
1164+
* @param {number=} opt_index
1165+
*/
1166+
proto.WorkingInit.prototype.addExtraBuiltinExtensionDirectories = function(value, opt_index) {
1167+
jspb.Message.addToRepeatedField(this, 10, value, opt_index);
1168+
};
1169+
1170+
1171+
/**
1172+
* Clears the list making it empty but non-null.
1173+
*/
1174+
proto.WorkingInit.prototype.clearExtraBuiltinExtensionDirectoriesList = function() {
1175+
this.setExtraBuiltinExtensionDirectoriesList([]);
1176+
};
1177+
1178+
10841179
goog.object.extend(exports, proto);

packages/protocol/test/server.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { createClient } from "./helpers";
33
describe("Server", () => {
44
const dataDirectory = "/tmp/example";
55
const workingDirectory = "/working/dir";
6+
const extensionsDirectory = "/tmp/example";
67
const builtInExtensionsDirectory = "/tmp/example";
78
const cacheDirectory = "/tmp/cache";
89
const client = createClient({
10+
extensionsDirectory,
911
builtInExtensionsDirectory,
1012
cacheDirectory,
1113
dataDirectory,

packages/server/src/cli.ts

+22-4
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@ import opn = require("opn");
1616

1717
import * as commander from "commander";
1818

19+
const collect = <T>(value: T, previous: T[]): T[] => {
20+
return previous.concat(value);
21+
};
22+
1923
commander.version(process.env.VERSION || "development")
2024
.name("code-server")
2125
.description("Run VS Code on a remote server.")
2226
.option("--cert <value>")
2327
.option("--cert-key <value>")
24-
.option("-e, --extensions-dir <dir>", "Set the root path for extensions.")
25-
.option("-d --user-data-dir <dir>", " Specifies the directory that user data is kept in, useful when running as root.")
28+
.option("-e, --extensions-dir <dir>", "Override the main default path for user extensions.")
29+
.option("--builtin-extensions-dir <dir>", "Override the main default path for built-in extensions.")
30+
.option("--extra-extensions-dir [dir]", "Path to an extra user extension directory (repeatable).", collect, [])
31+
.option("--extra-builtin-extensions-dir [dir]", "Path to an extra built-in extension directory (repeatable).", collect, [])
32+
.option("-d --user-data-dir <dir>", "Specifies the directory that user data is kept in, useful when running as root.")
2633
.option("--data-dir <value>", "DEPRECATED: Use '--user-data-dir' instead. Customize where user-data is stored.")
2734
.option("-h, --host <value>", "Customize the hostname.", "0.0.0.0")
2835
.option("-o, --open", "Open in the browser on startup.", false)
@@ -59,6 +66,9 @@ const bold = (text: string | number): string | number => {
5966

6067
readonly userDataDir?: string;
6168
readonly extensionsDir?: string;
69+
readonly builtinExtensionsDir?: string;
70+
readonly extraExtensionsDir?: string[];
71+
readonly extraBuiltinExtensionsDir?: string[];
6272

6373
readonly dataDir?: string;
6474
readonly password?: string;
@@ -84,6 +94,10 @@ const bold = (text: string | number): string | number => {
8494

8595
const dataDir = path.resolve(options.userDataDir || options.dataDir || path.join(dataHome, "code-server"));
8696
const extensionsDir = options.extensionsDir ? path.resolve(options.extensionsDir) : path.resolve(dataDir, "extensions");
97+
const builtInExtensionsDir = options.builtinExtensionsDir ? path.resolve(options.builtinExtensionsDir)
98+
: path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
99+
const extraExtensionDirs = options.extraExtensionsDir ? options.extraExtensionsDir.map((p) => path.resolve(p)) : [];
100+
const extraBuiltinExtensionDirs = options.extraBuiltinExtensionsDir ? options.extraBuiltinExtensionsDir.map((p) => path.resolve(p)) : [];
87101
const workingDir = path.resolve(args[0] || process.cwd());
88102
const dependenciesDir = path.join(os.tmpdir(), "code-server/dependencies");
89103

@@ -99,8 +113,11 @@ const bold = (text: string | number): string | number => {
99113
fse.mkdirp(cacheHome),
100114
fse.mkdirp(dataDir),
101115
fse.mkdirp(extensionsDir),
116+
fse.mkdirp(builtInExtensionsDir),
102117
fse.mkdirp(workingDir),
103118
fse.mkdirp(dependenciesDir),
119+
...extraExtensionDirs.map((p) => fse.mkdirp(p)),
120+
...extraBuiltinExtensionDirs.map((p) => fse.mkdirp(p)),
104121
]);
105122

106123
const unpackExecutable = (binaryName: string): void => {
@@ -116,7 +133,6 @@ const bold = (text: string | number): string | number => {
116133
// tslint:disable-next-line no-any
117134
(<any>global).RIPGREP_LOCATION = path.join(dependenciesDir, "rg");
118135

119-
const builtInExtensionsDir = path.resolve(buildDir || path.join(__dirname, ".."), "build/extensions");
120136
if (options.bootstrapFork) {
121137
const modulePath = options.bootstrapFork;
122138
if (!modulePath) {
@@ -192,7 +208,7 @@ const bold = (text: string | number): string | number => {
192208
// TODO: fill in appropriate doc url
193209
logger.info("Additional documentation: http://github.com/cdr/code-server");
194210
logger.info("Initializing", field("data-dir", dataDir), field("extensions-dir", extensionsDir), field("working-dir", workingDir), field("log-dir", logDir));
195-
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir);
211+
const sharedProcess = new SharedProcess(dataDir, extensionsDir, builtInExtensionsDir, extraExtensionDirs, extraBuiltinExtensionDirs);
196212
const sendSharedProcessReady = (socket: WebSocket): void => {
197213
const active = new SharedProcessActive();
198214
active.setSocketPath(sharedProcess.socketPath);
@@ -247,6 +263,8 @@ const bold = (text: string | number): string | number => {
247263
serverOptions: {
248264
extensionsDirectory: extensionsDir,
249265
builtInExtensionsDirectory: builtInExtensionsDir,
266+
extraExtensionDirectories: extraExtensionDirs,
267+
extraBuiltinExtensionDirectories: extraBuiltinExtensionDirs,
250268
dataDirectory: dataDir,
251269
workingDirectory: workingDir,
252270
cacheDirectory: cacheHome,

packages/server/src/vscode/sharedProcess.ts

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class SharedProcess {
3939
private readonly userDataDir: string,
4040
private readonly extensionsDir: string,
4141
private readonly builtInExtensionsDir: string,
42+
private readonly extraExtensionDirs: string[],
43+
private readonly extraBuiltinExtensionDirs: string[],
4244
) {
4345
this.retry.run();
4446
}
@@ -134,6 +136,8 @@ export class SharedProcess {
134136
"builtin-extensions-dir": this.builtInExtensionsDir,
135137
"user-data-dir": this.userDataDir,
136138
"extensions-dir": this.extensionsDir,
139+
"extra-extension-dirs": this.extraExtensionDirs,
140+
"extra-builtin-extension-dirs": this.extraBuiltinExtensionDirs,
137141
},
138142
logLevel: this.logger.level,
139143
sharedIPCHandle: this.socketPath,

packages/vscode/src/fill/environmentService.ts

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ export class EnvironmentService extends environment.EnvironmentService {
1212
public get extensionsPath(): string {
1313
return paths.getExtensionsDirectory();
1414
}
15+
16+
public get builtinExtensionsPath(): string {
17+
return paths.getBuiltInExtensionsDirectory();
18+
}
19+
20+
public get extraExtensionPaths(): string[] {
21+
return paths.getExtraExtensionDirectories();
22+
}
23+
24+
public get extraBuiltinExtensionPaths(): string[] {
25+
return paths.getExtraBuiltinExtensionDirectories();
26+
}
1527
}
1628

1729
const target = environment as typeof environment;

0 commit comments

Comments
 (0)