Skip to content

Commit 8a0f1d8

Browse files
committed
Move start path logic out of patch and fix it
1 parent efaeb3b commit 8a0f1d8

File tree

5 files changed

+107
-89
lines changed

5 files changed

+107
-89
lines changed

scripts/vscode.patch

+18-60
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ index 0000000000..eb62b87798
852852
+}
853853
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
854854
new file mode 100644
855-
index 0000000000..cb606e6a68
855+
index 0000000000..9995e9f7fc
856856
--- /dev/null
857857
+++ b/src/vs/server/entry.ts
858858
@@ -0,0 +1,67 @@
@@ -897,8 +897,8 @@ index 0000000000..cb606e6a68
897897
+ process.send(message);
898898
+};
899899
+
900-
+// Wait for the init message then start up VS Code. Future messages will return
901-
+// new workbench options without starting a new instance.
900+
+// Wait for the init message then start up VS Code. Subsequent messages will
901+
+// return new workbench options without starting a new instance.
902902
+process.on('message', async (message: CodeServerMessage, socket) => {
903903
+ logger.debug('got message from code-server', field('message', message));
904904
+ switch (message.type) {
@@ -934,10 +934,10 @@ index 0000000000..56331ff1fc
934934
+require('../../bootstrap-amd').load('vs/server/entry');
935935
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
936936
new file mode 100644
937-
index 0000000000..218faa34d2
937+
index 0000000000..3bfef75d81
938938
--- /dev/null
939939
+++ b/src/vs/server/ipc.d.ts
940-
@@ -0,0 +1,93 @@
940+
@@ -0,0 +1,91 @@
941941
+/**
942942
+ * External interfaces for integration into code-server over IPC. No vs imports
943943
+ * should be made in this file.
@@ -971,19 +971,18 @@ index 0000000000..218faa34d2
971971
+export type VscodeMessage = ReadyMessage | OptionsMessage;
972972
+
973973
+export interface StartPath {
974-
+ path?: string[] | string;
975-
+ workspace?: boolean;
974+
+ url: string;
975+
+ workspace: boolean;
976976
+}
977977
+
978-
+export interface Settings {
979-
+ lastVisited?: StartPath;
978+
+export interface Args {
979+
+ _: string[];
980980
+}
981981
+
982982
+export interface VscodeOptions {
983983
+ readonly remoteAuthority: string;
984-
+ readonly query: Query;
985-
+ readonly args?: string[];
986-
+ readonly settings: Settings;
984+
+ readonly args: Args;
985+
+ readonly startPath?: StartPath;
987986
+}
988987
+
989988
+export interface VscodeOptionsMessage extends VscodeOptions {
@@ -1008,7 +1007,6 @@ index 0000000000..218faa34d2
10081007
+}
10091008
+
10101009
+export interface WorkbenchOptions {
1011-
+ readonly startPath?: StartPath;
10121010
+ readonly workbenchWebConfiguration: {
10131011
+ readonly remoteAuthority?: string;
10141012
+ readonly folderUri?: UriComponents;
@@ -2181,15 +2179,13 @@ index 0000000000..3c74512192
21812179
+}
21822180
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
21832181
new file mode 100644
2184-
index 0000000000..5207c90081
2182+
index 0000000000..81d275a80a
21852183
--- /dev/null
21862184
+++ b/src/vs/server/node/server.ts
2187-
@@ -0,0 +1,293 @@
2188-
+import * as fs from 'fs-extra';
2185+
@@ -0,0 +1,253 @@
21892186
+import * as net from 'net';
21902187
+import * as path from 'path';
21912188
+import { Emitter } from 'vs/base/common/event';
2192-
+import { sanitizeFilePath } from 'vs/base/common/extpath';
21932189
+import { Schemas } from 'vs/base/common/network';
21942190
+import { URI } from 'vs/base/common/uri';
21952191
+import { getMachineId } from 'vs/base/node/id';
@@ -2232,12 +2228,10 @@ index 0000000000..5207c90081
22322228
+import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
22332229
+import { INodeProxyService, NodeProxyChannel } from 'vs/server/common/nodeProxy';
22342230
+import { TelemetryChannel } from 'vs/server/common/telemetry';
2235-
+import { Query, StartPath, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc';
2231+
+import { Query, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc';
22362232
+import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from 'vs/server/node/channel';
2237-
+import { parseArgs } from 'vs/server/node/cli';
22382233
+import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection';
22392234
+import { TelemetryClient } from 'vs/server/node/insights';
2240-
+import { logger } from 'vs/server/node/logger';
22412235
+import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls';
22422236
+import { Protocol } from 'vs/server/node/protocol';
22432237
+import { getUriTransformer } from 'vs/server/node/util';
@@ -2253,27 +2247,19 @@ index 0000000000..5207c90081
22532247
+
22542248
+ private readonly services = new ServiceCollection();
22552249
+ private servicesPromise?: Promise<void>;
2256-
+ private args?: ParsedArgs;
22572250
+
22582251
+ public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> {
2259-
+ if (!this.args) {
2260-
+ this.args = parseArgs(options.args || []);
2261-
+ }
22622252
+ const transformer = getUriTransformer(options.remoteAuthority);
2263-
+ const startPath = await this.getFirstValidPath([
2264-
+ options.settings.lastVisited,
2265-
+ { path: this.args._[0] },
2266-
+ ]);
22672253
+ if (!this.servicesPromise) {
2268-
+ this.servicesPromise = this.initializeServices(this.args);
2254+
+ this.servicesPromise = this.initializeServices(options.args);
22692255
+ }
22702256
+ await this.servicesPromise;
22712257
+ const environment = this.services.get(IEnvironmentService) as IEnvironmentService;
2258+
+ const startPath = options.startPath;
22722259
+ return {
2273-
+ startPath,
22742260
+ workbenchWebConfiguration: {
2275-
+ workspaceUri: startPath && startPath.workspace ? transformer.transformOutgoing(URI.file(startPath.path)) : undefined,
2276-
+ folderUri: startPath && !startPath.workspace ? transformer.transformOutgoing(URI.file(startPath.path)) : undefined,
2261+
+ workspaceUri: startPath && startPath.workspace ? URI.parse(startPath.url) : undefined,
2262+
+ folderUri: startPath && !startPath.workspace ? URI.parse(startPath.url) : undefined,
22772263
+ remoteAuthority: options.remoteAuthority,
22782264
+ logLevel: getLogLevel(environment),
22792265
+ },
@@ -2305,34 +2291,6 @@ index 0000000000..5207c90081
23052291
+ return true;
23062292
+ }
23072293
+
2308-
+ /**
2309-
+ * Choose the first valid path. If `workspace` is undefined then either a
2310-
+ * workspace or a directory are acceptable. Otherwise it must be a file if a
2311-
+ * workspace or a directory otherwise.
2312-
+ */
2313-
+ private async getFirstValidPath(startPaths: Array<StartPath | undefined>): Promise<{ path: string, workspace?: boolean} | undefined> {
2314-
+ const cwd = process.env.VSCODE_CWD || process.cwd();
2315-
+ for (let i = 0; i < startPaths.length; ++i) {
2316-
+ const startPath = startPaths[i];
2317-
+ if (!startPath) {
2318-
+ continue;
2319-
+ }
2320-
+ const paths = typeof startPath.path === 'string' ? [startPath.path] : (startPath.path || []);
2321-
+ for (let j = 0; j < paths.length; ++j) {
2322-
+ const p = sanitizeFilePath(paths[j], cwd);
2323-
+ try {
2324-
+ const stat = await fs.stat(p);
2325-
+ if (typeof startPath.workspace === 'undefined' || startPath.workspace !== stat.isDirectory()) {
2326-
+ return { path: p, workspace: !stat.isDirectory() };
2327-
+ }
2328-
+ } catch (error) {
2329-
+ logger.warn(error.message);
2330-
+ }
2331-
+ }
2332-
+ }
2333-
+ return undefined;
2334-
+ }
2335-
+
23362294
+ private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
23372295
+ if (product.commit && message.commit !== product.commit) {
23382296
+ throw new Error(`Version mismatch (${message.commit} instead of ${product.commit})`);

src/node/cli.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { AuthType } from "./http"
2+
import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc"
3+
4+
export interface Args extends VsArgs {
5+
auth?: AuthType
6+
"base-path"?: string
7+
cert?: string
8+
"cert-key"?: string
9+
format?: string
10+
host?: string
11+
json?: boolean
12+
open?: boolean
13+
port?: string
14+
socket?: string
15+
version?: boolean
16+
_: string[]
17+
}
18+
19+
// TODO: Implement proper CLI parser.
20+
export const parse = (): Args => {
21+
const last = process.argv[process.argv.length - 1]
22+
return {
23+
version: process.argv.includes("--version"),
24+
json: process.argv.includes("--json"),
25+
_: last && !last.startsWith("-") ? [last] : [],
26+
}
27+
}

src/node/entry.ts

+7-19
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,13 @@
11
import { logger } from "@coder/logger"
22
import { ApiHttpProvider } from "./api/server"
33
import { MainHttpProvider } from "./app/server"
4+
import { Args, parse } from "./cli"
45
import { AuthType, HttpServer } from "./http"
56
import { generateCertificate, generatePassword, hash, open } from "./util"
67
import { VscodeHttpProvider } from "./vscode/server"
78
import { ipcMain, wrap } from "./wrapper"
89

9-
export interface Args {
10-
auth?: AuthType
11-
"base-path"?: string
12-
cert?: string
13-
"cert-key"?: string
14-
format?: string
15-
host?: string
16-
open?: boolean
17-
port?: string
18-
socket?: string
19-
_?: string[]
20-
}
21-
22-
const main = async (args: Args = {}): Promise<void> => {
10+
const main = async (args: Args): Promise<void> => {
2311
const auth = args.auth || AuthType.Password
2412
const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword()))
2513

@@ -51,7 +39,7 @@ const main = async (args: Args = {}): Promise<void> => {
5139
const httpServer = new HttpServer(options)
5240
httpServer.registerHttpProvider("/", MainHttpProvider)
5341
httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer)
54-
httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, [])
42+
httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, args)
5543

5644
ipcMain().onDispose(() => httpServer.dispose())
5745

@@ -88,10 +76,10 @@ const main = async (args: Args = {}): Promise<void> => {
8876
}
8977
}
9078

91-
// TODO: Implement CLI parser.
92-
if (process.argv.includes("--version")) {
79+
const args = parse()
80+
if (args.version) {
9381
const version = require("../../package.json").version
94-
if (process.argv.includes("--json")) {
82+
if (args.json) {
9583
console.log({
9684
codeServer: version,
9785
vscode: require("../../lib/vscode/package.json").version,
@@ -101,5 +89,5 @@ if (process.argv.includes("--version")) {
10189
}
10290
process.exit(0)
10391
} else {
104-
wrap(main)
92+
wrap(() => main(args))
10593
}

src/node/vscode/error.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<meta http-equiv="Content-Security-Policy" content="font-src 'self' fonts.gstatic.com; connect-src 'self'; default-src ws: wss: 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:;">
77
<title>code-server</title>
88
</head>
9-
<body>
9+
<body style="background-color:#272727;">
1010
<div id="root" style="color:#f4f4f4;padding:20px;max-width:700px;">
1111
{{ERROR}}
1212
</div>

src/node/vscode/server.ts

+54-9
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
import { field, logger } from "@coder/logger"
22
import * as cp from "child_process"
33
import * as crypto from "crypto"
4+
import * as fs from "fs-extra"
45
import * as http from "http"
56
import * as net from "net"
67
import * as path from "path"
8+
import * as url from "url"
79
import {
810
CodeServerMessage,
9-
Settings,
11+
StartPath,
1012
VscodeMessage,
1113
VscodeOptions,
1214
WorkbenchOptions,
1315
} from "../../../lib/vscode/src/vs/server/ipc"
1416
import { HttpCode, HttpError } from "../../common/http"
1517
import { generateUuid } from "../../common/util"
18+
import { Args } from "../cli"
1619
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
1720
import { SettingsProvider } from "../settings"
1821
import { xdgLocalDir } from "../util"
1922

23+
export interface Settings {
24+
lastVisited: StartPath
25+
}
26+
2027
export class VscodeHttpProvider extends HttpProvider {
2128
private readonly serverRootPath: string
2229
private readonly vsRootPath: string
2330
private readonly settings = new SettingsProvider<Settings>(path.join(xdgLocalDir, "coder.json"))
2431
private _vscode?: Promise<cp.ChildProcess>
2532
private workbenchOptions?: WorkbenchOptions
2633

27-
public constructor(options: HttpProviderOptions, private readonly args: string[]) {
34+
public constructor(options: HttpProviderOptions, private readonly args: Args) {
2835
super(options)
2936
this.vsRootPath = path.resolve(this.rootPath, "lib/vscode")
3037
this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")
@@ -161,24 +168,26 @@ export class VscodeHttpProvider extends HttpProvider {
161168

162169
private async getRoot(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
163170
const settings = await this.settings.read()
171+
const startPath = await this.getFirstValidPath([
172+
{ url: route.query.workspace, workspace: true },
173+
{ url: route.query.folder, workspace: false },
174+
settings.lastVisited,
175+
this.args._ && this.args._.length > 0 ? { url: this.urlify(this.args._[0]) } : undefined,
176+
])
164177
const [response, options] = await Promise.all([
165178
await this.getUtf8Resource(this.rootPath, `src/node/vscode/workbench${!this.isDev ? "-build" : ""}.html`),
166179
this.initialize({
167180
args: this.args,
168-
query: route.query,
169181
remoteAuthority: request.headers.host as string,
170-
settings,
182+
startPath,
171183
}),
172184
])
173185

174186
this.workbenchOptions = options
175187

176-
if (options.startPath) {
188+
if (startPath) {
177189
this.settings.write({
178-
lastVisited: {
179-
path: options.startPath.path,
180-
workspace: options.startPath.workspace,
181-
},
190+
lastVisited: startPath,
182191
})
183192
}
184193

@@ -201,4 +210,40 @@ export class VscodeHttpProvider extends HttpProvider {
201210
response.content = response.content.replace(/{{COMMIT}}/g, this.options.commit).replace(/{{ERROR}}/g, message)
202211
return response
203212
}
213+
214+
/**
215+
* Choose the first valid path. If `workspace` is undefined then either a
216+
* workspace or a directory are acceptable. Otherwise it must be a file if a
217+
* workspace or a directory otherwise.
218+
*/
219+
private async getFirstValidPath(
220+
startPaths: Array<{ url?: string | string[]; workspace?: boolean } | undefined>
221+
): Promise<StartPath | undefined> {
222+
for (let i = 0; i < startPaths.length; ++i) {
223+
const startPath = startPaths[i]
224+
if (!startPath) {
225+
continue
226+
}
227+
const paths = typeof startPath.url === "string" ? [startPath.url] : startPath.url || []
228+
for (let j = 0; j < paths.length; ++j) {
229+
const u = url.parse(paths[j])
230+
try {
231+
if (!u.pathname) {
232+
throw new Error(`${paths[j]} is not a valid URL`)
233+
}
234+
const stat = await fs.stat(u.pathname)
235+
if (typeof startPath.workspace === "undefined" || startPath.workspace !== stat.isDirectory()) {
236+
return { url: u.href, workspace: !stat.isDirectory() }
237+
}
238+
} catch (error) {
239+
logger.warn(error.message)
240+
}
241+
}
242+
}
243+
return undefined
244+
}
245+
246+
private urlify(p: string): string {
247+
return "vscode-remote://host" + path.resolve(p)
248+
}
204249
}

0 commit comments

Comments
 (0)