Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | 3x 3x 3x 3x 3x 3x 34x 34x 2x 34x 10x 1x 1x 13x 13x 13x 9x 1x 1x 2x 2x 3x 34x 34x 13x 12x 6x 3x 9x 3x 3x 2x 2x 1x 9x 9x 9x 9x 7x 3x 2x 2x 5x 9x 9x 9x 9x 5x 5x 1x 2x 2x 1x 20x 15x 18x 18x 13x 13x 16x 10x 2x 10x | import {
DownloadCanceledError,
assetNameFor,
detectHost,
ensureBinary,
installedBinary,
isDevBuild,
isDownloadCanceled,
latestRelease,
listReleases as listPackageReleases,
type DownloadProgress,
type EnsureResult as LauncherEnsureResult,
type GpuDetection as LauncherDetection,
type Host,
type InstalledBinary,
type LauncherError,
type ResolvedRelease,
} from "lilbee";
import { MESSAGES } from "./locales/en";
import { node } from "./node";
import {
ENSURE_SOURCE,
LAUNCHER_ERROR_CODE,
PLATFORM,
SERVER_VARIANT,
type EnsureRequest,
type GpuDetection,
type MigratedBinary,
type ServerVariant,
} from "./types";
import { formatDiskSize } from "./utils";
export type ReleaseInfo = ResolvedRelease;
export type { DownloadProgress, InstalledBinary };
/** An installed binary and, when this call resolved a release, the probe that chose its build. */
export interface EnsureResult extends InstalledBinary {
source: LauncherEnsureResult["source"];
/** Null on a cache hit: nothing was probed. */
detection: GpuDetection | null;
}
export { DownloadCanceledError, isDevBuild, isDownloadCanceled };
const FLAT_BINARY_NAME = "lilbee";
const WINDOWS_EXE_SUFFIX = ".exe";
const PART_SUFFIX = ".part";
const VERSION_FLAG = "--version";
const LAUNCHER_ERROR_NAME = "LauncherError";
/** The baseline build a ROCm-family variant falls back to. */
const ROCM_BASELINE: Partial<Record<ServerVariant, ServerVariant>> = {
[SERVER_VARIANT.ROCM]: SERVER_VARIANT.DEFAULT,
[SERVER_VARIANT.COMPAT_ROCM]: SERVER_VARIANT.COMPAT,
};
// Unknown gfx targets are not "supports everything": a ROCm build refuses cards it ships no kernels for.
function withKnownGpu(host: Host): Host {
const baseline = ROCM_BASELINE[host.variant];
if (baseline === undefined || host.amdGfxTargets.length > 0) return host;
return { ...host, variant: baseline };
}
async function releaseHost(): Promise<Host> {
return withKnownGpu(await detectHost());
}
/** The plugin's record of a probe: the package's report without its CPU probe. */
function recordedDetection(detection: LauncherDetection | undefined): GpuDetection | null {
if (detection === undefined) return null;
const { nvidia, amd, detectedAt } = detection;
return { nvidia, amd, detectedAt };
}
function asLauncherError(err: unknown): LauncherError | null {
return err instanceof Error && err.name === LAUNCHER_ERROR_NAME ? (err as LauncherError) : null;
}
/** The plugin's wording for a launcher failure; anything else passes through unchanged. */
function pluginError(err: unknown): unknown {
const failure = asLauncherError(err);
if (failure === null) return err;
switch (failure.code) {
case LAUNCHER_ERROR_CODE.NO_SPACE:
return new Error(
MESSAGES.ERROR_DOWNLOAD_NO_SPACE(
formatDiskSize(Number(failure.neededBytes)),
formatDiskSize(Number(failure.freeBytes)),
),
);
case LAUNCHER_ERROR_CODE.STALLED:
return new Error(MESSAGES.ERROR_DOWNLOAD_STALLED);
case LAUNCHER_ERROR_CODE.NO_DIGEST:
case LAUNCHER_ERROR_CODE.DIGEST_MISMATCH:
return new Error(MESSAGES.ERROR_DOWNLOAD_UNVERIFIED);
case LAUNCHER_ERROR_CODE.HTTP:
return new Error(MESSAGES.ERROR_GITHUB_STATUS(Number(failure.status)));
default:
return err;
}
}
async function withPluginWording<T>(work: Promise<T>): Promise<T> {
try {
return await work;
} catch (err) {
throw pluginError(err);
}
}
/** Recent installable releases for the version picker, newest first, dev builds included when asked. */
export async function listReleases(includeDev: boolean): Promise<ReleaseInfo[]> {
return withPluginWording(listPackageReleases({ includeDev, host: await releaseHost() }));
}
/** The newest installable release, honouring the dev-build preference. */
export async function getLatestRelease(includeDev: boolean): Promise<ReleaseInfo> {
return withPluginWording(latestRelease({ includeDev, host: await releaseHost() }));
}
export function checkForUpdate(currentVersion: string, latestTag: string): boolean {
return currentVersion !== latestTag && latestTag !== "";
}
function flatBinaryName(): string {
return process.platform === PLATFORM.WIN32 ? `${FLAT_BINARY_NAME}${WINDOWS_EXE_SUFFIX}` : FLAT_BINARY_NAME;
}
/** The tag a binary reports (`lilbee 0.6.90b432` reads as v0.6.90b432), or null when it cannot say. */
async function probeVersion(path: string): Promise<string | null> {
try {
const { stdout } = await node.execFile(path, [VERSION_FLAG]);
const [, version] = stdout.trim().split(/\s+/);
return version ? `v${version}` : null;
} catch {
return null;
}
}
/**
* Move a flat `<binDir>/lilbee` install into the package's `<binDir>/<release>/<asset>` layout
* and return what it was filed under. An install with no recorded version is asked for its
* version first and deleted only when it cannot answer.
*/
export async function migrateFlatBinary(
binDir: string,
version: string,
variant: ServerVariant | "",
): Promise<MigratedBinary | null> {
const flat = node.join(binDir, flatBinaryName());
const part = `${flat}${PART_SUFFIX}`;
if (node.existsSync(part)) node.unlinkSync(part);
if (!node.existsSync(flat)) return null;
const release = version || (await probeVersion(flat));
if (release === null) {
node.unlinkSync(flat);
return null;
}
const { assetName, variant: filedAs } = hostAssetFor(variant || SERVER_VARIANT.DEFAULT);
const releaseDir = node.join(binDir, release);
node.mkdirSync(releaseDir, { recursive: true });
node.renameSync(flat, node.join(releaseDir, assetName));
return { release, variant: filedAs };
}
/** This host's asset name for a build; a build the host cannot name (a stale record) files as the default build. */
function hostAssetFor(variant: ServerVariant): { assetName: string; variant: ServerVariant } {
try {
return { assetName: assetNameFor(process.platform, process.arch, variant), variant };
} catch {
return {
assetName: assetNameFor(process.platform, process.arch, SERVER_VARIANT.DEFAULT),
variant: SERVER_VARIANT.DEFAULT,
};
}
}
async function clearQuarantine(path: string, onFailed?: () => void): Promise<void> {
try {
await node.execFile("xattr", ["-cr", path]);
} catch {
onFailed?.();
}
}
export class ServerBinary {
constructor(private binDir: string) {}
/** The newest installed binary for this machine, or null when none is installed. */
installed(): InstalledBinary | null {
return installedBinary({ cacheDir: this.binDir });
}
/** Make a binary available, downloading when needed; a fresh macOS download has its quarantine cleared. */
async ensure(request: EnsureRequest): Promise<EnsureResult> {
const { onQuarantineFailed, ...options } = request;
if (!options.release && !options.force) {
const installed = this.installed();
if (installed !== null) return { ...installed, source: ENSURE_SOURCE.CACHE, detection: null };
}
const { detection, ...result } = await withPluginWording(
ensureBinary({ ...options, cacheDir: this.binDir, host: await releaseHost(), requireDigest: true }),
);
if (result.source === ENSURE_SOURCE.DOWNLOAD && process.platform === PLATFORM.DARWIN) {
await clearQuarantine(result.path, onQuarantineFailed);
}
return { ...result, detection: recordedDetection(detection) };
}
}
|