refactor: update build environment
refactored to stick to my UNIX principles, in addition to exposing a cleaner GNU Make interface
This commit is contained in:
parent
219f877888
commit
fcec0ee5b1
5 changed files with 1061 additions and 3520 deletions
0
LICENSE
Normal file
0
LICENSE
Normal file
36
Makefile
36
Makefile
|
|
@ -1,28 +1,40 @@
|
|||
NPM=npm
|
||||
|
||||
.PHONY: configure chore build dist test publish doc
|
||||
.PHONY: configure chore package-lock.json publish dist
|
||||
|
||||
all: chore
|
||||
all: dist
|
||||
|
||||
chore: configure
|
||||
tags:
|
||||
ctags -R --exclude=node_modules --exclude=vendor --exclude=docs \
|
||||
--exclude=*.js --exclude=*.htm* --exclude=*.json --exclude=src/style
|
||||
|
||||
chore: configure package-lock.json
|
||||
|
||||
configure:
|
||||
autoconf
|
||||
|
||||
build:
|
||||
$(NPM) run build
|
||||
build/release/: node_modules/ src/ tsconfig.json
|
||||
$(NPM) run build:release
|
||||
|
||||
test:
|
||||
$(NPM) run test
|
||||
build/debug/: node_modules/ src/ tsconfig.debug.json
|
||||
$(NPM) run build:debug
|
||||
|
||||
doc:
|
||||
build/doc/: node_modules/ src/ typedoc.json tsconfig.json
|
||||
$(NPM) run doc
|
||||
|
||||
dist:
|
||||
$(NPM) run dist
|
||||
test-reports/: node_modules/ tests/ src/ jest.config.mjs
|
||||
$(NPM) run test
|
||||
|
||||
publish:
|
||||
$(NPM) run mypublish -- -r '$(NPM_REGISTRY)'
|
||||
dist: build/release/ build/doc/
|
||||
$(NPM) run dist -- build/doc/
|
||||
|
||||
publish: node_modules/ tsconfig.node.json
|
||||
$(NPM) run publish_ -- -r '$(NPM_REGISTRY)'
|
||||
|
||||
# necessary when using a local npm mirror/proxy
|
||||
package-lock.json: package.json
|
||||
rm -rf package-lock.json
|
||||
npm install --registry=https://registry.npmjs.org
|
||||
|
||||
clean:
|
||||
rm -rvf configure~ config.log config.status autom4te.cache build dist
|
||||
|
|
|
|||
4267
package-lock.json
generated
4267
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
"name": "administratrix/esm-logging",
|
||||
"version": "1.0.0",
|
||||
"description": "port of Python standard library logging module",
|
||||
"main": "index.js",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "npm run build:release",
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
"watch:debug": "npm run build:debug -- --watch",
|
||||
"doc": "typedoc --entryPoints src/index.ts --html build/doc",
|
||||
"mypublish": "ts-node -P tsconfig.node.json scripts/publish.ts",
|
||||
"dist": "ts-node -P tsconfig.node.json scripts/pack.ts build/release dist"
|
||||
"dist": "ts-node -P tsconfig.node.json scripts/npm-pack.ts build/release dist"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.3.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typedoc": "^0.27.9",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
|
|
|
|||
273
scripts/npm-pack.ts
Normal file
273
scripts/npm-pack.ts
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
import * as child_process from 'node:child_process';
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import * as util from 'node:util';
|
||||
|
||||
const SCRIPTNAME = path.basename(__filename);
|
||||
|
||||
const DEFAULT_INPUT_DIR: string = path.join('build', 'release');
|
||||
const DEFAULT_OUTPUT_DIR: string = 'dist';
|
||||
const DEFAULT_ASSETS_INDEX_BASENAME: string = 'assets.txt';
|
||||
const DEFAULT_DOCS_DIRNAME: string = 'docs/';
|
||||
const DEFAULT_LIB_DIRNAME: string = 'lib/';
|
||||
|
||||
function usage(exec: string): string {
|
||||
return `
|
||||
Usage: ${exec} [OPTIONS] [INPUT] [OUTPUT] [DOCS]
|
||||
|
||||
Create a tarball from a package
|
||||
|
||||
This script is a wrapper around \`npm pack\`.
|
||||
|
||||
This project uses npm pack to distribute its assets, even though it's not the
|
||||
most ideal as the resulting tarball has a directory structure specific to npm
|
||||
packages. The reason it is still utilized though is because it does not require
|
||||
any additional dependencies outside the Node.js/npm runtime environment.
|
||||
|
||||
It copies the current working directory to a temporary directory, moves the
|
||||
build artifacts to the root of it and then starts \`npm pack\` from within that
|
||||
directory.
|
||||
|
||||
This is necessary, because traditional directory layout of build environments
|
||||
isn't compatible with npm pack routine. With npm packages, usually build
|
||||
artifacts are transpiled into the same directory as their sources and then
|
||||
excluded via e.g. \`.gitignore\`. This is how the \`npm pack\` routine expects
|
||||
it, which gives poor isolation between sources and build artifacts.
|
||||
|
||||
Positional arguments:
|
||||
|
||||
INPUT - directory of build output used as the input for packaging
|
||||
[default:${DEFAULT_INPUT_DIR}]
|
||||
|
||||
OUTPUT - directory to output the package (tarball) into
|
||||
[default:${DEFAULT_OUTPUT_DIR}]
|
||||
|
||||
DOCS - directory containing documentation, which is used as an auxiliary
|
||||
input for packaging alongside INPUT.
|
||||
|
||||
Options:
|
||||
|
||||
-d, --docs-dirname - name of directory to output documentation into
|
||||
(if supplied through DOCS).
|
||||
[default:${DEFAULT_DOCS_DIRNAME}]
|
||||
|
||||
-l, --lib-dirname - name of directory to output transpiled module into
|
||||
[default:${DEFAULT_LIB_DIRNAME}]
|
||||
`;
|
||||
}
|
||||
|
||||
export interface PackageOptions {
|
||||
inputDir: string,
|
||||
outputDir: string,
|
||||
docsInputDir: string | null,
|
||||
docsOutputDirname: string,
|
||||
libOutputDirname: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively traverse a directory and yield all paths relative to the root
|
||||
*
|
||||
* @param root - path where to start traversal from
|
||||
*/
|
||||
export function* listFiles(
|
||||
root: string,
|
||||
trueRoot?: string,
|
||||
): Generator<string, void, unknown> {
|
||||
trueRoot = trueRoot ?? root;
|
||||
if (!fs.existsSync(root)) {
|
||||
throw new Error(`path does not exist: '${root}'`);
|
||||
}
|
||||
|
||||
var files = fs.readdirSync(root);
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
let filePath = path.join(root, files[i]);
|
||||
let stat = fs.lstatSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) { yield* listFiles(filePath, trueRoot) }
|
||||
else { yield path.relative(trueRoot, filePath); }
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: write TSDOC block comment
|
||||
*/
|
||||
function pack(options: PackageOptions): void {
|
||||
var cwd = process.cwd();
|
||||
|
||||
if (path.dirname(options.inputDir) == path.basename(options.inputDir)) {
|
||||
throw new Error('inputDir must have a nesting depth of at least 2')
|
||||
}
|
||||
|
||||
if ([path.sep, '.'].includes(options.inputDir[0])) {
|
||||
throw new Error(`inputDir must be a relative path inside of '${cwd}'`)
|
||||
}
|
||||
|
||||
console.log(`${SCRIPTNAME}: creating temporary directory...`);
|
||||
const tempDir = fs.mkdtempSync(path.join(
|
||||
os.tmpdir(),
|
||||
`${path.basename(cwd)}-`
|
||||
));
|
||||
|
||||
console.log(`${SCRIPTNAME}: copying metadata...`);
|
||||
[
|
||||
'package.json',
|
||||
'LICENSE',
|
||||
'README.md',
|
||||
].forEach((target) => {
|
||||
// TODO: sync file stats
|
||||
fs.cpSync(
|
||||
path.join(cwd, target),
|
||||
path.join(tempDir, target),
|
||||
{
|
||||
filter: (src: string, dest: string) => {
|
||||
console.log(
|
||||
`cp: ${path.relative(cwd, src)} > ${dest}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if (options.docsInputDir) {
|
||||
console.log(`${SCRIPTNAME}: docs supplied, will copy...`);
|
||||
// TODO: sync file stats
|
||||
fs.cpSync(
|
||||
path.join(cwd, options.docsInputDir),
|
||||
path.join(tempDir, options.docsOutputDirname),
|
||||
{
|
||||
recursive: true,
|
||||
filter: (src: string, dest: string) => {
|
||||
console.log(
|
||||
`cp: ${path.relative(cwd, src)} > ${dest}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
else {
|
||||
console.log(`${SCRIPTNAME}: no docs supplied, will not copy...`);
|
||||
}
|
||||
|
||||
console.log(`${SCRIPTNAME}: copying build output...`);
|
||||
fs.cpSync(
|
||||
options.inputDir,
|
||||
path.join(tempDir, options.libOutputDirname),
|
||||
{
|
||||
recursive: true,
|
||||
filter: (src: string, dest: string) => {
|
||||
console.log(
|
||||
`cp: ${path.relative(cwd, src)} > ${dest}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const outputDir = path.resolve(cwd, options.outputDir);
|
||||
console.log(`mkdir: ${outputDir}`);
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
|
||||
console.log(`npm: pack --pack-destination ${outputDir}`);
|
||||
child_process.execSync(
|
||||
`npm pack --pack-destination ${outputDir}`,
|
||||
{
|
||||
cwd: tempDir,
|
||||
stdio: "inherit"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
// minimum number of positional arguments
|
||||
const minPosargs: number = 2;
|
||||
|
||||
// default values of options arguments
|
||||
const defaultOptargs: {[key: string]: any} = {
|
||||
'docs-dirname': DEFAULT_DOCS_DIRNAME,
|
||||
'lib-dirname': DEFAULT_LIB_DIRNAME,
|
||||
};
|
||||
|
||||
// required options arguments
|
||||
const requiredOptargs: string[] = [
|
||||
'docs-dirname',
|
||||
'lib-dirname',
|
||||
];
|
||||
|
||||
// the interface of parseArgs is very simple and Typescript does not play
|
||||
// nicely with it, since it expects any reassignments to be of the same type
|
||||
// as the primitives parseArgs allows. That's why I'm doing a lot of `as
|
||||
// unknown as whatever` kung-fu down below. The node runtime doesn't care
|
||||
// anyway...
|
||||
var {values, positionals} = util.parseArgs({
|
||||
options: {
|
||||
'docs-dirname': {
|
||||
type: 'string',
|
||||
short: 'd'
|
||||
},
|
||||
'lib-dirname': {
|
||||
type: 'string',
|
||||
short: 'd'
|
||||
},
|
||||
'help': {
|
||||
type: 'boolean',
|
||||
short: 'h'
|
||||
}
|
||||
},
|
||||
allowPositionals: true
|
||||
});
|
||||
|
||||
// there's probably a prettier way as to not have to reassign this just to
|
||||
// make tsc happy, but I'm a little exhausted...
|
||||
const args: string[] = positionals;
|
||||
|
||||
if (values.help != undefined) {
|
||||
const exec = [
|
||||
'ts-node',
|
||||
path.join(path.basename(__dirname), path.basename(__filename))
|
||||
].join(' ');
|
||||
console.log(usage(exec));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
values = {...defaultOptargs, ...values};
|
||||
|
||||
var errors: boolean = false;
|
||||
|
||||
for (var requiredOptarg of requiredOptargs) {
|
||||
if (!(requiredOptarg in values)) {
|
||||
console.error(
|
||||
`error: missing options argument: --${requiredOptarg}`
|
||||
);
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (positionals.length < minPosargs) {
|
||||
if (positionals.length == 1) {
|
||||
positionals.push(DEFAULT_OUTPUT_DIR);
|
||||
}
|
||||
|
||||
else if (positionals.length == 0) {
|
||||
positionals.push(DEFAULT_INPUT_DIR);
|
||||
positionals.push(DEFAULT_OUTPUT_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors != false) {
|
||||
console.log(`supply -h/--help, for more information.`)
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
pack({
|
||||
inputDir: positionals[0],
|
||||
outputDir: positionals[1],
|
||||
docsInputDir: positionals[2] ?? null,
|
||||
docsOutputDirname: values['docs-dirname']!,
|
||||
libOutputDirname: values['lib-dirname']!,
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue