Skip to content

Commit 5651201

Browse files
committed
Copy old macOS data directory if applicable
1 parent f475767 commit 5651201

File tree

3 files changed

+117
-90
lines changed

3 files changed

+117
-90
lines changed

src/node/cli.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { field, Level, logger } from "@coder/logger"
22
import * as fs from "fs-extra"
33
import yaml from "js-yaml"
4+
import * as os from "os"
45
import * as path from "path"
56
import { Args as VsArgs } from "../../lib/vscode/src/vs/server/ipc"
67
import { AuthType } from "./http"
@@ -151,12 +152,12 @@ export const optionDescriptions = (): string[] => {
151152
)
152153
}
153154

154-
export const parse = (
155+
export const parse = async (
155156
argv: string[],
156157
opts?: {
157158
configFile: string
158159
},
159-
): Args => {
160+
): Promise<Args> => {
160161
const error = (msg: string): Error => {
161162
if (opts?.configFile) {
162163
msg = `error reading ${opts.configFile}: ${msg}`
@@ -300,6 +301,7 @@ export const parse = (
300301
}
301302

302303
if (!args["user-data-dir"]) {
304+
await copyOldMacOSDataDir()
303305
args["user-data-dir"] = paths.data
304306
}
305307

@@ -351,7 +353,7 @@ export async function readConfigFile(configPath?: string): Promise<Args> {
351353
}
352354
return `--${optName}=${opt}`
353355
})
354-
const args = parse(configFileArgv, {
356+
const args = await parse(configFileArgv, {
355357
configFile: configPath,
356358
})
357359
return {
@@ -400,3 +402,18 @@ export function bindAddrFromAllSources(cliArgs: Args, configArgs: Args): [string
400402

401403
return [addr.host, addr.port]
402404
}
405+
406+
async function copyOldMacOSDataDir(): Promise<void> {
407+
if (os.platform() !== "darwin") {
408+
return
409+
}
410+
if (await fs.pathExists(paths.data)) {
411+
return
412+
}
413+
414+
// If the old data directory exists, we copy it in.
415+
const oldDataDir = path.join(os.homedir(), "Library/Application Support", "code-server")
416+
if (await fs.pathExists(oldDataDir)) {
417+
await fs.copy(oldDataDir, paths.data)
418+
}
419+
}

src/node/entry.ts

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -125,58 +125,62 @@ const main = async (cliArgs: Args): Promise<void> => {
125125
}
126126
}
127127

128-
const tryParse = (): Args => {
129-
try {
130-
return parse(process.argv.slice(2))
131-
} catch (error) {
132-
console.error(error.message)
133-
process.exit(1)
128+
async function entry(): Promise<void> {
129+
const tryParse = async (): Promise<Args> => {
130+
try {
131+
return await parse(process.argv.slice(2))
132+
} catch (error) {
133+
console.error(error.message)
134+
process.exit(1)
135+
}
134136
}
135-
}
136137

137-
const args = tryParse()
138-
if (args.help) {
139-
console.log("code-server", version, commit)
140-
console.log("")
141-
console.log(`Usage: code-server [options] [path]`)
142-
console.log("")
143-
console.log("Options")
144-
optionDescriptions().forEach((description) => {
145-
console.log("", description)
146-
})
147-
} else if (args.version) {
148-
if (args.json) {
149-
console.log({
150-
codeServer: version,
151-
commit,
152-
vscode: require("../../lib/vscode/package.json").version,
138+
const args = await tryParse()
139+
if (args.help) {
140+
console.log("code-server", version, commit)
141+
console.log("")
142+
console.log(`Usage: code-server [options] [path]`)
143+
console.log("")
144+
console.log("Options")
145+
optionDescriptions().forEach((description) => {
146+
console.log("", description)
147+
})
148+
} else if (args.version) {
149+
if (args.json) {
150+
console.log({
151+
codeServer: version,
152+
commit,
153+
vscode: require("../../lib/vscode/package.json").version,
154+
})
155+
} else {
156+
console.log(version, commit)
157+
}
158+
process.exit(0)
159+
} else if (args["list-extensions"] || args["install-extension"] || args["uninstall-extension"]) {
160+
logger.debug("forking vs code cli...")
161+
const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], {
162+
env: {
163+
...process.env,
164+
CODE_SERVER_PARENT_PID: process.pid.toString(),
165+
},
153166
})
167+
vscode.once("message", (message) => {
168+
logger.debug("Got message from VS Code", field("message", message))
169+
if (message.type !== "ready") {
170+
logger.error("Unexpected response waiting for ready response")
171+
process.exit(1)
172+
}
173+
const send: CliMessage = { type: "cli", args }
174+
vscode.send(send)
175+
})
176+
vscode.once("error", (error) => {
177+
logger.error(error.message)
178+
process.exit(1)
179+
})
180+
vscode.on("exit", (code) => process.exit(code || 0))
154181
} else {
155-
console.log(version, commit)
182+
wrap(() => main(args))
156183
}
157-
process.exit(0)
158-
} else if (args["list-extensions"] || args["install-extension"] || args["uninstall-extension"]) {
159-
logger.debug("forking vs code cli...")
160-
const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], {
161-
env: {
162-
...process.env,
163-
CODE_SERVER_PARENT_PID: process.pid.toString(),
164-
},
165-
})
166-
vscode.once("message", (message) => {
167-
logger.debug("Got message from VS Code", field("message", message))
168-
if (message.type !== "ready") {
169-
logger.error("Unexpected response waiting for ready response")
170-
process.exit(1)
171-
}
172-
const send: CliMessage = { type: "cli", args }
173-
vscode.send(send)
174-
})
175-
vscode.once("error", (error) => {
176-
logger.error(error.message)
177-
process.exit(1)
178-
})
179-
vscode.on("exit", (code) => process.exit(code || 0))
180-
} else {
181-
wrap(() => main(args))
182184
}
185+
186+
entry()

test/cli.test.ts

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ describe("cli", () => {
1616
"user-data-dir": paths.data,
1717
}
1818

19-
it("should set defaults", () => {
20-
assert.deepEqual(parse([]), defaults)
19+
it("should set defaults", async () => {
20+
assert.deepEqual(await await parse([]), defaults)
2121
})
2222

23-
it("should parse all available options", () => {
23+
it("should parse all available options", async () => {
2424
assert.deepEqual(
25-
parse([
25+
await await parse([
2626
"--bind-addr=192.169.0.1:8080",
2727
"--auth",
2828
"none",
@@ -84,8 +84,8 @@ describe("cli", () => {
8484
)
8585
})
8686

87-
it("should work with short options", () => {
88-
assert.deepEqual(parse(["-vvv", "-v"]), {
87+
it("should work with short options", async () => {
88+
assert.deepEqual(await parse(["-vvv", "-v"]), {
8989
...defaults,
9090
log: "trace",
9191
verbose: true,
@@ -95,17 +95,17 @@ describe("cli", () => {
9595
assert.equal(logger.level, Level.Trace)
9696
})
9797

98-
it("should use log level env var", () => {
98+
it("should use log level env var", async () => {
9999
process.env.LOG_LEVEL = "debug"
100-
assert.deepEqual(parse([]), {
100+
assert.deepEqual(await parse([]), {
101101
...defaults,
102102
log: "debug",
103103
})
104104
assert.equal(process.env.LOG_LEVEL, "debug")
105105
assert.equal(logger.level, Level.Debug)
106106

107107
process.env.LOG_LEVEL = "trace"
108-
assert.deepEqual(parse([]), {
108+
assert.deepEqual(await parse([]), {
109109
...defaults,
110110
log: "trace",
111111
verbose: true,
@@ -114,25 +114,25 @@ describe("cli", () => {
114114
assert.equal(logger.level, Level.Trace)
115115
})
116116

117-
it("should prefer --log to env var and --verbose to --log", () => {
117+
it("should prefer --log to env var and --verbose to --log", async () => {
118118
process.env.LOG_LEVEL = "debug"
119-
assert.deepEqual(parse(["--log", "info"]), {
119+
assert.deepEqual(await parse(["--log", "info"]), {
120120
...defaults,
121121
log: "info",
122122
})
123123
assert.equal(process.env.LOG_LEVEL, "info")
124124
assert.equal(logger.level, Level.Info)
125125

126126
process.env.LOG_LEVEL = "trace"
127-
assert.deepEqual(parse(["--log", "info"]), {
127+
assert.deepEqual(await parse(["--log", "info"]), {
128128
...defaults,
129129
log: "info",
130130
})
131131
assert.equal(process.env.LOG_LEVEL, "info")
132132
assert.equal(logger.level, Level.Info)
133133

134134
process.env.LOG_LEVEL = "warn"
135-
assert.deepEqual(parse(["--log", "info", "--verbose"]), {
135+
assert.deepEqual(await parse(["--log", "info", "--verbose"]), {
136136
...defaults,
137137
log: "trace",
138138
verbose: true,
@@ -141,62 +141,68 @@ describe("cli", () => {
141141
assert.equal(logger.level, Level.Trace)
142142
})
143143

144-
it("should ignore invalid log level env var", () => {
144+
it("should ignore invalid log level env var", async () => {
145145
process.env.LOG_LEVEL = "bogus"
146-
assert.deepEqual(parse([]), defaults)
146+
assert.deepEqual(await parse([]), defaults)
147147
})
148148

149-
it("should error if value isn't provided", () => {
150-
assert.throws(() => parse(["--auth"]), /--auth requires a value/)
151-
assert.throws(() => parse(["--auth=", "--log=debug"]), /--auth requires a value/)
152-
assert.throws(() => parse(["--auth", "--log"]), /--auth requires a value/)
153-
assert.throws(() => parse(["--auth", "--invalid"]), /--auth requires a value/)
154-
assert.throws(() => parse(["--bind-addr"]), /--bind-addr requires a value/)
149+
it("should error if value isn't provided", async () => {
150+
await assert.rejects(async () => await parse(["--auth"]), /--auth requires a value/)
151+
await assert.rejects(async () => await parse(["--auth=", "--log=debug"]), /--auth requires a value/)
152+
await assert.rejects(async () => await parse(["--auth", "--log"]), /--auth requires a value/)
153+
await assert.rejects(async () => await parse(["--auth", "--invalid"]), /--auth requires a value/)
154+
await assert.rejects(async () => await parse(["--bind-addr"]), /--bind-addr requires a value/)
155155
})
156156

157-
it("should error if value is invalid", () => {
158-
assert.throws(() => parse(["--port", "foo"]), /--port must be a number/)
159-
assert.throws(() => parse(["--auth", "invalid"]), /--auth valid values: \[password, none\]/)
160-
assert.throws(() => parse(["--log", "invalid"]), /--log valid values: \[trace, debug, info, warn, error\]/)
157+
it("should error if value is invalid", async () => {
158+
await assert.rejects(async () => await parse(["--port", "foo"]), /--port must be a number/)
159+
await assert.rejects(async () => await parse(["--auth", "invalid"]), /--auth valid values: \[password, none\]/)
160+
await assert.rejects(
161+
async () => await parse(["--log", "invalid"]),
162+
/--log valid values: \[trace, debug, info, warn, error\]/,
163+
)
161164
})
162165

163-
it("should error if the option doesn't exist", () => {
164-
assert.throws(() => parse(["--foo"]), /Unknown option --foo/)
166+
it("should error if the option doesn't exist", async () => {
167+
await assert.rejects(async () => await parse(["--foo"]), /Unknown option --foo/)
165168
})
166169

167-
it("should not error if the value is optional", () => {
168-
assert.deepEqual(parse(["--cert"]), {
170+
it("should not error if the value is optional", async () => {
171+
assert.deepEqual(await parse(["--cert"]), {
169172
...defaults,
170173
cert: {
171174
value: undefined,
172175
},
173176
})
174177
})
175178

176-
it("should not allow option-like values", () => {
177-
assert.throws(() => parse(["--socket", "--socket-path-value"]), /--socket requires a value/)
179+
it("should not allow option-like values", async () => {
180+
await assert.rejects(async () => await parse(["--socket", "--socket-path-value"]), /--socket requires a value/)
178181
// If you actually had a path like this you would do this instead:
179-
assert.deepEqual(parse(["--socket", "./--socket-path-value"]), {
182+
assert.deepEqual(await parse(["--socket", "./--socket-path-value"]), {
180183
...defaults,
181184
socket: path.resolve("--socket-path-value"),
182185
})
183-
assert.throws(() => parse(["--cert", "--socket-path-value"]), /Unknown option --socket-path-value/)
186+
await assert.rejects(
187+
async () => await parse(["--cert", "--socket-path-value"]),
188+
/Unknown option --socket-path-value/,
189+
)
184190
})
185191

186-
it("should allow positional arguments before options", () => {
187-
assert.deepEqual(parse(["foo", "test", "--auth", "none"]), {
192+
it("should allow positional arguments before options", async () => {
193+
assert.deepEqual(await parse(["foo", "test", "--auth", "none"]), {
188194
...defaults,
189195
_: ["foo", "test"],
190196
auth: "none",
191197
})
192198
})
193199

194-
it("should support repeatable flags", () => {
195-
assert.deepEqual(parse(["--proxy-domain", "*.coder.com"]), {
200+
it("should support repeatable flags", async () => {
201+
assert.deepEqual(await parse(["--proxy-domain", "*.coder.com"]), {
196202
...defaults,
197203
"proxy-domain": ["*.coder.com"],
198204
})
199-
assert.deepEqual(parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "test.com"]), {
205+
assert.deepEqual(await parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "test.com"]), {
200206
...defaults,
201207
"proxy-domain": ["*.coder.com", "test.com"],
202208
})

0 commit comments

Comments
 (0)