UNPKG

@goreleaser/example

Version:

Example NPM publish pipeline

175 lines (158 loc) 4.23 kB
const { archives } = require("./package.json"); const fs = require("fs"); const crypto = require("crypto"); const path = require("path"); const JSZip = require("jszip"); const tar = require("tar"); const axios = require("axios"); const { spawnSync } = require("child_process"); const getArchive = () => { let target = `${process.platform}-${process.arch}`; const archive = archives[target]; if (!archive) { throw new Error(`No archive available for ${target}`); } return archive; }; const binDir = path.join(__dirname, "bin"); async function extractTar(tarPath, binaries, dir) { try { await tar.x({ file: tarPath, cwd: dir, filter: (path) => binaries.includes(path), }); console.log(`Successfully extracted binaries to "${dir}"`); } catch (err) { throw new Error(`Extraction failed: ${err.message}`); } } async function extractZip(zipPath, binaries, dir) { try { const zipData = fs.readFileSync(zipPath); const zip = await JSZip.loadAsync(zipData); for (const binary of binaries) { if (!zip.files[binary]) { throw new Error( `Error: ${binary} does not exist in ${zipPath}`, ); } const content = await zip.files[binary].async("nodebuffer"); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } const file = path.join(dir, binary); fs.writeFileSync(file, content); fs.chmodSync(file, "755"); console.log(`Successfully extracted "${binary}" to "${dir}"`); } } catch (err) { throw new Error(`Extraction failed: ${err.message}`); } } const run = async (bin) => { await install(); if (process.platform === "win32") { bin += ".exe"; } const [, , ...args] = process.argv; let result = spawnSync(path.join(binDir, bin), args, { cwd: process.cwd(), stdio: "inherit", }); if (result.error) { console.error(result.error); } return result.status; }; const install = async () => { try { let archive = getArchive(); if (await exists(archive)) { return; } let tmp = fs.mkdtempSync("archive-"); let archivePath = path.join(tmp, archive.name); await download(archive.url, archivePath); verify(archivePath, archive.checksum); if (!fs.existsSync(binDir)) { fs.mkdirSync(binDir); } switch (archive.format) { case "binary": const bin = path.join(binDir, archive.bins[0]); fs.copyFileSync(archivePath, bin); fs.chmodSync(bin, 0o755); return; case "zip": return extractZip(archivePath, archive.bins, binDir); case "tar": case "tar.gz": case "tgz": return extractTar(archivePath, archive.bins, binDir); case "tar.zst": case "tzst": case "tar.xz": case "txz": default: throw new Error(`unsupported format: ${archive.format}`); } } catch (err) { throw new Error(`Installation failed: ${err.message}`); } }; const verify = (filename, checksum) => { if (checksum.algorithm == "" || checksum.digest == "") { console.warn("Warning: No checksum provided for verification"); return; } let digest = crypto .createHash(checksum.algorithm) .update(fs.readFileSync(filename)) .digest("hex"); if (digest != checksum.digest) { throw new Error( `${filename}: ${checksum.algorithm} does not match, expected ${checksum.digest}, got ${digest}`, ); } }; const download = async (url, filename) => { try { console.log(`Downloading ${url} to ${filename}...`); const dir = path.dirname(filename); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } const response = await axios({ method: "GET", url: url, responseType: "stream", timeout: 300000, // 5min }); const writer = fs.createWriteStream(filename); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on("finish", () => { console.log(`Download complete: ${filename}`); resolve(dir); }); writer.on("error", (err) => { console.error(`Error writing file: ${err.message}`); reject(err); }); }); } catch (err) { throw new Error(`Download failed: ${err.message}`); } }; function exists(archive) { if (!fs.existsSync(binDir)) { return false; } return archive.bins.every((bin) => fs.existsSync(path.join(binDir, bin))); } module.exports = { install, run, getArchive, };