npm-pkgbuild
Version:
create ArchLinux, RPM and Debian packages from npm packages
195 lines (173 loc) • 5.98 kB
JavaScript
import { program, Option } from "commander";
import { execa } from "execa";
import { createExpressionTransformer } from "content-entry-transform";
import { UTIController } from "uti";
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 => {
program.option(`--${o.name}`, o.description);
program.option(`--no-${o.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("-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,
context
} 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, base] = source.split(/:/);
if (!base) {
destination = "/";
base = source;
}
return new FileContentProvider(
{
base
},
{ destination }
);
})
);
const o = new outputFactory(context.expand(properties));
const transformer = [
{ name: "skip-bare-modules",
match: entry => entry.isBlob && uc.fileNameConformsTo(entry.name, "public.bare-dynamic-link-library"),
async transform(entry) {}
},
{
name: "skip-architecutes",
match: (entry) => entry.name.endsWith(".node") && entry.filename,
async transform(entry) {
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, "com.netscape.javascript-source"),
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,
context.expand
);
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")
: "";
}