Skip to content

Commit

Permalink
refactor: tidy up open, wsl and docker utils
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Aug 30, 2023
1 parent 9e67e2e commit f039645
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 444 deletions.
27 changes: 27 additions & 0 deletions src/lib/docker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { readFileSync, statSync } from "node:fs";

let isDockerCached: boolean;

export function isDocker() {
if (isDockerCached === undefined) {
isDockerCached = _hasDockerEnvironment() || _hasDockerCGroup();
}
return isDockerCached;
}

Check warning on line 10 in src/lib/docker.ts

View check run for this annotation

Codecov / codecov/patch

src/lib/docker.ts#L6-L10

Added lines #L6 - L10 were not covered by tests

function _hasDockerEnvironment() {
try {
statSync("/.dockerenv");
return true;
} catch {
return false;
}
}

Check warning on line 19 in src/lib/docker.ts

View check run for this annotation

Codecov / codecov/patch

src/lib/docker.ts#L12-L19

Added lines #L12 - L19 were not covered by tests

function _hasDockerCGroup() {
try {
return readFileSync("/proc/self/cgroup", "utf8").includes("docker");
} catch {
return false;
}
}

Check warning on line 27 in src/lib/docker.ts

View check run for this annotation

Codecov / codecov/patch

src/lib/docker.ts#L21-L27

Added lines #L21 - L27 were not covered by tests
123 changes: 123 additions & 0 deletions src/lib/open.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
* Check main LICENSE for more information
*/
import childProcess, { SpawnOptions } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import { join } from "node:path";
import { getWslDrivesMountPoint, isWsl } from "./wsl";
import { isDocker } from "./docker";

export type OpenOptions = {
wait?: boolean;
background?: boolean;
newInstance?: boolean;
allowNonzeroExitCode?: boolean;
};

export async function open(target: string, options: OpenOptions = {}) {
let command;
const cliArguments = [];
const childProcessOptions: SpawnOptions = {};

if (process.platform === "darwin") {
// --- MacOS ---
command = "open";

if (options.wait) {
cliArguments.push("--wait-apps");
}

if (options.background) {
cliArguments.push("--background");
}

if (options.newInstance) {
cliArguments.push("--new");
}
} else if (process.platform === "win32" || (isWsl() && !isDocker())) {
// --- Windows or WSL ---
command = isWsl()
? `${getWslDrivesMountPoint()}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`
: `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`;

cliArguments.push(
"-NoProfile",
"-NonInteractive",
"–ExecutionPolicy",
"Bypass",
"-EncodedCommand",
);

if (!isWsl()) {
childProcessOptions.windowsVerbatimArguments = true;
}

const encodedArguments = ["Start"];

if (options.wait) {
encodedArguments.push("-Wait");
}

encodedArguments.push(target);

// Using Base64-encoded command, accepted by PowerShell, to allow special characters.
target = Buffer.from(encodedArguments.join(" "), "utf16le").toString(
"base64",
);
} else {
// --- Linux ---
command = "xdg-open";
const useSystemXdgOpen =
process.versions.electron || process.platform === "android";
if (!useSystemXdgOpen) {
command = join(os.tmpdir(), "xdg-open");
if (!fs.existsSync(command)) {
try {
fs.writeFileSync(
join(os.tmpdir(), "xdg-open"),
await import("./xdg-open").then((r) => r.xdgOpenScript()),
"utf8",
);
fs.chmodSync(command, 0o755 /* rwx r-x r-x */);
} catch {
command = "xdg-open";
}
}
}

if (!options.wait) {
// `xdg-open` will block the process unless stdio is ignored and it's detached from the parent even if it's unref'd.
childProcessOptions.stdio = "ignore";
childProcessOptions.detached = true;
}
}

cliArguments.push(target);

const subprocess = childProcess.spawn(
command,
cliArguments,
childProcessOptions,
);

if (options.wait) {
return new Promise((resolve, reject) => {
subprocess.once("error", reject);

subprocess.once("close", (exitCode) => {
if (options.allowNonzeroExitCode && exitCode! > 0) {
reject(new Error(`Exited with code ${exitCode}`));
return;
}

resolve(subprocess);
});
});
}

subprocess.unref();

return subprocess;
}

Check warning on line 123 in src/lib/open.ts

View check run for this annotation

Codecov / codecov/patch

src/lib/open.ts#L19-L123

Added lines #L19 - L123 were not covered by tests
Loading

0 comments on commit f039645

Please sign in to comment.