Skip to content

Commit 016daf2

Browse files
committed
Parse arguments once
Fixes #2316.
1 parent 247c4ec commit 016daf2

File tree

2 files changed

+51
-27
lines changed

2 files changed

+51
-27
lines changed

src/node/entry.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,22 @@ const main = async (args: DefaultedArgs): Promise<void> => {
154154
}
155155

156156
async function entry(): Promise<void> {
157-
const cliArgs = parse(process.argv.slice(2))
158-
const configArgs = await readConfigFile(cliArgs.config)
159-
const args = await setDefaults(cliArgs, configArgs)
160-
161157
// There's no need to check flags like --help or to spawn in an existing
162158
// instance for the child process because these would have already happened in
163-
// the parent and the child wouldn't have been spawned.
159+
// the parent and the child wouldn't have been spawned. We also get the
160+
// arguments from the parent so we don't have to parse twice and to account
161+
// for environment manipulation (like how PASSWORD gets removed to avoid
162+
// leaking to child processes).
164163
if (isChild(wrapper)) {
165-
await wrapper.handshake()
164+
const args = await wrapper.handshake()
166165
wrapper.preventExit()
167166
return main(args)
168167
}
169168

169+
const cliArgs = parse(process.argv.slice(2))
170+
const configArgs = await readConfigFile(cliArgs.config)
171+
const args = await setDefaults(cliArgs, configArgs)
172+
170173
if (args.help) {
171174
console.log("code-server", version, commit)
172175
console.log("")
@@ -201,7 +204,7 @@ async function entry(): Promise<void> {
201204
return openInExistingInstance(args, socketPath)
202205
}
203206

204-
return wrapper.start()
207+
return wrapper.start(args)
205208
}
206209

207210
entry().catch((error) => {

src/node/wrapper.ts

+41-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Logger, field, logger } from "@coder/logger"
1+
import { field, Logger, logger } from "@coder/logger"
22
import * as cp from "child_process"
33
import * as path from "path"
44
import * as rfs from "rotating-file-stream"
55
import { Emitter } from "../common/emitter"
6+
import { DefaultedArgs } from "./cli"
67
import { paths } from "./util"
78

89
const timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
@@ -58,7 +59,12 @@ export function onMessage<M, T extends M>(
5859
})
5960
}
6061

61-
interface HandshakeMessage {
62+
interface ParentHandshakeMessage {
63+
type: "handshake"
64+
args: DefaultedArgs
65+
}
66+
67+
interface ChildHandshakeMessage {
6268
type: "handshake"
6369
}
6470

@@ -67,7 +73,8 @@ interface RelaunchMessage {
6773
version: string
6874
}
6975

70-
type Message = RelaunchMessage | HandshakeMessage
76+
type ChildMessage = RelaunchMessage | ChildHandshakeMessage
77+
type ParentMessage = ParentHandshakeMessage
7178

7279
class ProcessError extends Error {
7380
public constructor(message: string, public readonly code: number | undefined) {
@@ -164,15 +171,16 @@ class ChildProcess extends Process {
164171
/**
165172
* Initiate the handshake and wait for a response from the parent.
166173
*/
167-
public async handshake(): Promise<void> {
174+
public async handshake(): Promise<DefaultedArgs> {
168175
this.send({ type: "handshake" })
169-
await onMessage<Message, HandshakeMessage>(
176+
const message = await onMessage<ParentMessage, ParentHandshakeMessage>(
170177
process,
171-
(message): message is HandshakeMessage => {
178+
(message): message is ParentHandshakeMessage => {
172179
return message.type === "handshake"
173180
},
174181
this.logger,
175182
)
183+
return message.args
176184
}
177185

178186
/**
@@ -185,7 +193,7 @@ class ChildProcess extends Process {
185193
/**
186194
* Send a message to the parent.
187195
*/
188-
private send(message: Message): void {
196+
private send(message: ChildMessage): void {
189197
if (!process.send) {
190198
throw new Error("not spawned with IPC")
191199
}
@@ -211,12 +219,19 @@ export class ParentProcess extends Process {
211219
private readonly logStdoutStream: rfs.RotatingFileStream
212220
private readonly logStderrStream: rfs.RotatingFileStream
213221

214-
protected readonly _onChildMessage = new Emitter<Message>()
222+
protected readonly _onChildMessage = new Emitter<ChildMessage>()
215223
protected readonly onChildMessage = this._onChildMessage.event
216224

225+
private args?: DefaultedArgs
226+
217227
public constructor(private currentVersion: string, private readonly options?: WrapperOptions) {
218228
super()
219229

230+
process.on("SIGUSR1", async () => {
231+
this.logger.info("Received SIGUSR1; hotswapping")
232+
this.relaunch()
233+
})
234+
220235
const opts = {
221236
size: "10M",
222237
maxFiles: 10,
@@ -253,21 +268,17 @@ export class ParentProcess extends Process {
253268
private async relaunch(): Promise<void> {
254269
this.disposeChild()
255270
try {
256-
await this.start()
271+
this.started = this._start()
272+
await this.started
257273
} catch (error) {
258274
this.logger.error(error.message)
259275
this.exit(typeof error.code === "number" ? error.code : 1)
260276
}
261277
}
262278

263-
public start(): Promise<void> {
264-
// If we have a process then we've already bound this.
265-
if (!this.child) {
266-
process.on("SIGUSR1", async () => {
267-
this.logger.info("Received SIGUSR1; hotswapping")
268-
this.relaunch()
269-
})
270-
}
279+
public start(args: DefaultedArgs): Promise<void> {
280+
// Store for relaunches.
281+
this.args = args
271282
if (!this.started) {
272283
this.started = this._start()
273284
}
@@ -320,14 +331,24 @@ export class ParentProcess extends Process {
320331
* Wait for a handshake from the child then reply.
321332
*/
322333
private async handshake(child: cp.ChildProcess): Promise<void> {
323-
await onMessage<Message, HandshakeMessage>(
334+
if (!this.args) {
335+
throw new Error("started without args")
336+
}
337+
await onMessage<ChildMessage, ChildHandshakeMessage>(
324338
child,
325-
(message): message is HandshakeMessage => {
339+
(message): message is ChildHandshakeMessage => {
326340
return message.type === "handshake"
327341
},
328342
this.logger,
329343
)
330-
child.send({ type: "handshake" })
344+
this.send(child, { type: "handshake", args: this.args })
345+
}
346+
347+
/**
348+
* Send a message to the child.
349+
*/
350+
private send(child: cp.ChildProcess, message: ParentMessage): void {
351+
child.send(message)
331352
}
332353
}
333354

0 commit comments

Comments
 (0)