Move start path logic out of patch and fix it

This commit is contained in:
Asher 2020-02-06 12:29:19 -06:00
parent efaeb3b110
commit 8a0f1d846e
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
5 changed files with 107 additions and 89 deletions

View File

@ -852,7 +852,7 @@ index 0000000000..eb62b87798
+} +}
diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts
new file mode 100644 new file mode 100644
index 0000000000..cb606e6a68 index 0000000000..9995e9f7fc
--- /dev/null --- /dev/null
+++ b/src/vs/server/entry.ts +++ b/src/vs/server/entry.ts
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
@ -897,8 +897,8 @@ index 0000000000..cb606e6a68
+ process.send(message); + process.send(message);
+}; +};
+ +
+// Wait for the init message then start up VS Code. Future messages will return +// Wait for the init message then start up VS Code. Subsequent messages will
+// new workbench options without starting a new instance. +// return new workbench options without starting a new instance.
+process.on('message', async (message: CodeServerMessage, socket) => { +process.on('message', async (message: CodeServerMessage, socket) => {
+ logger.debug('got message from code-server', field('message', message)); + logger.debug('got message from code-server', field('message', message));
+ switch (message.type) { + switch (message.type) {
@ -934,10 +934,10 @@ index 0000000000..56331ff1fc
+require('../../bootstrap-amd').load('vs/server/entry'); +require('../../bootstrap-amd').load('vs/server/entry');
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
new file mode 100644 new file mode 100644
index 0000000000..218faa34d2 index 0000000000..3bfef75d81
--- /dev/null --- /dev/null
+++ b/src/vs/server/ipc.d.ts +++ b/src/vs/server/ipc.d.ts
@@ -0,0 +1,93 @@ @@ -0,0 +1,91 @@
+/** +/**
+ * External interfaces for integration into code-server over IPC. No vs imports + * External interfaces for integration into code-server over IPC. No vs imports
+ * should be made in this file. + * should be made in this file.
@ -971,19 +971,18 @@ index 0000000000..218faa34d2
+export type VscodeMessage = ReadyMessage | OptionsMessage; +export type VscodeMessage = ReadyMessage | OptionsMessage;
+ +
+export interface StartPath { +export interface StartPath {
+ path?: string[] | string; + url: string;
+ workspace?: boolean; + workspace: boolean;
+} +}
+ +
+export interface Settings { +export interface Args {
+ lastVisited?: StartPath; + _: string[];
+} +}
+ +
+export interface VscodeOptions { +export interface VscodeOptions {
+ readonly remoteAuthority: string; + readonly remoteAuthority: string;
+ readonly query: Query; + readonly args: Args;
+ readonly args?: string[]; + readonly startPath?: StartPath;
+ readonly settings: Settings;
+} +}
+ +
+export interface VscodeOptionsMessage extends VscodeOptions { +export interface VscodeOptionsMessage extends VscodeOptions {
@ -1008,7 +1007,6 @@ index 0000000000..218faa34d2
+} +}
+ +
+export interface WorkbenchOptions { +export interface WorkbenchOptions {
+ readonly startPath?: StartPath;
+ readonly workbenchWebConfiguration: { + readonly workbenchWebConfiguration: {
+ readonly remoteAuthority?: string; + readonly remoteAuthority?: string;
+ readonly folderUri?: UriComponents; + readonly folderUri?: UriComponents;
@ -2181,15 +2179,13 @@ index 0000000000..3c74512192
+} +}
diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts diff --git a/src/vs/server/node/server.ts b/src/vs/server/node/server.ts
new file mode 100644 new file mode 100644
index 0000000000..5207c90081 index 0000000000..81d275a80a
--- /dev/null --- /dev/null
+++ b/src/vs/server/node/server.ts +++ b/src/vs/server/node/server.ts
@@ -0,0 +1,293 @@ @@ -0,0 +1,253 @@
+import * as fs from 'fs-extra';
+import * as net from 'net'; +import * as net from 'net';
+import * as path from 'path'; +import * as path from 'path';
+import { Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event';
+import { sanitizeFilePath } from 'vs/base/common/extpath';
+import { Schemas } from 'vs/base/common/network'; +import { Schemas } from 'vs/base/common/network';
+import { URI } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri';
+import { getMachineId } from 'vs/base/node/id'; +import { getMachineId } from 'vs/base/node/id';
@ -2232,12 +2228,10 @@ index 0000000000..5207c90081
+import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; +import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
+import { INodeProxyService, NodeProxyChannel } from 'vs/server/common/nodeProxy'; +import { INodeProxyService, NodeProxyChannel } from 'vs/server/common/nodeProxy';
+import { TelemetryChannel } from 'vs/server/common/telemetry'; +import { TelemetryChannel } from 'vs/server/common/telemetry';
+import { Query, StartPath, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc'; +import { Query, VscodeOptions, WorkbenchOptions } from 'vs/server/ipc';
+import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from 'vs/server/node/channel'; +import { ExtensionEnvironmentChannel, FileProviderChannel, NodeProxyService } from 'vs/server/node/channel';
+import { parseArgs } from 'vs/server/node/cli';
+import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection'; +import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection';
+import { TelemetryClient } from 'vs/server/node/insights'; +import { TelemetryClient } from 'vs/server/node/insights';
+import { logger } from 'vs/server/node/logger';
+import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls'; +import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls';
+import { Protocol } from 'vs/server/node/protocol'; +import { Protocol } from 'vs/server/node/protocol';
+import { getUriTransformer } from 'vs/server/node/util'; +import { getUriTransformer } from 'vs/server/node/util';
@ -2253,27 +2247,19 @@ index 0000000000..5207c90081
+ +
+ private readonly services = new ServiceCollection(); + private readonly services = new ServiceCollection();
+ private servicesPromise?: Promise<void>; + private servicesPromise?: Promise<void>;
+ private args?: ParsedArgs;
+ +
+ public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> { + public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> {
+ if (!this.args) {
+ this.args = parseArgs(options.args || []);
+ }
+ const transformer = getUriTransformer(options.remoteAuthority); + const transformer = getUriTransformer(options.remoteAuthority);
+ const startPath = await this.getFirstValidPath([
+ options.settings.lastVisited,
+ { path: this.args._[0] },
+ ]);
+ if (!this.servicesPromise) { + if (!this.servicesPromise) {
+ this.servicesPromise = this.initializeServices(this.args); + this.servicesPromise = this.initializeServices(options.args);
+ } + }
+ await this.servicesPromise; + await this.servicesPromise;
+ const environment = this.services.get(IEnvironmentService) as IEnvironmentService; + const environment = this.services.get(IEnvironmentService) as IEnvironmentService;
+ const startPath = options.startPath;
+ return { + return {
+ startPath,
+ workbenchWebConfiguration: { + workbenchWebConfiguration: {
+ workspaceUri: startPath && startPath.workspace ? transformer.transformOutgoing(URI.file(startPath.path)) : undefined, + workspaceUri: startPath && startPath.workspace ? URI.parse(startPath.url) : undefined,
+ folderUri: startPath && !startPath.workspace ? transformer.transformOutgoing(URI.file(startPath.path)) : undefined, + folderUri: startPath && !startPath.workspace ? URI.parse(startPath.url) : undefined,
+ remoteAuthority: options.remoteAuthority, + remoteAuthority: options.remoteAuthority,
+ logLevel: getLogLevel(environment), + logLevel: getLogLevel(environment),
+ }, + },
@ -2305,34 +2291,6 @@ index 0000000000..5207c90081
+ return true; + return true;
+ } + }
+ +
+ /**
+ * Choose the first valid path. If `workspace` is undefined then either a
+ * workspace or a directory are acceptable. Otherwise it must be a file if a
+ * workspace or a directory otherwise.
+ */
+ private async getFirstValidPath(startPaths: Array<StartPath | undefined>): Promise<{ path: string, workspace?: boolean} | undefined> {
+ const cwd = process.env.VSCODE_CWD || process.cwd();
+ for (let i = 0; i < startPaths.length; ++i) {
+ const startPath = startPaths[i];
+ if (!startPath) {
+ continue;
+ }
+ const paths = typeof startPath.path === 'string' ? [startPath.path] : (startPath.path || []);
+ for (let j = 0; j < paths.length; ++j) {
+ const p = sanitizeFilePath(paths[j], cwd);
+ try {
+ const stat = await fs.stat(p);
+ if (typeof startPath.workspace === 'undefined' || startPath.workspace !== stat.isDirectory()) {
+ return { path: p, workspace: !stat.isDirectory() };
+ }
+ } catch (error) {
+ logger.warn(error.message);
+ }
+ }
+ }
+ return undefined;
+ }
+
+ private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> { + private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> {
+ if (product.commit && message.commit !== product.commit) { + if (product.commit && message.commit !== product.commit) {
+ throw new Error(`Version mismatch (${message.commit} instead of ${product.commit})`); + throw new Error(`Version mismatch (${message.commit} instead of ${product.commit})`);

27
src/node/cli.ts Normal file
View File

@ -0,0 +1,27 @@
import { AuthType } from "./http"
import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc"
export interface Args extends VsArgs {
auth?: AuthType
"base-path"?: string
cert?: string
"cert-key"?: string
format?: string
host?: string
json?: boolean
open?: boolean
port?: string
socket?: string
version?: boolean
_: string[]
}
// TODO: Implement proper CLI parser.
export const parse = (): Args => {
const last = process.argv[process.argv.length - 1]
return {
version: process.argv.includes("--version"),
json: process.argv.includes("--json"),
_: last && !last.startsWith("-") ? [last] : [],
}
}

View File

@ -1,25 +1,13 @@
import { logger } from "@coder/logger" import { logger } from "@coder/logger"
import { ApiHttpProvider } from "./api/server" import { ApiHttpProvider } from "./api/server"
import { MainHttpProvider } from "./app/server" import { MainHttpProvider } from "./app/server"
import { Args, parse } from "./cli"
import { AuthType, HttpServer } from "./http" import { AuthType, HttpServer } from "./http"
import { generateCertificate, generatePassword, hash, open } from "./util" import { generateCertificate, generatePassword, hash, open } from "./util"
import { VscodeHttpProvider } from "./vscode/server" import { VscodeHttpProvider } from "./vscode/server"
import { ipcMain, wrap } from "./wrapper" import { ipcMain, wrap } from "./wrapper"
export interface Args { const main = async (args: Args): Promise<void> => {
auth?: AuthType
"base-path"?: string
cert?: string
"cert-key"?: string
format?: string
host?: string
open?: boolean
port?: string
socket?: string
_?: string[]
}
const main = async (args: Args = {}): Promise<void> => {
const auth = args.auth || AuthType.Password const auth = args.auth || AuthType.Password
const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword())) const originalPassword = auth === AuthType.Password && (process.env.PASSWORD || (await generatePassword()))
@ -51,7 +39,7 @@ const main = async (args: Args = {}): Promise<void> => {
const httpServer = new HttpServer(options) const httpServer = new HttpServer(options)
httpServer.registerHttpProvider("/", MainHttpProvider) httpServer.registerHttpProvider("/", MainHttpProvider)
httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer) httpServer.registerHttpProvider("/api", ApiHttpProvider, httpServer)
httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, []) httpServer.registerHttpProvider("/vscode-embed", VscodeHttpProvider, args)
ipcMain().onDispose(() => httpServer.dispose()) ipcMain().onDispose(() => httpServer.dispose())
@ -88,10 +76,10 @@ const main = async (args: Args = {}): Promise<void> => {
} }
} }
// TODO: Implement CLI parser. const args = parse()
if (process.argv.includes("--version")) { if (args.version) {
const version = require("../../package.json").version const version = require("../../package.json").version
if (process.argv.includes("--json")) { if (args.json) {
console.log({ console.log({
codeServer: version, codeServer: version,
vscode: require("../../lib/vscode/package.json").version, vscode: require("../../lib/vscode/package.json").version,
@ -101,5 +89,5 @@ if (process.argv.includes("--version")) {
} }
process.exit(0) process.exit(0)
} else { } else {
wrap(main) wrap(() => main(args))
} }

View File

@ -6,7 +6,7 @@
<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:;"> <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:;">
<title>code-server</title> <title>code-server</title>
</head> </head>
<body> <body style="background-color:#272727;">
<div id="root" style="color:#f4f4f4;padding:20px;max-width:700px;"> <div id="root" style="color:#f4f4f4;padding:20px;max-width:700px;">
{{ERROR}} {{ERROR}}
</div> </div>

View File

@ -1,22 +1,29 @@
import { field, logger } from "@coder/logger" import { field, logger } from "@coder/logger"
import * as cp from "child_process" import * as cp from "child_process"
import * as crypto from "crypto" import * as crypto from "crypto"
import * as fs from "fs-extra"
import * as http from "http" import * as http from "http"
import * as net from "net" import * as net from "net"
import * as path from "path" import * as path from "path"
import * as url from "url"
import { import {
CodeServerMessage, CodeServerMessage,
Settings, StartPath,
VscodeMessage, VscodeMessage,
VscodeOptions, VscodeOptions,
WorkbenchOptions, WorkbenchOptions,
} from "../../../lib/vscode/src/vs/server/ipc" } from "../../../lib/vscode/src/vs/server/ipc"
import { HttpCode, HttpError } from "../../common/http" import { HttpCode, HttpError } from "../../common/http"
import { generateUuid } from "../../common/util" import { generateUuid } from "../../common/util"
import { Args } from "../cli"
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http" import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
import { SettingsProvider } from "../settings" import { SettingsProvider } from "../settings"
import { xdgLocalDir } from "../util" import { xdgLocalDir } from "../util"
export interface Settings {
lastVisited: StartPath
}
export class VscodeHttpProvider extends HttpProvider { export class VscodeHttpProvider extends HttpProvider {
private readonly serverRootPath: string private readonly serverRootPath: string
private readonly vsRootPath: string private readonly vsRootPath: string
@ -24,7 +31,7 @@ export class VscodeHttpProvider extends HttpProvider {
private _vscode?: Promise<cp.ChildProcess> private _vscode?: Promise<cp.ChildProcess>
private workbenchOptions?: WorkbenchOptions private workbenchOptions?: WorkbenchOptions
public constructor(options: HttpProviderOptions, private readonly args: string[]) { public constructor(options: HttpProviderOptions, private readonly args: Args) {
super(options) super(options)
this.vsRootPath = path.resolve(this.rootPath, "lib/vscode") this.vsRootPath = path.resolve(this.rootPath, "lib/vscode")
this.serverRootPath = path.join(this.vsRootPath, "out/vs/server") this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")
@ -161,24 +168,26 @@ export class VscodeHttpProvider extends HttpProvider {
private async getRoot(request: http.IncomingMessage, route: Route): Promise<HttpResponse> { private async getRoot(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
const settings = await this.settings.read() const settings = await this.settings.read()
const startPath = await this.getFirstValidPath([
{ url: route.query.workspace, workspace: true },
{ url: route.query.folder, workspace: false },
settings.lastVisited,
this.args._ && this.args._.length > 0 ? { url: this.urlify(this.args._[0]) } : undefined,
])
const [response, options] = await Promise.all([ const [response, options] = await Promise.all([
await this.getUtf8Resource(this.rootPath, `src/node/vscode/workbench${!this.isDev ? "-build" : ""}.html`), await this.getUtf8Resource(this.rootPath, `src/node/vscode/workbench${!this.isDev ? "-build" : ""}.html`),
this.initialize({ this.initialize({
args: this.args, args: this.args,
query: route.query,
remoteAuthority: request.headers.host as string, remoteAuthority: request.headers.host as string,
settings, startPath,
}), }),
]) ])
this.workbenchOptions = options this.workbenchOptions = options
if (options.startPath) { if (startPath) {
this.settings.write({ this.settings.write({
lastVisited: { lastVisited: startPath,
path: options.startPath.path,
workspace: options.startPath.workspace,
},
}) })
} }
@ -201,4 +210,40 @@ export class VscodeHttpProvider extends HttpProvider {
response.content = response.content.replace(/{{COMMIT}}/g, this.options.commit).replace(/{{ERROR}}/g, message) response.content = response.content.replace(/{{COMMIT}}/g, this.options.commit).replace(/{{ERROR}}/g, message)
return response return response
} }
/**
* Choose the first valid path. If `workspace` is undefined then either a
* workspace or a directory are acceptable. Otherwise it must be a file if a
* workspace or a directory otherwise.
*/
private async getFirstValidPath(
startPaths: Array<{ url?: string | string[]; workspace?: boolean } | undefined>
): Promise<StartPath | undefined> {
for (let i = 0; i < startPaths.length; ++i) {
const startPath = startPaths[i]
if (!startPath) {
continue
}
const paths = typeof startPath.url === "string" ? [startPath.url] : startPath.url || []
for (let j = 0; j < paths.length; ++j) {
const u = url.parse(paths[j])
try {
if (!u.pathname) {
throw new Error(`${paths[j]} is not a valid URL`)
}
const stat = await fs.stat(u.pathname)
if (typeof startPath.workspace === "undefined" || startPath.workspace !== stat.isDirectory()) {
return { url: u.href, workspace: !stat.isDirectory() }
}
} catch (error) {
logger.warn(error.message)
}
}
}
return undefined
}
private urlify(p: string): string {
return "vscode-remote://host" + path.resolve(p)
}
} }