diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index ee5819a5..cc6d2aa5 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -2,7 +2,7 @@ Please link to the issue this PR solves. If there is no existing issue, please first create one unless the fix is minor. -Please make sure the base of your PR is the master branch! +Please make sure the base of your PR is the default branch! --> ## Checklist diff --git a/CHANGELOG.md b/CHANGELOG.md index f723fc7b..12e3d507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ VS Code v1.56 ### Development - chore: ignore updates to microsoft/playwright-github-action +- fix(socket): use xdgBasedir.runtime instead of tmp #3304 @jsjoeio ## 3.10.0 diff --git a/src/node/socket.ts b/src/node/socket.ts index 9c937bbb..1651046d 100644 --- a/src/node/socket.ts +++ b/src/node/socket.ts @@ -4,8 +4,7 @@ import * as path from "path" import * as tls from "tls" import { Emitter } from "../common/emitter" import { generateUuid } from "../common/util" -import { tmpdir } from "./constants" -import { canConnect } from "./util" +import { canConnect, paths } from "./util" /** * Provides a way to proxy a TLS socket. Can be used when you need to pass a @@ -13,7 +12,7 @@ import { canConnect } from "./util" */ export class SocketProxyProvider { private readonly onProxyConnect = new Emitter() - private proxyPipe = path.join(tmpdir, "tls-proxy") + private proxyPipe = path.join(paths.runtime, "tls-proxy") private _proxyServer?: Promise private readonly proxyTimeout = 5000 @@ -76,7 +75,10 @@ export class SocketProxyProvider { this._proxyServer = this.findFreeSocketPath(this.proxyPipe) .then((pipe) => { this.proxyPipe = pipe - return Promise.all([fs.mkdir(tmpdir, { recursive: true }), fs.rmdir(this.proxyPipe, { recursive: true })]) + return Promise.all([ + fs.mkdir(path.dirname(this.proxyPipe), { recursive: true }), + fs.rmdir(this.proxyPipe, { recursive: true }), + ]) }) .then(() => { return new Promise((resolve) => { diff --git a/src/node/util.ts b/src/node/util.ts index 380e32b9..f1882471 100644 --- a/src/node/util.ts +++ b/src/node/util.ts @@ -8,9 +8,10 @@ import * as path from "path" import * as util from "util" import xdgBasedir from "xdg-basedir" -interface Paths { +export interface Paths { data: string config: string + runtime: string } export const paths = getEnvPaths() @@ -20,23 +21,34 @@ export const paths = getEnvPaths() * On MacOS this function gets the standard XDG directories instead of using the native macOS * ones. Most CLIs do this as in practice only GUI apps use the standard macOS directories. */ -function getEnvPaths(): Paths { - let paths: Paths - if (process.platform === "win32") { - paths = envPaths("code-server", { - suffix: "", - }) - } else { - if (xdgBasedir.data === undefined || xdgBasedir.config === undefined) { - throw new Error("No home folder?") - } - paths = { - data: path.join(xdgBasedir.data, "code-server"), - config: path.join(xdgBasedir.config, "code-server"), - } +export function getEnvPaths(): Paths { + const paths = envPaths("code-server", { suffix: "" }) + const append = (p: string): string => path.join(p, "code-server") + switch (process.platform) { + case "darwin": + return { + // envPaths uses native directories so force Darwin to use the XDG spec + // to align with other CLI tools. + data: xdgBasedir.data ? append(xdgBasedir.data) : paths.data, + config: xdgBasedir.config ? append(xdgBasedir.config) : paths.config, + // Fall back to temp if there is no runtime dir. + runtime: xdgBasedir.runtime ? append(xdgBasedir.runtime) : paths.temp, + } + case "win32": + return { + data: paths.data, + config: paths.config, + // Windows doesn't have a runtime dir. + runtime: paths.temp, + } + default: + return { + data: paths.data, + config: paths.config, + // Fall back to temp if there is no runtime dir. + runtime: xdgBasedir.runtime ? append(xdgBasedir.runtime) : paths.temp, + } } - - return paths } /** diff --git a/test/unit/node/util.test.ts b/test/unit/node/util.test.ts new file mode 100644 index 00000000..bb1884b9 --- /dev/null +++ b/test/unit/node/util.test.ts @@ -0,0 +1,147 @@ +describe("getEnvPaths", () => { + describe("on darwin", () => { + let ORIGINAL_PLATFORM = "" + + beforeAll(() => { + ORIGINAL_PLATFORM = process.platform + + Object.defineProperty(process, "platform", { + value: "darwin", + }) + }) + + beforeEach(() => { + jest.resetModules() + jest.mock("env-paths", () => { + return () => ({ + data: "/home/envPath/.local/share", + config: "/home/envPath/.config", + temp: "/tmp/envPath/runtime", + }) + }) + }) + + afterAll(() => { + // Restore old platform + + Object.defineProperty(process, "platform", { + value: ORIGINAL_PLATFORM, + }) + }) + + it("should return the env paths using xdgBasedir", () => { + jest.mock("xdg-basedir", () => ({ + data: "/home/usr/.local/share", + config: "/home/usr/.config", + runtime: "/tmp/runtime", + })) + const getEnvPaths = require("../../../src/node/util").getEnvPaths + const envPaths = getEnvPaths() + + expect(envPaths.data).toEqual("/home/usr/.local/share/code-server") + expect(envPaths.config).toEqual("/home/usr/.config/code-server") + expect(envPaths.runtime).toEqual("/tmp/runtime/code-server") + }) + + it("should return the env paths using envPaths when xdgBasedir is undefined", () => { + jest.mock("xdg-basedir", () => ({})) + const getEnvPaths = require("../../../src/node/util").getEnvPaths + const envPaths = getEnvPaths() + + expect(envPaths.data).toEqual("/home/envPath/.local/share") + expect(envPaths.config).toEqual("/home/envPath/.config") + expect(envPaths.runtime).toEqual("/tmp/envPath/runtime") + }) + }) + describe("on win32", () => { + let ORIGINAL_PLATFORM = "" + + beforeAll(() => { + ORIGINAL_PLATFORM = process.platform + + Object.defineProperty(process, "platform", { + value: "win32", + }) + }) + + beforeEach(() => { + jest.resetModules() + jest.mock("env-paths", () => { + return () => ({ + data: "/windows/envPath/.local/share", + config: "/windows/envPath/.config", + temp: "/tmp/envPath/runtime", + }) + }) + }) + + afterAll(() => { + // Restore old platform + + Object.defineProperty(process, "platform", { + value: ORIGINAL_PLATFORM, + }) + }) + + it("should return the env paths using envPaths", () => { + const getEnvPaths = require("../../../src/node/util").getEnvPaths + const envPaths = getEnvPaths() + + expect(envPaths.data).toEqual("/windows/envPath/.local/share") + expect(envPaths.config).toEqual("/windows/envPath/.config") + expect(envPaths.runtime).toEqual("/tmp/envPath/runtime") + }) + }) + describe("on other platforms", () => { + let ORIGINAL_PLATFORM = "" + + beforeAll(() => { + ORIGINAL_PLATFORM = process.platform + + Object.defineProperty(process, "platform", { + value: "linux", + }) + }) + + beforeEach(() => { + jest.resetModules() + jest.mock("env-paths", () => { + return () => ({ + data: "/linux/envPath/.local/share", + config: "/linux/envPath/.config", + temp: "/tmp/envPath/runtime", + }) + }) + }) + + afterAll(() => { + // Restore old platform + + Object.defineProperty(process, "platform", { + value: ORIGINAL_PLATFORM, + }) + }) + + it("should return the runtime using xdgBasedir if it exists", () => { + jest.mock("xdg-basedir", () => ({ + runtime: "/tmp/runtime", + })) + const getEnvPaths = require("../../../src/node/util").getEnvPaths + const envPaths = getEnvPaths() + + expect(envPaths.data).toEqual("/linux/envPath/.local/share") + expect(envPaths.config).toEqual("/linux/envPath/.config") + expect(envPaths.runtime).toEqual("/tmp/runtime/code-server") + }) + + it("should return the env paths using envPaths when xdgBasedir is undefined", () => { + jest.mock("xdg-basedir", () => ({})) + const getEnvPaths = require("../../../src/node/util").getEnvPaths + const envPaths = getEnvPaths() + + expect(envPaths.data).toEqual("/linux/envPath/.local/share") + expect(envPaths.config).toEqual("/linux/envPath/.config") + expect(envPaths.runtime).toEqual("/tmp/envPath/runtime") + }) + }) +})