Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(tester): Zotero run failed due to miss deps on Utuntu 24 #76

Merged
merged 6 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/core/tester.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { Context } from "../types/index.js";
import http from "node:http";
import { join, resolve } from "node:path";
import process, { cwd } from "node:process";
import process from "node:process";
import { build } from "esbuild";
import { copy, emptyDir, outputFile, outputJSON, pathExists } from "fs-extra/esm";
import { isCI } from "std-env";
import { glob } from "tinyglobby";
import { Xvfb } from "xvfb-ts";
import { saveResource } from "../utils/file.js";
import { installXvfb, installZoteroLinux } from "../utils/headless.js";
import { installDepsForUbuntu24, installXvfb, installZoteroLinux } from "../utils/headless.js";
import { toArray } from "../utils/string.js";
import { ZoteroRunner } from "../utils/zotero-runner.js";
import { findFreeTcpPort } from "../utils/zotero/remote-zotero.js";
Expand Down Expand Up @@ -547,13 +547,11 @@ export default class Test extends Base {
async startZoteroHeadless() {
// Ensure xvfb installing
await installXvfb();
await installDepsForUbuntu24();

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

// Set Environment Variable for Zotero Bin Path
process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH = `${cwd()}/Zotero_linux-x86_64/zotero`;

const xvfb = new Xvfb({
timeout: 2000,
});
Expand Down
91 changes: 57 additions & 34 deletions src/utils/headless.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,71 @@
import { execSync } from "node:child_process";
import process from "node:process";
import { isLinux } from "std-env";
import { logger } from "./log.js";
import { isDebug, isLinux } from "std-env";
import { LOG_LEVEL, logger } from "./log.js";

export async function installXvfb() {
logger.debug("Installing xvfb...");
if (!isLinux) {
logger.error("Unsupported platform. Please install Xvfb manually.");
process.exit(1);
}
function isPackageInstalled(packageName: string): boolean {
try {
execSync("which xvfb", { stdio: "ignore" });
execSync(`dpkg-query -W ${packageName}`, { stdio: "ignore" });
return true;
}
catch {
try {
const osId = execSync("cat /etc/os-release | grep '^ID='").toString();
if (osId.includes("ubuntu") || osId.includes("debian")) {
logger.debug("Detected Ubuntu/Debian. Installing Xvfb...");
execSync("sudo apt-get update && sudo apt-get install -y xvfb", { stdio: "pipe" });
}
else if (osId.includes("centos") || osId.includes("rhel")) {
logger.debug("Detected CentOS/RHEL. Installing Xvfb...");
execSync("sudo yum install -y xorg-x11-server-Xvfb", { stdio: "pipe" });
}
else {
throw new Error("Unsupported Linux distribution.");
}
logger.debug("Xvfb installation completed.");
return false;
}
}

function installPackage(packageName: string): void {
const debug = isDebug || logger.level <= LOG_LEVEL.debug;
try {
logger.debug(`Installing ${packageName}...`);
execSync(`sudo apt update && sudo apt install -y ${packageName}`, { stdio: debug ? "inherit" : "pipe" });
logger.debug(`${packageName} installed successfully.`);
}
catch (error) {
logger.fail(`Failed to install ${packageName}.`, error);
throw error;
}
}

function checkAndInstallDependencies(packages: string[]): void {
packages.forEach((pkg) => {
if (isPackageInstalled(pkg)) {
logger.debug(`${pkg} is already installed.`);
}
catch (error) {
logger.error("Failed to install Xvfb:", error);
process.exit(1);
else {
installPackage(pkg);
}
});
}

export async function installXvfb() {
if (!isLinux) {
logger.error("Unsupported platform. Please install Xvfb manually.");
return;
}

const osId = execSync("cat /etc/os-release | grep '^ID='").toString();
if (!(osId.includes("ubuntu") || osId.includes("debian"))) {
logger.error("Unsupported Linux distribution.");
return;
}

checkAndInstallDependencies(["xvfb", "x11-xkb-utils", "xkb-data"]);
}

export async function installDepsForUbuntu24() {
checkAndInstallDependencies(["libasound2t64", "libdbus-glib-1-2"]);
}

export async function installZoteroLinux() {
logger.debug("Installing Zotero...");
try {
execSync("wget -O zotero.tar.bz2 'https://www.zotero.org/download/client/dl?platform=linux-x86_64&channel=beta'", { stdio: "pipe" });
execSync("tar -xvf zotero.tar.bz2", { stdio: "pipe" });
}
catch (e) {
logger.error(e);
throw new Error("Zotero extracted failed");
if (process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH) {
logger.debug("Local Zotero found, skip to download.");
return;
}

logger.debug("Installing Zotero...");
execSync("wget -O zotero.tar.bz2 'https://www.zotero.org/download/client/dl?platform=linux-x86_64&channel=beta'", { stdio: "pipe" });
execSync("tar -xvf zotero.tar.bz2", { stdio: "pipe" });

// Set Environment Variable for Zotero Bin Path
process.env.ZOTERO_PLUGIN_ZOTERO_BIN_PATH = `${process.cwd()}/Zotero_linux-x86_64/zotero`;
}
4 changes: 4 additions & 0 deletions src/utils/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export class Log {
this.logLevel = LOG_LEVEL[level];
}

get level() {
return this.logLevel;
}

private formatArgs(arg: any): string {
if (typeof arg === "string")
return arg;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/zotero-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export class ZoteroRunner {
const remotePort = await findFreeTcpPort();
args.push("-start-debugger-server", String(remotePort));

logger.debug("Zotero start args: ", args);

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

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

logger.debug("Connecting to the remote Firefox debugger...");
await this.remoteFirefox.connect(remotePort);
logger.debug(`Connected to the remote Firefox debugger on port: ${remotePort}`);
}
Expand Down
1 change: 1 addition & 0 deletions src/utils/zotero/remote-zotero.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export class RemoteFirefox {
return this.client;
}
catch (error: any) {
logger.fail("Failed to connecte to RDP client, retry...");
if (isErrorWithCode("ECONNREFUSED", error)) {
await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL));
lastError = error;
Expand Down
Loading