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
|
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:
|
configure:
|
||||||
autoconf
|
autoconf
|
||||||
|
|
||||||
build:
|
build/release/: node_modules/ src/ tsconfig.json
|
||||||
$(NPM) run build
|
$(NPM) run build:release
|
||||||
|
|
||||||
test:
|
build/debug/: node_modules/ src/ tsconfig.debug.json
|
||||||
$(NPM) run test
|
$(NPM) run build:debug
|
||||||
|
|
||||||
doc:
|
build/doc/: node_modules/ src/ typedoc.json tsconfig.json
|
||||||
$(NPM) run doc
|
$(NPM) run doc
|
||||||
|
|
||||||
dist:
|
test-reports/: node_modules/ tests/ src/ jest.config.mjs
|
||||||
$(NPM) run dist
|
$(NPM) run test
|
||||||
|
|
||||||
publish:
|
dist: build/release/ build/doc/
|
||||||
$(NPM) run mypublish -- -r '$(NPM_REGISTRY)'
|
$(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:
|
clean:
|
||||||
rm -rvf configure~ config.log config.status autom4te.cache build dist
|
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",
|
"name": "administratrix/esm-logging",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "port of Python standard library logging module",
|
"description": "port of Python standard library logging module",
|
||||||
"main": "index.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"build": "npm run build:release",
|
"build": "npm run build:release",
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"watch:debug": "npm run build:debug -- --watch",
|
"watch:debug": "npm run build:debug -- --watch",
|
||||||
"doc": "typedoc --entryPoints src/index.ts --html build/doc",
|
"doc": "typedoc --entryPoints src/index.ts --html build/doc",
|
||||||
"mypublish": "ts-node -P tsconfig.node.json scripts/publish.ts",
|
"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": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"ts-jest": "^29.3.2",
|
"ts-jest": "^29.3.2",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
"typedoc": "^0.27.9",
|
"typedoc": "^0.27.9",
|
||||||
"typescript": "^5.8.3"
|
"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