Skip to content

Commit 78658f1

Browse files
jsjoeiocode-asher
andauthored
refactor: remove folder/workspace from vsCodeCliArgs (#4932)
* refactor: remove folder/workspace from vsCodeCliArgs Since we handle this in the vscode.ts route, we no longer need to pass it to VS Code as a CLI arg since it's deprecated on that side. * feat(vscode): redirect to folder from cli * Update src/node/routes/vscode.ts Co-authored-by: Asher <[email protected]> * fixup!: update _: type * fixup!: move vars to lower if block * fixup!: share redirect block * fixup!: mmove req.query.ew block into if * fixup!: refactor vscode tests * refactor: make vscode.ts logic easier to read * fixup!: fix broken tests and clean up logic * chore: upgrade vscode version * fixup!: delete unnecessary if closed block * Update src/node/routes/vscode.ts Co-authored-by: Asher <[email protected]> * fixup!: rename to FOLDER_OR_WORKSPACE_WAS_CLOSED Co-authored-by: Asher <[email protected]>
1 parent b018112 commit 78658f1

File tree

6 files changed

+73
-128
lines changed

6 files changed

+73
-128
lines changed

src/node/cli.ts

+2-26
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,7 @@ 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 {
7-
canConnect,
8-
generateCertificate,
9-
generatePassword,
10-
humanPath,
11-
paths,
12-
isNodeJSErrnoException,
13-
isFile,
14-
} from "./util"
6+
import { canConnect, generateCertificate, generatePassword, humanPath, paths, isNodeJSErrnoException } from "./util"
157

168
const DEFAULT_SOCKET_PATH = path.join(os.tmpdir(), "vscode-ipc")
179

@@ -448,7 +440,7 @@ export interface DefaultedArgs extends ConfigArgs {
448440
"extensions-dir": string
449441
"user-data-dir": string
450442
/* Positional arguments. */
451-
_: []
443+
_: string[]
452444
}
453445

454446
/**
@@ -770,25 +762,9 @@ export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Prom
770762
* Convert our arguments to VS Code server arguments.
771763
*/
772764
export const toVsCodeArgs = async (args: DefaultedArgs): Promise<CodeServerLib.ServerParsedArgs> => {
773-
let workspace = ""
774-
let folder = ""
775-
if (args._.length) {
776-
const lastEntry = path.resolve(args._[args._.length - 1])
777-
const entryIsFile = await isFile(lastEntry)
778-
if (entryIsFile && path.extname(lastEntry) === ".code-workspace") {
779-
workspace = lastEntry
780-
} else if (!entryIsFile) {
781-
folder = lastEntry
782-
}
783-
// Otherwise it is a regular file. Spawning VS Code with a file is not yet
784-
// supported but it can be done separately after code-server spawns.
785-
}
786-
787765
return {
788766
"connection-token": "0000",
789767
...args,
790-
workspace,
791-
folder,
792768
"accept-server-license-terms": true,
793769
/** Type casting. */
794770
help: !!args.help,

src/node/routes/vscode.ts

+34-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { logger } from "@coder/logger"
22
import * as express from "express"
3+
import * as path from "path"
34
import { WebsocketRequest } from "../../../typings/pluginapi"
45
import { logError } from "../../common/util"
56
import { toVsCodeArgs } from "../cli"
67
import { isDevMode } from "../constants"
78
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
89
import { SocketProxyProvider } from "../socket"
9-
import { loadAMDModule } from "../util"
10+
import { isFile, loadAMDModule } from "../util"
1011
import { Router as WsRouter } from "../wsRouter"
1112
import { errorHandler } from "./errors"
1213

@@ -25,6 +26,9 @@ export class CodeServerRouteWrapper {
2526

2627
private $root: express.Handler = async (req, res, next) => {
2728
const isAuthenticated = await authenticated(req)
29+
const NO_FOLDER_OR_WORKSPACE_QUERY = !req.query.folder && !req.query.workspace
30+
// Ew means the workspace was closed so clear the last folder/workspace.
31+
const FOLDER_OR_WORKSPACE_WAS_CLOSED = req.query.ew
2832

2933
if (!isAuthenticated) {
3034
const to = self(req)
@@ -33,25 +37,38 @@ export class CodeServerRouteWrapper {
3337
})
3438
}
3539

36-
const { query } = await req.settings.read()
37-
if (query) {
38-
// Ew means the workspace was closed so clear the last folder/workspace.
39-
if (req.query.ew) {
40-
delete query.folder
41-
delete query.workspace
42-
}
40+
if (NO_FOLDER_OR_WORKSPACE_QUERY && !FOLDER_OR_WORKSPACE_WAS_CLOSED) {
41+
const settings = await req.settings.read()
42+
const lastOpened = settings.query || {}
43+
// This flag disables the last opened behavior
44+
const IGNORE_LAST_OPENED = req.args["ignore-last-opened"]
45+
const HAS_LAST_OPENED_FOLDER_OR_WORKSPACE = lastOpened.folder || lastOpened.workspace
46+
const HAS_FOLDER_OR_WORKSPACE_FROM_CLI = req.args._.length > 0
47+
const to = self(req)
48+
49+
let folder = undefined
50+
let workspace = undefined
4351

4452
// Redirect to the last folder/workspace if nothing else is opened.
45-
if (
46-
!req.query.folder &&
47-
!req.query.workspace &&
48-
(query.folder || query.workspace) &&
49-
!req.args["ignore-last-opened"] // This flag disables this behavior.
50-
) {
51-
const to = self(req)
53+
if (HAS_LAST_OPENED_FOLDER_OR_WORKSPACE && !IGNORE_LAST_OPENED) {
54+
folder = lastOpened.folder
55+
workspace = lastOpened.workspace
56+
} else if (HAS_FOLDER_OR_WORKSPACE_FROM_CLI) {
57+
const lastEntry = path.resolve(req.args._[req.args._.length - 1])
58+
const entryIsFile = await isFile(lastEntry)
59+
const IS_WORKSPACE_FILE = entryIsFile && path.extname(lastEntry) === ".code-workspace"
60+
61+
if (IS_WORKSPACE_FILE) {
62+
workspace = lastEntry
63+
} else if (!entryIsFile) {
64+
folder = lastEntry
65+
}
66+
}
67+
68+
if (folder || workspace) {
5269
return redirect(req, res, to, {
53-
folder: query.folder,
54-
workspace: query.workspace,
70+
folder,
71+
workspace,
5572
})
5673
}
5774
}

test/unit/node/cli.test.ts

-25
Original file line numberDiff line numberDiff line change
@@ -726,29 +726,6 @@ describe("toVsCodeArgs", () => {
726726
it("should convert empty args", async () => {
727727
expect(await toVsCodeArgs(await setDefaults(parse([])))).toStrictEqual({
728728
...vscodeDefaults,
729-
folder: "",
730-
workspace: "",
731-
})
732-
})
733-
734-
it("should convert with workspace", async () => {
735-
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
736-
await fs.writeFile(workspace, "foobar")
737-
expect(await toVsCodeArgs(await setDefaults(parse([workspace])))).toStrictEqual({
738-
...vscodeDefaults,
739-
workspace,
740-
folder: "",
741-
_: [workspace],
742-
})
743-
})
744-
745-
it("should convert with folder", async () => {
746-
const folder = await tmpdir(testName)
747-
expect(await toVsCodeArgs(await setDefaults(parse([folder])))).toStrictEqual({
748-
...vscodeDefaults,
749-
folder,
750-
workspace: "",
751-
_: [folder],
752729
})
753730
})
754731

@@ -757,8 +734,6 @@ describe("toVsCodeArgs", () => {
757734
await fs.writeFile(file, "foobar")
758735
expect(await toVsCodeArgs(await setDefaults(parse([file])))).toStrictEqual({
759736
...vscodeDefaults,
760-
folder: "",
761-
workspace: "",
762737
_: [file],
763738
})
764739
})

test/unit/node/routes/vscode.test.ts

+34-57
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
11
import { promises as fs } from "fs"
2-
import { Response } from "node-fetch"
32
import * as path from "path"
43
import { clean, tmpdir } from "../../../utils/helpers"
54
import * as httpserver from "../../../utils/httpserver"
65
import * as integration from "../../../utils/integration"
76

8-
interface WorkbenchConfig {
9-
folderUri?: {
10-
path: string
11-
}
12-
workspaceUri?: {
13-
path: string
14-
}
15-
}
16-
177
describe("vscode", () => {
188
let codeServer: httpserver.HttpServer | undefined
199

@@ -39,7 +29,7 @@ describe("vscode", () => {
3929
expect(resp.status).toBe(200)
4030
const html = await resp.text()
4131
const url = new URL(resp.url) // Check there were no redirections.
42-
expect(url.pathname + decodeURIComponent(url.search)).toBe(route)
32+
expect(url.pathname + url.search).toBe(route)
4333
switch (route) {
4434
case "/":
4535
case "/vscode/":
@@ -52,59 +42,33 @@ describe("vscode", () => {
5242
}
5343
})
5444

55-
/**
56-
* Get the workbench config from the provided response.
57-
*/
58-
const getConfig = async (resp: Response): Promise<WorkbenchConfig> => {
59-
expect(resp.status).toBe(200)
60-
const html = await resp.text()
61-
const match = html.match(/<meta id="vscode-workbench-web-configuration" data-settings="(.+)">/)
62-
if (!match || !match[1]) {
63-
throw new Error("Unable to find workbench configuration")
64-
}
65-
const config = match[1].replace(/&quot;/g, '"')
66-
try {
67-
return JSON.parse(config)
68-
} catch (error) {
69-
console.error("Failed to parse workbench configuration", config)
70-
throw error
71-
}
72-
}
73-
74-
it("should have no default folder or workspace", async () => {
75-
codeServer = await integration.setup(["--auth=none"], "")
76-
77-
const config = await getConfig(await codeServer.fetch("/"))
78-
expect(config.folderUri).toBeUndefined()
79-
expect(config.workspaceUri).toBeUndefined()
80-
})
81-
82-
it("should have a default folder", async () => {
83-
const defaultDir = await tmpdir(testName)
84-
codeServer = await integration.setup(["--auth=none", defaultDir], "")
45+
it("should redirect to the passed in workspace using human-readable query", async () => {
46+
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
47+
await fs.writeFile(workspace, "")
48+
codeServer = await integration.setup(["--auth=none", workspace], "")
8549

86-
// At first it will load the directory provided on the command line.
87-
const config = await getConfig(await codeServer.fetch("/"))
88-
expect(config.folderUri?.path).toBe(defaultDir)
89-
expect(config.workspaceUri).toBeUndefined()
50+
const resp = await codeServer.fetch("/")
51+
const url = new URL(resp.url)
52+
expect(url.pathname).toBe("/")
53+
expect(url.search).toBe(`?workspace=${workspace}`)
9054
})
9155

92-
it("should have a default workspace", async () => {
93-
const defaultWorkspace = path.join(await tmpdir(testName), "test.code-workspace")
94-
await fs.writeFile(defaultWorkspace, "")
95-
codeServer = await integration.setup(["--auth=none", defaultWorkspace], "")
56+
it("should redirect to the passed in folder using human-readable query", async () => {
57+
const folder = await tmpdir(testName)
58+
codeServer = await integration.setup(["--auth=none", folder], "")
9659

97-
// At first it will load the workspace provided on the command line.
98-
const config = await getConfig(await codeServer.fetch("/"))
99-
expect(config.folderUri).toBeUndefined()
100-
expect(config.workspaceUri?.path).toBe(defaultWorkspace)
60+
const resp = await codeServer.fetch("/")
61+
const url = new URL(resp.url)
62+
expect(url.pathname).toBe("/")
63+
expect(url.search).toBe(`?folder=${folder}`)
10164
})
10265

10366
it("should redirect to last query folder/workspace", async () => {
10467
codeServer = await integration.setup(["--auth=none"], "")
10568

10669
const folder = await tmpdir(testName)
10770
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
71+
await fs.writeFile(workspace, "")
10872
let resp = await codeServer.fetch("/", undefined, {
10973
folder,
11074
workspace,
@@ -118,21 +82,32 @@ describe("vscode", () => {
11882
resp = await codeServer.fetch(route)
11983
const url = new URL(resp.url)
12084
expect(url.pathname).toBe(route)
121-
expect(decodeURIComponent(url.search)).toBe(`?folder=${folder}&workspace=${workspace}`)
85+
expect(url.search).toBe(`?folder=${folder}&workspace=${workspace}`)
12286
await resp.text()
12387
}
12488

12589
// Closing the folder should stop the redirecting.
12690
resp = await codeServer.fetch("/", undefined, { ew: "true" })
12791
let url = new URL(resp.url)
12892
expect(url.pathname).toBe("/")
129-
expect(decodeURIComponent(url.search)).toBe("?ew=true")
93+
expect(url.search).toBe("?ew=true")
13094
await resp.text()
13195

13296
resp = await codeServer.fetch("/")
13397
url = new URL(resp.url)
13498
expect(url.pathname).toBe("/")
135-
expect(decodeURIComponent(url.search)).toBe("")
99+
expect(url.search).toBe("")
100+
await resp.text()
101+
})
102+
103+
it("should do nothing when nothing is passed in", async () => {
104+
codeServer = await integration.setup(["--auth=none"], "")
105+
106+
let resp = await codeServer.fetch("/", undefined)
107+
108+
expect(resp.status).toBe(200)
109+
const url = new URL(resp.url)
110+
expect(url.search).toBe("")
136111
await resp.text()
137112
})
138113

@@ -141,6 +116,8 @@ describe("vscode", () => {
141116

142117
const folder = await tmpdir(testName)
143118
const workspace = path.join(await tmpdir(testName), "test.code-workspace")
119+
await fs.writeFile(workspace, "")
120+
144121
let resp = await codeServer.fetch("/", undefined, {
145122
folder,
146123
workspace,
@@ -152,7 +129,7 @@ describe("vscode", () => {
152129
resp = await codeServer.fetch("/")
153130
const url = new URL(resp.url)
154131
expect(url.pathname).toBe("/")
155-
expect(decodeURIComponent(url.search)).toBe("")
132+
expect(url.search).toBe("")
156133
await resp.text()
157134
})
158135
})

vendor/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
"postinstall": "./postinstall.sh"
88
},
99
"devDependencies": {
10-
"code-oss-dev": "coder/vscode#0fd21e4078ac1dddb26be024f5d4224a4b86da93"
10+
"code-oss-dev": "coder/vscode#bd734e3d9f21b1bce4dabab2514177e90c090ee6"
1111
}
1212
}

vendor/yarn.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ clone-response@^1.0.2:
274274
dependencies:
275275
mimic-response "^1.0.0"
276276

277-
code-oss-dev@coder/vscode#0fd21e4078ac1dddb26be024f5d4224a4b86da93:
277+
code-oss-dev@coder/vscode#bd734e3d9f21b1bce4dabab2514177e90c090ee6:
278278
version "1.63.0"
279-
resolved "https://codeload.github.com/coder/vscode/tar.gz/%3Cspan%20class="x x-first x-last">0fd21e4078ac1dddb26be024f5d4224a4b86da93"
279+
resolved "https://codeload.github.com/coder/vscode/tar.gz/%3Cspan%20class="x x-first x-last">bd734e3d9f21b1bce4dabab2514177e90c090ee6"
280280
dependencies:
281281
"@microsoft/applicationinsights-web" "^2.6.4"
282282
"@parcel/watcher" "2.0.3"

0 commit comments

Comments
 (0)