Skip to content

Commit 961023f

Browse files
authored
fix(tester): Zotero run failed due to miss deps on Utuntu 24 (#76)
* fix: install more deps and show more detailed log * style: lint
1 parent d48abc2 commit 961023f

File tree

5 files changed

+69
-39
lines changed

5 files changed

+69
-39
lines changed

src/core/tester.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import type { Context } from "../types/index.js";
22
import http from "node:http";
33
import { join, resolve } from "node:path";
4-
import process, { cwd } from "node:process";
4+
import process from "node:process";
55
import { build } from "esbuild";
66
import { copy, emptyDir, outputFile, outputJSON, pathExists } from "fs-extra/esm";
77
import { isCI } from "std-env";
88
import { glob } from "tinyglobby";
99
import { Xvfb } from "xvfb-ts";
1010
import { saveResource } from "../utils/file.js";
11-
import { installXvfb, installZoteroLinux } from "../utils/headless.js";
11+
import { installDepsForUbuntu24, installXvfb, installZoteroLinux } from "../utils/headless.js";
1212
import { toArray } from "../utils/string.js";
1313
import { ZoteroRunner } from "../utils/zotero-runner.js";
1414
import { findFreeTcpPort } from "../utils/zotero/remote-zotero.js";
@@ -547,13 +547,11 @@ export default class Test extends Base {
547547
async startZoteroHeadless() {
548548
// Ensure xvfb installing
549549
await installXvfb();
550+
await installDepsForUbuntu24();
550551

551552
// Download and Extract Zotero Beta Linux
552553
await installZoteroLinux();
553554

554-
// Set Environment Variable for Zotero Bin Path
555-
process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH = `${cwd()}/Zotero_linux-x86_64/zotero`;
556-
557555
const xvfb = new Xvfb({
558556
timeout: 2000,
559557
});

src/utils/headless.ts

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,71 @@
11
import { execSync } from "node:child_process";
22
import process from "node:process";
3-
import { isLinux } from "std-env";
4-
import { logger } from "./log.js";
3+
import { isDebug, isLinux } from "std-env";
4+
import { LOG_LEVEL, logger } from "./log.js";
55

6-
export async function installXvfb() {
7-
logger.debug("Installing xvfb...");
8-
if (!isLinux) {
9-
logger.error("Unsupported platform. Please install Xvfb manually.");
10-
process.exit(1);
11-
}
6+
function isPackageInstalled(packageName: string): boolean {
127
try {
13-
execSync("which xvfb", { stdio: "ignore" });
8+
execSync(`dpkg-query -W ${packageName}`, { stdio: "ignore" });
9+
return true;
1410
}
1511
catch {
16-
try {
17-
const osId = execSync("cat /etc/os-release | grep '^ID='").toString();
18-
if (osId.includes("ubuntu") || osId.includes("debian")) {
19-
logger.debug("Detected Ubuntu/Debian. Installing Xvfb...");
20-
execSync("sudo apt-get update && sudo apt-get install -y xvfb", { stdio: "pipe" });
21-
}
22-
else if (osId.includes("centos") || osId.includes("rhel")) {
23-
logger.debug("Detected CentOS/RHEL. Installing Xvfb...");
24-
execSync("sudo yum install -y xorg-x11-server-Xvfb", { stdio: "pipe" });
25-
}
26-
else {
27-
throw new Error("Unsupported Linux distribution.");
28-
}
29-
logger.debug("Xvfb installation completed.");
12+
return false;
13+
}
14+
}
15+
16+
function installPackage(packageName: string): void {
17+
const debug = isDebug || logger.level <= LOG_LEVEL.debug;
18+
try {
19+
logger.debug(`Installing ${packageName}...`);
20+
execSync(`sudo apt update && sudo apt install -y ${packageName}`, { stdio: debug ? "inherit" : "pipe" });
21+
logger.debug(`${packageName} installed successfully.`);
22+
}
23+
catch (error) {
24+
logger.fail(`Failed to install ${packageName}.`, error);
25+
throw error;
26+
}
27+
}
28+
29+
function checkAndInstallDependencies(packages: string[]): void {
30+
packages.forEach((pkg) => {
31+
if (isPackageInstalled(pkg)) {
32+
logger.debug(`${pkg} is already installed.`);
3033
}
31-
catch (error) {
32-
logger.error("Failed to install Xvfb:", error);
33-
process.exit(1);
34+
else {
35+
installPackage(pkg);
3436
}
37+
});
38+
}
39+
40+
export async function installXvfb() {
41+
if (!isLinux) {
42+
logger.error("Unsupported platform. Please install Xvfb manually.");
43+
return;
3544
}
45+
46+
const osId = execSync("cat /etc/os-release | grep '^ID='").toString();
47+
if (!(osId.includes("ubuntu") || osId.includes("debian"))) {
48+
logger.error("Unsupported Linux distribution.");
49+
return;
50+
}
51+
52+
checkAndInstallDependencies(["xvfb", "x11-xkb-utils", "xkb-data"]);
53+
}
54+
55+
export async function installDepsForUbuntu24() {
56+
checkAndInstallDependencies(["libasound2t64", "libdbus-glib-1-2"]);
3657
}
3758

3859
export async function installZoteroLinux() {
39-
logger.debug("Installing Zotero...");
40-
try {
41-
execSync("wget -O zotero.tar.bz2 'https://www.zotero.org/download/client/dl?platform=linux-x86_64&channel=beta'", { stdio: "pipe" });
42-
execSync("tar -xvf zotero.tar.bz2", { stdio: "pipe" });
43-
}
44-
catch (e) {
45-
logger.error(e);
46-
throw new Error("Zotero extracted failed");
60+
if (process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH) {
61+
logger.debug("Local Zotero found, skip to download.");
62+
return;
4763
}
64+
65+
logger.debug("Installing Zotero...");
66+
execSync("wget -O zotero.tar.bz2 'https://www.zotero.org/download/client/dl?platform=linux-x86_64&channel=beta'", { stdio: "pipe" });
67+
execSync("tar -xvf zotero.tar.bz2", { stdio: "pipe" });
68+
69+
// Set Environment Variable for Zotero Bin Path
70+
process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH = `${process.cwd()}/Zotero_linux-x86_64/zotero`;
4871
}

src/utils/log.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export class Log {
4545
this.logLevel = LOG_LEVEL[level];
4646
}
4747

48+
get level() {
49+
return this.logLevel;
50+
}
51+
4852
private formatArgs(arg: any): string {
4953
if (typeof arg === "string")
5054
return arg;

src/utils/zotero-runner.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ export class ZoteroRunner {
117117
const remotePort = await findFreeTcpPort();
118118
args.push("-start-debugger-server", String(remotePort));
119119

120+
logger.debug("Zotero start args: ", args);
121+
120122
const env = {
121123
...process.env,
122124
XPCOM_DEBUG_BREAK: "stack",
@@ -126,10 +128,12 @@ export class ZoteroRunner {
126128
// Using `spawn` so we can stream logging as they come in, rather than
127129
// buffer them up until the end, which can easily hit the max buffer size.
128130
this.zotero = spawn(this.options.binaryPath, args, { env });
131+
logger.debug("Zotero started, pid:", this.zotero.pid);
129132

130133
// Handle Zotero log, necessary on macOS
131134
this.zotero.stdout?.on("data", (_data) => {});
132135

136+
logger.debug("Connecting to the remote Firefox debugger...");
133137
await this.remoteFirefox.connect(remotePort);
134138
logger.debug(`Connected to the remote Firefox debugger on port: ${remotePort}`);
135139
}

src/utils/zotero/remote-zotero.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export class RemoteFirefox {
8484
return this.client;
8585
}
8686
catch (error: any) {
87+
logger.fail("Failed to connecte to RDP client, retry...");
8788
if (isErrorWithCode("ECONNREFUSED", error)) {
8889
await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL));
8990
lastError = error;

0 commit comments

Comments
 (0)