Skip to content

Commit 2e9a8fb

Browse files
authored
Merge branch 'main' into patch-2
2 parents ba0a6c9 + 1b60ef4 commit 2e9a8fb

File tree

20 files changed

+326
-278
lines changed

20 files changed

+326
-278
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ jobs:
142142
path: |
143143
vendor/modules/code-oss-dev/.build
144144
vendor/modules/code-oss-dev/out-build
145-
vendor/modules/code-oss-dev/out-vscode-server
146-
vendor/modules/code-oss-dev/out-vscode-server-min
147-
key: vscode-server-build-${{ steps.vscode-rev.outputs.rev }}
145+
vendor/modules/code-oss-dev/out-vscode-reh-web
146+
vendor/modules/code-oss-dev/out-vscode-reh-web-min
147+
key: vscode-reh-build-${{ steps.vscode-rev.outputs.rev }}
148148

149149
- name: Build vscode
150150
if: steps.cache-vscode.outputs.cache-hit != 'true'

ci/build/build-release.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ EOF
6767
bundle_vscode() {
6868
mkdir -p "$VSCODE_OUT_PATH"
6969
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
70-
rsync "$VSCODE_SRC_PATH/out-vscode-server${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
70+
rsync "$VSCODE_SRC_PATH/out-vscode-reh-web${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
7171

7272
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
7373
if [ "$KEEP_MODULES" = 0 ]; then
@@ -88,7 +88,7 @@ bundle_vscode() {
8888
cat << EOF
8989
{
9090
"enableTelemetry": true,
91-
"commit": "$(git rev-parse HEAD)",
91+
"commit": "$(cd "$VSCODE_SRC_PATH" && git rev-parse HEAD)",
9292
"quality": "stable",
9393
"date": $(jq -n 'now | todate')
9494
}

ci/build/build-vscode.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ main() {
1111

1212
cd vendor/modules/code-oss-dev
1313

14-
# extensions-ci compiles extensions and includes their media.
15-
# compile-web compiles web extensions. TODO: Unsure if used.
16-
yarn gulp extensions-ci compile-web "vscode-server${MINIFY:+-min}"
14+
# Any platform works since we have our own packaging step (for now).
15+
yarn gulp "vscode-reh-web-linux-x64${MINIFY:+-min}"
1716
}
1817

1918
main "$@"

docs/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ access it in the browser.
1414
- Preserve battery life when you're on the go; all intensive tasks run on your
1515
server
1616

17+
| 🔔 code-server is a free browser-based IDE while [Coder](https://coder.com/), is our enterprise developer workspace platform. For more information, visit [Coder.com](https://coder.com/docs/comparison)
18+
| ---
19+
1720
## Requirements
1821

1922
See [requirements](requirements.md) for minimum specs, as well as instructions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"lint": "./ci/dev/lint.sh",
2929
"test": "echo 'Run yarn test:unit or yarn test:e2e' && exit 1",
3030
"ci": "./ci/dev/ci.sh",
31-
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS='--max_old_space_size=32384 --trace-warnings' ts-node ./ci/dev/watch.ts",
31+
"watch": "VSCODE_DEV=1 VSCODE_IPC_HOOK_CLI= NODE_OPTIONS='--max_old_space_size=32384 --trace-warnings' ts-node ./ci/dev/watch.ts",
3232
"icons": "./ci/dev/gen_icons.sh",
3333
"coverage": "codecov"
3434
},

src/node/cli.ts

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@ import { promises as fs } from "fs"
33
import yaml from "js-yaml"
44
import * as os from "os"
55
import * as path from "path"
6-
import { canConnect, generateCertificate, generatePassword, humanPath, paths, isNodeJSErrnoException } from "./util"
6+
import {
7+
canConnect,
8+
generateCertificate,
9+
generatePassword,
10+
humanPath,
11+
paths,
12+
isNodeJSErrnoException,
13+
isFile,
14+
} from "./util"
715

816
const DEFAULT_SOCKET_PATH = path.join(os.tmpdir(), "vscode-ipc")
917

@@ -31,53 +39,53 @@ export enum LogLevel {
3139

3240
export class OptionalString extends Optional<string> {}
3341

34-
export interface Args
35-
extends Pick<
36-
CodeServerLib.NativeParsedArgs,
37-
| "_"
38-
| "user-data-dir"
39-
| "enable-proposed-api"
40-
| "extensions-dir"
41-
| "builtin-extensions-dir"
42-
| "extra-extensions-dir"
43-
| "extra-builtin-extensions-dir"
44-
| "ignore-last-opened"
45-
| "locale"
46-
| "log"
47-
| "verbose"
48-
| "install-source"
49-
| "list-extensions"
50-
| "install-extension"
51-
| "uninstall-extension"
52-
| "locate-extension"
53-
// | "telemetry"
54-
> {
42+
/**
43+
* Arguments that the user explicitly provided on the command line. All
44+
* arguments must be optional.
45+
*
46+
* For arguments with defaults see DefaultedArgs.
47+
*/
48+
export interface UserProvidedArgs {
5549
config?: string
5650
auth?: AuthType
5751
password?: string
5852
"hashed-password"?: string
5953
cert?: OptionalString
6054
"cert-host"?: string
6155
"cert-key"?: string
62-
"disable-telemetry"?: boolean
6356
"disable-update-check"?: boolean
6457
enable?: string[]
6558
help?: boolean
6659
host?: string
60+
port?: number
6761
json?: boolean
6862
log?: LogLevel
6963
open?: boolean
70-
port?: number
7164
"bind-addr"?: string
7265
socket?: string
7366
version?: boolean
74-
force?: boolean
75-
"show-versions"?: boolean
7667
"proxy-domain"?: string[]
7768
"reuse-window"?: boolean
7869
"new-window"?: boolean
79-
70+
"ignore-last-opened"?: boolean
8071
link?: OptionalString
72+
verbose?: boolean
73+
/* Positional arguments. */
74+
_?: string[]
75+
76+
// VS Code flags.
77+
"disable-telemetry"?: boolean
78+
force?: boolean
79+
"user-data-dir"?: string
80+
"enable-proposed-api"?: string[]
81+
"extensions-dir"?: string
82+
"builtin-extensions-dir"?: string
83+
"install-extension"?: string[]
84+
"uninstall-extension"?: string[]
85+
"list-extensions"?: boolean
86+
"locate-extension"?: string[]
87+
"show-versions"?: boolean
88+
category?: string
8189
}
8290

8391
interface Option<T> {
@@ -121,7 +129,7 @@ type Options<T> = {
121129
[P in keyof T]: Option<OptionType<T[P]>>
122130
}
123131

124-
const options: Options<Required<Args>> = {
132+
const options: Options<Required<UserProvidedArgs>> = {
125133
auth: { type: AuthType, description: "The type of authentication to use." },
126134
password: {
127135
type: "string",
@@ -178,12 +186,10 @@ const options: Options<Required<Args>> = {
178186
"user-data-dir": { type: "string", path: true, description: "Path to the user data directory." },
179187
"extensions-dir": { type: "string", path: true, description: "Path to the extensions directory." },
180188
"builtin-extensions-dir": { type: "string", path: true },
181-
"extra-extensions-dir": { type: "string[]", path: true },
182-
"extra-builtin-extensions-dir": { type: "string[]", path: true },
183189
"list-extensions": { type: "boolean", description: "List installed VS Code extensions." },
184190
force: { type: "boolean", description: "Avoid prompts when installing VS Code extensions." },
185-
"install-source": { type: "string" },
186191
"locate-extension": { type: "string[]" },
192+
category: { type: "string" },
187193
"install-extension": {
188194
type: "string[]",
189195
description:
@@ -214,7 +220,6 @@ const options: Options<Required<Args>> = {
214220
description: "Force to open a file or folder in an already opened window.",
215221
},
216222

217-
locale: { type: "string" },
218223
log: { type: LogLevel },
219224
verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." },
220225

@@ -271,12 +276,16 @@ export function splitOnFirstEquals(str: string): string[] {
271276
return split
272277
}
273278

279+
/**
280+
* Parse arguments into UserProvidedArgs. This should not go beyond checking
281+
* that arguments are valid types and have values when required.
282+
*/
274283
export const parse = (
275284
argv: string[],
276285
opts?: {
277286
configFile?: string
278287
},
279-
): Args => {
288+
): UserProvidedArgs => {
280289
const error = (msg: string): Error => {
281290
if (opts?.configFile) {
282291
msg = `error reading ${opts.configFile}: ${msg}`
@@ -285,7 +294,7 @@ export const parse = (
285294
return new Error(msg)
286295
}
287296

288-
const args: Args = { _: [] }
297+
const args: UserProvidedArgs = {}
289298
let ended = false
290299

291300
for (let i = 0; i < argv.length; ++i) {
@@ -299,17 +308,17 @@ export const parse = (
299308

300309
// Options start with a dash and require a value if non-boolean.
301310
if (!ended && arg.startsWith("-")) {
302-
let key: keyof Args | undefined
311+
let key: keyof UserProvidedArgs | undefined
303312
let value: string | undefined
304313
if (arg.startsWith("--")) {
305314
const split = splitOnFirstEquals(arg.replace(/^--/, ""))
306-
key = split[0] as keyof Args
315+
key = split[0] as keyof UserProvidedArgs
307316
value = split[1]
308317
} else {
309318
const short = arg.replace(/^-/, "")
310319
const pair = Object.entries(options).find(([, v]) => v.short === short)
311320
if (pair) {
312-
key = pair[0] as keyof Args
321+
key = pair[0] as keyof UserProvidedArgs
313322
}
314323
}
315324

@@ -384,6 +393,10 @@ export const parse = (
384393
}
385394

386395
// Everything else goes into _.
396+
if (typeof args._ === "undefined") {
397+
args._ = []
398+
}
399+
387400
args._.push(arg)
388401
}
389402

@@ -397,6 +410,11 @@ export const parse = (
397410
return args
398411
}
399412

413+
/**
414+
* User-provided arguments with defaults. The distinction between user-provided
415+
* args and defaulted args exists so we can tell the difference between end
416+
* values and what the user actually provided on the command line.
417+
*/
400418
export interface DefaultedArgs extends ConfigArgs {
401419
auth: AuthType
402420
cert?: {
@@ -410,14 +428,18 @@ export interface DefaultedArgs extends ConfigArgs {
410428
usingEnvHashedPassword: boolean
411429
"extensions-dir": string
412430
"user-data-dir": string
431+
/* Positional arguments. */
432+
_: []
433+
folder: string
434+
workspace: string
413435
}
414436

415437
/**
416438
* Take CLI and config arguments (optional) and return a single set of arguments
417439
* with the defaults set. Arguments from the CLI are prioritized over config
418440
* arguments.
419441
*/
420-
export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promise<DefaultedArgs> {
442+
export async function setDefaults(cliArgs: UserProvidedArgs, configArgs?: ConfigArgs): Promise<DefaultedArgs> {
421443
const args = Object.assign({}, configArgs || {}, cliArgs)
422444

423445
if (!args["user-data-dir"]) {
@@ -472,7 +494,7 @@ export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promi
472494
args.auth = AuthType.Password
473495
}
474496

475-
const addr = bindAddrFromAllSources(configArgs || { _: [] }, cliArgs)
497+
const addr = bindAddrFromAllSources(configArgs || {}, cliArgs)
476498
args.host = addr.host
477499
args.port = addr.port
478500

@@ -513,8 +535,29 @@ export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promi
513535
const proxyDomains = new Set((args["proxy-domain"] || []).map((d) => d.replace(/^\*\./, "")))
514536
args["proxy-domain"] = Array.from(proxyDomains)
515537

538+
if (typeof args._ === "undefined") {
539+
args._ = []
540+
}
541+
542+
let workspace = ""
543+
let folder = ""
544+
if (args._.length) {
545+
const lastEntry = path.resolve(process.cwd(), args._[args._.length - 1])
546+
const entryIsFile = await isFile(lastEntry)
547+
548+
if (entryIsFile && path.extname(lastEntry) === ".code-workspace") {
549+
workspace = lastEntry
550+
args._.pop()
551+
} else if (!entryIsFile) {
552+
folder = lastEntry
553+
args._.pop()
554+
}
555+
}
556+
516557
return {
517558
...args,
559+
workspace,
560+
folder,
518561
usingEnvPassword,
519562
usingEnvHashedPassword,
520563
} as DefaultedArgs // TODO: Technically no guarantee this is fulfilled.
@@ -539,7 +582,7 @@ cert: false
539582
`
540583
}
541584

542-
interface ConfigArgs extends Args {
585+
interface ConfigArgs extends UserProvidedArgs {
543586
config: string
544587
}
545588

@@ -581,7 +624,7 @@ export async function readConfigFile(configPath?: string): Promise<ConfigArgs> {
581624
*/
582625
export function parseConfigFile(configFile: string, configPath: string): ConfigArgs {
583626
if (!configFile) {
584-
return { _: [], config: configPath }
627+
return { config: configPath }
585628
}
586629

587630
const config = yaml.load(configFile, {
@@ -628,7 +671,7 @@ interface Addr {
628671
* This function creates the bind address
629672
* using the CLI args.
630673
*/
631-
export function bindAddrFromArgs(addr: Addr, args: Args): Addr {
674+
export function bindAddrFromArgs(addr: Addr, args: UserProvidedArgs): Addr {
632675
addr = { ...addr }
633676
if (args["bind-addr"]) {
634677
addr = parseBindAddr(args["bind-addr"])
@@ -646,7 +689,7 @@ export function bindAddrFromArgs(addr: Addr, args: Args): Addr {
646689
return addr
647690
}
648691

649-
function bindAddrFromAllSources(...argsConfig: Args[]): Addr {
692+
function bindAddrFromAllSources(...argsConfig: UserProvidedArgs[]): Addr {
650693
let addr: Addr = {
651694
host: "localhost",
652695
port: 8080,
@@ -683,30 +726,34 @@ export async function readSocketPath(path: string): Promise<string | undefined>
683726
/**
684727
* Determine if it looks like the user is trying to open a file or folder in an
685728
* existing instance. The arguments here should be the arguments the user
686-
* explicitly passed on the command line, not defaults or the configuration.
729+
* explicitly passed on the command line, *NOT DEFAULTS* or the configuration.
687730
*/
688-
export const shouldOpenInExistingInstance = async (args: Args): Promise<string | undefined> => {
731+
export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Promise<string | undefined> => {
689732
// Always use the existing instance if we're running from VS Code's terminal.
690733
if (process.env.VSCODE_IPC_HOOK_CLI) {
734+
logger.debug("Found VSCODE_IPC_HOOK_CLI")
691735
return process.env.VSCODE_IPC_HOOK_CLI
692736
}
693737

694738
// If these flags are set then assume the user is trying to open in an
695739
// existing instance since these flags have no effect otherwise.
696740
const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => {
697-
return args[cur as keyof Args] ? prev + 1 : prev
741+
return args[cur as keyof UserProvidedArgs] ? prev + 1 : prev
698742
}, 0)
699743
if (openInFlagCount > 0) {
744+
logger.debug("Found --reuse-window or --new-window")
700745
return readSocketPath(DEFAULT_SOCKET_PATH)
701746
}
702747

703748
// It's possible the user is trying to spawn another instance of code-server.
704-
// Check if any unrelated flags are set (check against one because `_` always
705-
// exists), that a file or directory was passed, and that the socket is
706-
// active.
707-
if (Object.keys(args).length === 1 && args._.length > 0) {
749+
// 1. Check if any unrelated flags are set (this should only run when
750+
// code-server is invoked exactly like this: `code-server my-file`).
751+
// 2. That a file or directory was passed.
752+
// 3. That the socket is active.
753+
if (Object.keys(args).length === 1 && typeof args._ !== "undefined" && args._.length > 0) {
708754
const socketPath = await readSocketPath(DEFAULT_SOCKET_PATH)
709755
if (socketPath && (await canConnect(socketPath))) {
756+
logger.debug("Found existing code-server socket")
710757
return socketPath
711758
}
712759
}

0 commit comments

Comments
 (0)