build-strap 6.1.0-main.174 → 6.1.0-main.176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -19
- package/package.json +6 -10
- package/src/cert.js +0 -1
- package/src/docker.date.js +12 -2
- package/src/dockerCleanup.js +18 -18
- package/src/fetch.js +3 -7
- package/src/npm.js +0 -1
- package/src/tgz.js +9 -6
- package/src/yarn.js +0 -2
package/README.md
CHANGED
|
@@ -6,51 +6,39 @@ This project builds itself, so take a look in the `targets/` folder for an examp
|
|
|
6
6
|
[](https://github.com/murrayju/build-strap/actions?query=workflow%3A%22CI+Build%22)
|
|
7
7
|
[](https://github.com/murrayju/build-strap/releases/latest)
|
|
8
8
|
[](https://npmjs.org/package/build-strap)
|
|
9
|
-
[](https://david-dm.org/murrayju/build-strap)
|
|
10
|
-
[](https://david-dm.org/murrayju/build-strap?type=dev)
|
|
11
9
|
|
|
12
10
|
## Create a "zero dependency" bootstrapped build
|
|
13
|
-
You can set up your project to build with (practically) no pre-requisite dependencies. [nub-strap](https://github.com/murrayju/nub-strap/) downloads a pinned version of [nub](https://nubjs.com) into the project. Nub then provides the pinned
|
|
11
|
+
You can set up your project to build with (practically) no pre-requisite dependencies. [nub-strap](https://github.com/murrayju/nub-strap/) downloads a pinned version of [nub](https://nubjs.com) into the project. Nub then provides the pinned version of node, and is also the package manager.
|
|
14
12
|
- Copy the `nub` script from nub-strap into the root of your project, and pin the nub version in it.
|
|
15
13
|
|
|
16
14
|
```
|
|
17
15
|
curl -o nub https://raw.githubusercontent.com/murrayju/nub-strap/main/nub && chmod +x nub
|
|
18
16
|
```
|
|
19
17
|
|
|
20
|
-
- Pin the node
|
|
18
|
+
- Pin the node version in your `package.json`, and set nub as the package manager (`./nub pm use nub` does this, and converts an existing lockfile to `nub.lock`).
|
|
21
19
|
|
|
22
20
|
```
|
|
23
21
|
{
|
|
24
22
|
"devEngines": {
|
|
25
|
-
"runtime": { "name": "node", "version": "24.18.0" }
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
"runtime": { "name": "node", "version": "24.18.0" },
|
|
24
|
+
"packageManager": { "name": "nub", "version": "^0.10.0", "onFail": "ignore" }
|
|
25
|
+
}
|
|
28
26
|
}
|
|
29
27
|
```
|
|
30
28
|
|
|
31
|
-
- Add a `yarn` script, which runs the pinned yarn with nub.
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
#!/bin/bash
|
|
35
|
-
set -euo pipefail
|
|
36
|
-
|
|
37
|
-
yarnJs=$(./nub pm which)
|
|
38
|
-
exec ./nub --node "$yarnJs" "$@"
|
|
39
|
-
```
|
|
40
|
-
|
|
41
29
|
- Add a `bs` script, which installs dependencies and runs your build targets.
|
|
42
30
|
|
|
43
31
|
```
|
|
44
32
|
#!/bin/bash
|
|
45
33
|
|
|
46
|
-
./
|
|
34
|
+
./nub install
|
|
47
35
|
exec ./nub ./targets/run.ts "$@"
|
|
48
36
|
```
|
|
49
37
|
|
|
50
38
|
## Add the dependency reference
|
|
51
39
|
Add `build-strap` to your `package.json` (likely in the `devDependencies` section).
|
|
52
40
|
```
|
|
53
|
-
|
|
41
|
+
./nub add -D build-strap
|
|
54
42
|
```
|
|
55
43
|
|
|
56
44
|
## Add meta information to your `package.json`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "build-strap",
|
|
3
|
-
"version": "6.1.0-main.
|
|
3
|
+
"version": "6.1.0-main.176",
|
|
4
4
|
"description": "Node scripts for building things",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Justin Murray <justin@murrayju.com>",
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
"url": "https://github.com/murrayju/build-strap"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
|
-
"main": "./src/index.js",
|
|
13
|
-
"types": "./src/index.d.ts",
|
|
14
12
|
"engines": {
|
|
15
13
|
"node": ">=24"
|
|
16
14
|
},
|
|
15
|
+
"resolutions": {
|
|
16
|
+
"minimatch": "^11.0.5"
|
|
17
|
+
},
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"bytes": "^3.1.1",
|
|
19
20
|
"chokidar": "^6.0.0",
|
|
@@ -23,14 +24,9 @@
|
|
|
23
24
|
"glob": "^14.0.4",
|
|
24
25
|
"is-reachable": "^6.1.0",
|
|
25
26
|
"js-yaml": "^5.5.0",
|
|
26
|
-
"lodash-es": "^4.17.21",
|
|
27
|
-
"moment": "^2.31.0",
|
|
28
|
-
"node-fetch": "^3.3.2",
|
|
29
27
|
"rimraf": "^6.1.4",
|
|
30
|
-
"stream-counter": "1",
|
|
31
28
|
"tar": "^7.1.0"
|
|
32
29
|
},
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
}
|
|
30
|
+
"main": "./src/index.js",
|
|
31
|
+
"types": "./src/index.d.ts"
|
|
36
32
|
}
|
package/src/cert.js
CHANGED
package/src/docker.date.js
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Docker prints dates in the Go format "2006-01-02 15:04:05.999999999 -0700 MST".
|
|
2
|
+
// We ignore the fractional seconds and the zone name.
|
|
3
|
+
const dockerDatePattern = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})(?:\.\d+)? ([+-]\d{2})(\d{2})/;
|
|
4
|
+
// Returns an invalid Date (NaN time) when the text does not match.
|
|
5
|
+
export const parseDockerDate = (date) => {
|
|
6
|
+
const match = dockerDatePattern.exec(date);
|
|
7
|
+
if (!match) {
|
|
8
|
+
return new Date(NaN);
|
|
9
|
+
}
|
|
10
|
+
const [, day, time, offsetHours, offsetMinutes] = match;
|
|
11
|
+
return new Date(`${day}T${time}${offsetHours}:${offsetMinutes}`);
|
|
12
|
+
};
|
package/src/dockerCleanup.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { uniq } from 'lodash-es';
|
|
2
|
-
import moment from 'moment';
|
|
3
1
|
import { dockerContainerLs } from './docker.container.js';
|
|
4
2
|
import { dockerImages, dockerRmi, getDockerRepo, getDockerTags, getUntaggedDockerIds, } from './docker.js';
|
|
5
3
|
import { buildLog } from './run.js';
|
|
@@ -45,22 +43,24 @@ export const dockerImageCleanup = async ({ buildImageIds = [], dryRun = process.
|
|
|
45
43
|
const filterLatest = (m) => purgeAll || !/^latest(-\w+)?$/.exec(m.tag);
|
|
46
44
|
// only match images more than an hour old, AND without a :latest* tag
|
|
47
45
|
const filterOld = (m) => purgeAll ||
|
|
48
|
-
(filterLatest(m) &&
|
|
49
|
-
const uniqueList =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
(filterLatest(m) && m.created.getTime() < Date.now() - 60 * 60 * 1000);
|
|
47
|
+
const uniqueList = [
|
|
48
|
+
...new Set([
|
|
49
|
+
// the things that we know were just built by us
|
|
50
|
+
// remove all tags from the given repos with a matching `buildImageIds`, except for :latest*
|
|
51
|
+
...(await flatten(repos.map((r) => buildImageIds.map(async (b) => getDockerTags(b, r, true, filterLatest))))),
|
|
52
|
+
// unconditionally delete explicitly passed images/ids
|
|
53
|
+
...images,
|
|
54
|
+
// images in the given `repos` without a tag, older than 1hr
|
|
55
|
+
...(await flatten(repos.map(async (r) => getUntaggedDockerIds(r, filterOld)))),
|
|
56
|
+
// images with no repo and no tag
|
|
57
|
+
...(await dockerImages(null, (m) => m.repository === '<none>' && m.tag === '<none>' && filterOld(m))).map((m) => m.id),
|
|
58
|
+
// any leftover tags from prior builds (only if purgeAll or purgeOld)
|
|
59
|
+
...(purgeAll || purgeOld
|
|
60
|
+
? await flatten(repos.map(async (r) => getDockerTags(null, r, true, filterOld)))
|
|
61
|
+
: []),
|
|
62
|
+
]),
|
|
63
|
+
];
|
|
64
64
|
if (dryRun) {
|
|
65
65
|
buildLog(`Images to delete (dry run):\n ${uniqueList.join('\n ')}`);
|
|
66
66
|
}
|
package/src/fetch.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
|
-
import fetch from 'node-fetch';
|
|
3
2
|
import path from 'path';
|
|
3
|
+
import { Readable } from 'stream';
|
|
4
|
+
import { pipeline } from 'stream/promises';
|
|
4
5
|
export const downloadFile = async (url, saveAs, overwrite = true) => {
|
|
5
6
|
const res = await fetch(url);
|
|
6
7
|
const { body, ok } = res;
|
|
@@ -11,10 +12,5 @@ export const downloadFile = async (url, saveAs, overwrite = true) => {
|
|
|
11
12
|
if (overwrite) {
|
|
12
13
|
await fs.remove(saveAs);
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
await new Promise((resolve, reject) => {
|
|
16
|
-
body.pipe(fileStream);
|
|
17
|
-
body.on('error', reject);
|
|
18
|
-
fileStream.on('finish', resolve);
|
|
19
|
-
});
|
|
15
|
+
await pipeline(Readable.fromWeb(body), fs.createWriteStream(saveAs));
|
|
20
16
|
};
|
package/src/npm.js
CHANGED
|
@@ -17,7 +17,6 @@ export async function npm({ args = [], npmPath, spawnOptions, } = {}) {
|
|
|
17
17
|
const localNpm = path.join(path.dirname(process.execPath), platform() === 'win32' ? '' : '../lib', 'node_modules/npm/bin/npm-cli.js');
|
|
18
18
|
const spawnOpts = {
|
|
19
19
|
env: process.env,
|
|
20
|
-
shell: true,
|
|
21
20
|
stdio: 'inherit',
|
|
22
21
|
...spawnOptions,
|
|
23
22
|
};
|
package/src/tgz.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import
|
|
4
|
+
import { Writable } from 'stream';
|
|
5
5
|
import { create } from 'tar';
|
|
6
6
|
import { buildLog } from './run.js';
|
|
7
7
|
const generateHash = async (stream, type) => new Promise((resolve, reject) => {
|
|
@@ -19,14 +19,17 @@ const generateHash = async (stream, type) => new Promise((resolve, reject) => {
|
|
|
19
19
|
});
|
|
20
20
|
export const generateFileHash = async (filePath, type) => generateHash(fs.createReadStream(filePath), type);
|
|
21
21
|
const countBytes = async (stream) => new Promise((resolve, reject) => {
|
|
22
|
-
|
|
22
|
+
let byteCount = 0;
|
|
23
|
+
const counter = new Writable({
|
|
24
|
+
write(chunk, _encoding, callback) {
|
|
25
|
+
byteCount += chunk.length;
|
|
26
|
+
callback();
|
|
27
|
+
},
|
|
28
|
+
});
|
|
23
29
|
stream
|
|
24
30
|
.pipe(counter)
|
|
25
31
|
.on('finish', () => {
|
|
26
|
-
resolve(
|
|
27
|
-
})
|
|
28
|
-
.on('end', () => {
|
|
29
|
-
resolve(counter.bytes);
|
|
32
|
+
resolve(byteCount);
|
|
30
33
|
})
|
|
31
34
|
.on('error', (err) => {
|
|
32
35
|
reject(err);
|
package/src/yarn.js
CHANGED
|
@@ -11,7 +11,6 @@ export async function yarn({ args = [], spawnOptions, } = {}) {
|
|
|
11
11
|
const localYarn = path.join(path.dirname(process.execPath), '/node_modules/yarn/bin/yarn.js');
|
|
12
12
|
const spawnOpts = {
|
|
13
13
|
env: process.env,
|
|
14
|
-
shell: true,
|
|
15
14
|
stdio: 'inherit',
|
|
16
15
|
...spawnOptions,
|
|
17
16
|
};
|
|
@@ -131,7 +130,6 @@ export async function yarnPublish({ npmAuthToken, npmConfig, npmCreds, npmPath,
|
|
|
131
130
|
FORCE_COLOR: 'true',
|
|
132
131
|
NPM_TOKEN: authToken,
|
|
133
132
|
},
|
|
134
|
-
shell: true,
|
|
135
133
|
stdio: 'inherit',
|
|
136
134
|
},
|
|
137
135
|
});
|