UNPKG

npm-pkgbuild

Version:

create ArchLinux, RPM and Debian packages from npm packages

220 lines (197 loc) 6.62 kB
#!/usr/bin/env -S node --no-warnings --title npm-pkgbuild import { program, Option } from "commander"; import { execa } from "execa"; import { createExpressionTransformer } from "content-entry-transform"; import { UTIController } from "uti"; import { expand } from "pacc"; import additionalUTIs from "./utis.mjs"; import { FileContentProvider, allInputs, allOutputs, extractFromPackage, createPublishingDetails } from "npm-pkgbuild"; import pkg from "../package.json" with { type: "json" }; program.description(pkg.description).version(pkg.version); allOutputs.forEach(o => { for (const name of [o.name, o.alias]) { if (name) { program.option(`--${name}`, o.description); program.option(`--no-${name}`, `do not ${o.description} output`); } } }); allInputs.forEach(i => { program.option(`--${i.name}`, i.description); }); program .option("--verbose", "be more verbose", false) .option("--dry", "do not execute, only print definitions", false) .option("--staging <dir>", "directory where to start packaging process") .option("-D --define <a=b>", "define property", (str, former = {}) => Object.assign(former, Object.fromEntries([str.split(/=/)])) ) .option("-p --dir <dir>", "which package to use", process.cwd()) .option("--continue", "continue on error") .option( "-c --content <dir>", "content directory", (c, a) => a.concat([c]), [] ) .option("-m --meta <dir>", "meta directory", (c, a) => a.concat([c]), []) .addOption( new Option( "--publish <url...>", "publishing urls (or directories) of the package" ) ) .action(async options => { try { const uc = new UTIController(); uc.register(additionalUTIs); for await (const { properties, sources, output, variant } of extractFromPackage(options, process.env)) { for (const inputFactory of allInputs.filter( inputFactory => options[inputFactory.name] === true )) { sources.push(new inputFactory()); } for (const outputFactory of allOutputs.filter( o => (options[o.name] === true || output[o.name] !== undefined) && options[o.name] !== false )) { if (!(await outputFactory.prepare(options, variant))) { console.warn(`output format ${outputFactory.name} not avaliable`); continue; } try { Object.assign( properties, { "user-agent": `npm-pkgbuild-${pkg.version}` }, options.define ); sources.push( ...[...options.content, ...options.meta] .filter(x => x) .map(source => { let [destination, dir] = source.split(/:/); if (!dir) { destination = "/"; dir = source; } return new FileContentProvider( { dir }, { destination } ); }) ); const context = { root: properties }; const o = new outputFactory(expand(properties, context)); const transformer = [ { name: "skip-bare-modules", match: entry => entry.isBlob && uc.fileNameConformsTo( entry.name, "public.bare-dynamic-link-library" ), async transform(entry) {} }, { name: "skip-architectures", match: entry => entry.name.endsWith(".node") && entry.filename, async transform(entry) { if (properties.arch) { const proc = await execa("file", ["-b", entry.filename], { cwd: options.dir }); const parts = proc.stdout.split(/\s*,\s*/); if ( parts.length < 4 || (parts.length > 4 && !parts[4].match(/Android/i)) ) { let arch = parts[1]; const archs = { "ARM aarch64": "aarch64" }; arch = archs[arch] || arch; if (properties.arch.indexOf(arch) >= 0) { return entry; } } } //console.log("skip", entry.filename); } }, createExpressionTransformer( entry => entry.isBlob && uc.fileNameConformsTo(entry.name, "public.text") && (!uc.fileNameConformsTo(entry.name, "public.source-code") || uc.fileNameConformsTo(entry.name, "public.configuration")), properties ) ]; const publishingDetails = createPublishingDetails(options.publish, { ...properties, ...process.env }); if (options.verbose) { console.log("variant:"); console.log(kv(variant, " ")); console.log("sources:"); console.log(" " + sources.join("\n ")); console.log("dependencies:"); console.log(kv(properties.dependencies, " ")); console.log( "publish:", publishingDetails.map(pd => pd.url) ); } const artifact = await o.create( sources.map(c => c[Symbol.asyncIterator]()), transformer, publishingDetails, options, object => expand(object, context) ); if (!options.dry) { await Promise.all( publishingDetails.map(publishDetail => o.publish(artifact, publishDetail) ) ); } } catch (e) { handleError(e, options); } } } } catch (e) { handleError(e, options); } }) .parse(process.argv); function handleError(e, options) { console.error(e); if (!options.continue) { process.exit(-1); } } function kv(object, prefix = "") { return object ? Object.entries(object) .map(([k, v]) => `${prefix}${k}: ${v}`) .join("\n") : ""; }