UNPKG

hugo-extended

Version:

✏️ Plug-and-play binary wrapper for Hugo Extended, the awesomest static-site generator.

191 lines (189 loc) 7.48 kB
import { getEnvConfig } from "./env.mjs"; import { execFileSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; //#region src/lib/utils.ts const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** * The first Hugo version that uses .pkg installers for macOS. * Versions before this use .tar.gz archives. * * @see https://github.com/gohugoio/hugo/issues/14135 */ const MACOS_PKG_MIN_VERSION = "0.153.0"; /** * Compares two semver version strings. * * @param a - First version string (e.g., "0.153.0") * @param b - Second version string (e.g., "0.152.1") * @returns -1 if a < b, 0 if a === b, 1 if a > b */ function compareVersions(a, b) { const partsA = a.split(".").map((n) => Number.parseInt(n, 10)); const partsB = b.split(".").map((n) => Number.parseInt(n, 10)); const maxLen = Math.max(partsA.length, partsB.length); for (let i = 0; i < maxLen; i++) { const numA = partsA[i] ?? 0; const numB = partsB[i] ?? 0; if (numA < numB) return -1; if (numA > numB) return 1; } return 0; } /** * Checks if a version uses .pkg installers for macOS. * Hugo v0.153.0+ uses .pkg, earlier versions use .tar.gz. * * @param version - The Hugo version to check * @returns true if the version uses .pkg installers on macOS */ function usesMacOSPkg(version) { return compareVersions(version, MACOS_PKG_MIN_VERSION) >= 0; } /** * Gets the Hugo version to install. * * Resolution order: * 1. HUGO_OVERRIDE_VERSION environment variable (if set) * 2. `hugoVersion` field in package.json (for emergency overrides) * 3. `version` field in package.json (should match Hugo release) * * @throws {Error} If package.json cannot be found and no override is set * @returns The version string (e.g., "0.88.1") */ function getPkgVersion() { const envConfig = getEnvConfig(); if (envConfig.overrideVersion) return envConfig.overrideVersion; const packageJsonPath = path.join(__dirname, "..", "..", "package.json"); try { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); return packageJson.hugoVersion || packageJson.version; } catch { throw new Error(`Could not find or read package.json at ${packageJsonPath}`); } } /** * Generates the full URL to a Hugo release file. * * By default, downloads from GitHub releases. Can be overridden with * HUGO_MIRROR_BASE_URL for mirrors or air-gapped environments. * * @param version - The Hugo version number (e.g., "0.88.1") * @param filename - The release filename (e.g., "hugo_extended_0.88.1_darwin-universal.pkg") * @returns The complete download URL for the release file */ function getReleaseUrl(version, filename) { const envConfig = getEnvConfig(); if (envConfig.downloadBaseUrl) return `${envConfig.downloadBaseUrl.replace(/\/$/, "")}/${filename}`; return `https://github.com/gohugoio/hugo/releases/download/v${version}/${filename}`; } /** * Gets the Hugo binary filename for the current platform. * * @returns "hugo.exe" on Windows, "hugo" on all other platforms */ function getBinFilename() { return process.platform === "win32" ? "hugo.exe" : "hugo"; } /** * Gets the absolute path to the Hugo binary. * * Resolution order: * 1. HUGO_BIN_PATH environment variable (if set) * 2. Local bin directory (./bin/hugo or ./bin/hugo.exe) * * @returns The absolute path to hugo binary */ function getBinPath() { const envConfig = getEnvConfig(); if (envConfig.binPath) return envConfig.binPath; return path.join(__dirname, "..", "..", "bin", getBinFilename()); } /** * Executes the Hugo binary and returns its version string. * * @param bin - The absolute path to the Hugo binary * @returns The version output string (e.g., "hugo v0.88.1-5BC54738+extended darwin/arm64 BuildDate=...") * @throws {Error} If the binary cannot be executed */ function getBinVersion(bin) { return execFileSync(bin, ["version"]).toString().trim(); } /** * Checks if the Hugo binary exists at the specified path. * * @param bin - The absolute path to check for the Hugo binary * @returns `true` if the file exists, `false` if it doesn't * @throws {Error} If an unexpected error occurs (other than ENOENT) */ function doesBinExist(bin) { try { if (fs.existsSync(bin)) return true; } catch (error) { if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") throw error; return false; } return false; } /** * Determines the correct Hugo release filename for the current platform and architecture. * * Hugo Extended is available for: * - macOS: x64 and ARM64 (universal binaries as of v0.102.0) * - Linux: x64 and ARM64 * - Windows: x64 only * * Other platform/architecture combinations fall back to vanilla Hugo where available. * Set HUGO_NO_EXTENDED=1 to force vanilla Hugo even on platforms that support Extended. * * Note: macOS uses .pkg installers starting from v0.153.0. Earlier versions use .tar.gz. * * @param version - The Hugo version number (e.g., "0.88.1") * @returns The release filename if supported (e.g., "hugo_extended_0.88.1_darwin-universal.pkg"), * or `null` if the platform/architecture combination is not supported */ function getReleaseFilename(version) { const { platform, arch } = process; const forceStandard = getEnvConfig().forceStandard; const edition = (extended, standard) => forceStandard ? standard : extended; if (platform === "darwin" && (arch === "x64" || arch === "arm64")) { if (usesMacOSPkg(version)) return edition(`hugo_extended_${version}_darwin-universal.pkg`, `hugo_${version}_darwin-universal.pkg`); return edition(`hugo_extended_${version}_darwin-universal.tar.gz`, `hugo_${version}_darwin-universal.tar.gz`); } return platform === "win32" && arch === "x64" ? edition(`hugo_extended_${version}_windows-amd64.zip`, `hugo_${version}_windows-amd64.zip`) : platform === "win32" && arch === "arm64" ? `hugo_${version}_windows-arm64.zip` : platform === "linux" && arch === "x64" ? edition(`hugo_extended_${version}_linux-amd64.tar.gz`, `hugo_${version}_linux-amd64.tar.gz`) : platform === "linux" && arch === "arm64" ? edition(`hugo_extended_${version}_linux-arm64.tar.gz`, `hugo_${version}_linux-arm64.tar.gz`) : platform === "freebsd" && arch === "x64" ? `hugo_${version}_freebsd-amd64.tar.gz` : platform === "openbsd" && arch === "x64" ? `hugo_${version}_openbsd-amd64.tar.gz` : null; } /** * Generates the checksums filename for a given Hugo version. * * @param version - The Hugo version number (e.g., "0.88.1") * @returns The checksums filename (e.g., "hugo_0.88.1_checksums.txt") */ function getChecksumFilename(version) { return `hugo_${version}_checksums.txt`; } /** * Determines if a release filename corresponds to Hugo Extended or vanilla Hugo. * * @param releaseFile - The release filename to check (e.g., "hugo_extended_0.88.1_darwin-universal.pkg") * @returns `true` if the release is Hugo Extended, `false` if it's vanilla Hugo */ function isExtended(releaseFile) { return releaseFile.startsWith("hugo_extended_"); } /** * Logger utility that respects the HUGO_QUIET setting. */ const logger = { info: (message) => { if (!getEnvConfig().quiet) console.info(message); }, warn: (message) => { if (!getEnvConfig().quiet) console.warn(`⚠ ${message}`); }, error: (message) => { console.error(`✖ ${message}`); } }; //#endregion export { compareVersions, doesBinExist, getBinFilename, getBinPath, getBinVersion, getChecksumFilename, getPkgVersion, getReleaseFilename, getReleaseUrl, isExtended, logger, usesMacOSPkg };