@finbheara/archive-client 0.22.0 → 0.24.0
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 +24 -0
- package/dist/chunks/{index-zwecpq08.js → index-vsk6837c.js} +183 -6
- package/dist/cli.js +432 -143
- package/dist/index.js +19 -1
- package/dist/types/cli-spec.d.ts +15 -0
- package/dist/types/cli.d.ts +7 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/local.d.ts +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ else `archive-client` in your home cache directory.
|
|
|
121
121
|
<root>/<tag>/index/<name>.sqlite the per-tag indexes
|
|
122
122
|
<root>/PINNED.json the user-local pin
|
|
123
123
|
<root>/config.json the user-local config
|
|
124
|
+
<root>/local/<tag>/ a local build a default query answered from (below)
|
|
124
125
|
|
|
125
126
|
A file already in place with no receipt (laid out by hand) is adopted where the manifest's hash
|
|
126
127
|
vouches for it, and fetched again where it does not. A published release never changes, so a
|
|
@@ -780,6 +781,29 @@ tag, a cut, `latest`) is never warned about: it was asked for. `main(argv, { fre
|
|
|
780
781
|
`false` to turn the check off, or a `floor` (a cut the caller requires, and why: where only the
|
|
781
782
|
floor is newer, the line says the cut is required, with the why, and to run `idq use <cut>`), the `command` the warning names and the clock.
|
|
782
783
|
|
|
784
|
+
A LOCAL BUILD ANSWERS THE DEFAULT SPEC. A project that builds releases can offer the client the
|
|
785
|
+
directories its unpublished builds sit in, `main(argv, { local: { builds } })`, where `builds()`
|
|
786
|
+
answers `{ dir, label, fraction? }[]`: a directory holding a build's `MANIFEST.json` and files as
|
|
787
|
+
its emitter wrote them, what to call it, and the fraction of its cut it builds. A query with no
|
|
788
|
+
`--release` then answers from the NEWEST COMPLETE build strictly newer than the pinned release
|
|
789
|
+
(the cut its manifest's input release names, then the fraction; with no pin, the newest cached
|
|
790
|
+
release; with neither, any complete build), and prints one line on stderr:
|
|
791
|
+
|
|
792
|
+
answered from <label> (unpublished, <dir>). Pass --release <tag> for a published one, or --live for the pin.
|
|
793
|
+
|
|
794
|
+
The answer's format and the exit code are otherwise the call's own. `--release <spec>` names a
|
|
795
|
+
release as ever, and `--live` forces the pinned one; neither reads a build. A build is COMPLETE
|
|
796
|
+
where its manifest parses, names an input release with a cut, and states a `results` database
|
|
797
|
+
that is on disk, each stated database at its stated bytes (`incomplete(dir)` says why not). The
|
|
798
|
+
caller leaves out a build it knows is still being written. A build is never read in place: its
|
|
799
|
+
files are added (hard-linked where the filesystem allows, every database checked against the
|
|
800
|
+
manifest's hash) to `<root>/local/<tag>` and indexed there on first use, the add made in a private
|
|
801
|
+
directory and renamed into place whole. `<root>/local` is no release tag, so `list`, `prune` and
|
|
802
|
+
`use` never see a build, the pin never moves to one, and it never counts among the releases a
|
|
803
|
+
prune keeps. The builds' cache keeps the one build it last answered from, and a build whose
|
|
804
|
+
manifest changed is added again. A verb whose index reads a file the build lacks (a table written
|
|
805
|
+
only when the release is published: `teams`, `events`) answers from the pinned release, saying so.
|
|
806
|
+
|
|
783
807
|
`resolve` speaks JSON lines: one answer per line out, and with no positional question the
|
|
784
808
|
questions are JSON lines on stdin, one per line (`{feis, code, year?, title?}`,
|
|
785
809
|
`{name, school?, age?, population?, oireachtas?}`,
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
} from "./index-hne1wadw.js";
|
|
10
10
|
import {
|
|
11
11
|
parseArchiveTag2,
|
|
12
|
+
renderArchiveTag2,
|
|
13
|
+
cutOf2,
|
|
12
14
|
compareTagsNewestFirst2,
|
|
13
15
|
parseReleaseSpec2,
|
|
14
16
|
pickTag2
|
|
@@ -2804,6 +2806,20 @@ function listIndexes2(rel) {
|
|
|
2804
2806
|
});
|
|
2805
2807
|
}
|
|
2806
2808
|
|
|
2809
|
+
import { createHash as createHash3 } from "crypto";
|
|
2810
|
+
import {
|
|
2811
|
+
copyFileSync as copyFileSync2,
|
|
2812
|
+
existsSync as existsSync6,
|
|
2813
|
+
linkSync as linkSync2,
|
|
2814
|
+
mkdirSync as mkdirSync5,
|
|
2815
|
+
readFileSync as readFileSync5,
|
|
2816
|
+
readdirSync as readdirSync4,
|
|
2817
|
+
renameSync as renameSync3,
|
|
2818
|
+
rmSync as rmSync5,
|
|
2819
|
+
statSync as statSync4
|
|
2820
|
+
} from "fs";
|
|
2821
|
+
import { join as join5 } from "path";
|
|
2822
|
+
|
|
2807
2823
|
import {
|
|
2808
2824
|
copyFileSync,
|
|
2809
2825
|
existsSync as existsSync5,
|
|
@@ -3966,17 +3982,178 @@ function releases2(opts = {}) {
|
|
|
3966
3982
|
return new ReleaseManager2(opts);
|
|
3967
3983
|
}
|
|
3968
3984
|
|
|
3969
|
-
|
|
3970
|
-
|
|
3985
|
+
var LOCAL_DIR2 = "local";
|
|
3986
|
+
var localRoot2 = (root) => join5(root, LOCAL_DIR2);
|
|
3987
|
+
var newerThan2 = (a, b) => a.cut > b.cut || a.cut === b.cut && a.fraction > b.fraction;
|
|
3988
|
+
function readManifest(dir) {
|
|
3989
|
+
const p = join5(dir, "MANIFEST.json");
|
|
3990
|
+
if (!existsSync6(p))
|
|
3991
|
+
return null;
|
|
3992
|
+
try {
|
|
3993
|
+
const v = JSON.parse(readFileSync5(p, "utf8"));
|
|
3994
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
3995
|
+
} catch {
|
|
3996
|
+
return null;
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
function incomplete2(dir) {
|
|
4000
|
+
const m = readManifest(dir);
|
|
4001
|
+
if (m === null)
|
|
4002
|
+
return "no MANIFEST.json that parses";
|
|
4003
|
+
if (cutOf2(typeof m.corpusRelease === "string" ? m.corpusRelease : undefined) === undefined)
|
|
4004
|
+
return "its manifest names no input release with a cut";
|
|
4005
|
+
const dbs = m.databases ?? {};
|
|
4006
|
+
if (dbs.results === undefined)
|
|
4007
|
+
return "its manifest states no results database";
|
|
4008
|
+
for (const name of DATABASES2) {
|
|
4009
|
+
const d = dbs[name];
|
|
4010
|
+
if (d === undefined)
|
|
4011
|
+
continue;
|
|
4012
|
+
const p = join5(dir, d.file ?? `${name}.sqlite`);
|
|
4013
|
+
if (!existsSync6(p))
|
|
4014
|
+
return `no ${d.file ?? `${name}.sqlite`}`;
|
|
4015
|
+
if (d.bytes !== undefined && statSync4(p).size !== d.bytes)
|
|
4016
|
+
return `${d.file ?? `${name}.sqlite`} is ${statSync4(p).size} bytes, the manifest says ${d.bytes}`;
|
|
4017
|
+
}
|
|
4018
|
+
return null;
|
|
4019
|
+
}
|
|
4020
|
+
function releaseVersion2(rel) {
|
|
4021
|
+
const t = parseArchiveTag2(rel.tag);
|
|
4022
|
+
const cut = cutOf2(typeof rel.manifest.corpusRelease === "string" ? rel.manifest.corpusRelease : undefined) ?? t?.cut;
|
|
4023
|
+
if (cut === undefined)
|
|
4024
|
+
return null;
|
|
4025
|
+
const f = rel.manifest.archiveFraction;
|
|
4026
|
+
return { cut, fraction: typeof f === "number" ? f : t?.fraction ?? 0 };
|
|
4027
|
+
}
|
|
4028
|
+
function pickBuild2(builds, base) {
|
|
4029
|
+
let best = null;
|
|
4030
|
+
for (const b of builds) {
|
|
4031
|
+
if (incomplete2(b.dir) !== null)
|
|
4032
|
+
continue;
|
|
4033
|
+
const manifest = readManifest(b.dir);
|
|
4034
|
+
const version = {
|
|
4035
|
+
cut: cutOf2(manifest.corpusRelease),
|
|
4036
|
+
fraction: b.fraction ?? 0
|
|
4037
|
+
};
|
|
4038
|
+
if (base !== null && !newerThan2(version, base))
|
|
4039
|
+
continue;
|
|
4040
|
+
if (best === null || newerThan2(version, best.version))
|
|
4041
|
+
best = { build: b, version, manifest };
|
|
4042
|
+
}
|
|
4043
|
+
return best;
|
|
4044
|
+
}
|
|
4045
|
+
function buildTag2(p) {
|
|
4046
|
+
const at = typeof p.manifest.emittedAt === "string" && !Number.isNaN(Date.parse(p.manifest.emittedAt)) ? new Date(p.manifest.emittedAt) : statSync4(join5(p.build.dir, "MANIFEST.json")).mtime;
|
|
4047
|
+
const date = at.toISOString().slice(0, 10).replaceAll("-", ".");
|
|
4048
|
+
return renderArchiveTag2({ date, cut: p.version.cut, fraction: p.version.fraction });
|
|
4049
|
+
}
|
|
4050
|
+
function buildFiles(dir) {
|
|
4051
|
+
return readdirSync4(dir).filter((n) => statSync4(join5(dir, n)).isFile()).filter((n) => {
|
|
4052
|
+
const m = /^(.*)\.sqlite(\.zst)?$/.exec(n);
|
|
4053
|
+
return m === null || isDatabase(m[1]);
|
|
4054
|
+
}).sort();
|
|
4055
|
+
}
|
|
4056
|
+
function lacks(b, manifest, inputs) {
|
|
4057
|
+
return inputs.filter((a) => !planAsset2(a, manifest).published.some((n) => existsSync6(join5(b.dir, n))));
|
|
4058
|
+
}
|
|
4059
|
+
function buildRemote(label) {
|
|
4060
|
+
const refuse = async () => {
|
|
4061
|
+
throw new Error(`archive-client: ${label} is a local build: it carries only its own files`);
|
|
4062
|
+
};
|
|
4063
|
+
return { name: "local-build", tags: refuse, assets: refuse, download: refuse };
|
|
4064
|
+
}
|
|
4065
|
+
var sha256Of = (path) => createHash3("sha256").update(readFileSync5(path)).digest("hex");
|
|
4066
|
+
var scratchName = (kind) => `.${kind}-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
|
|
4067
|
+
function buildOptions(root, label, opts) {
|
|
4068
|
+
return { ...opts, cache: localRoot2(root), remote: buildRemote(label), assets: [] };
|
|
4069
|
+
}
|
|
4070
|
+
async function openBuild2(root, p, opts) {
|
|
4071
|
+
const o = buildOptions(root, p.build.label, opts);
|
|
4072
|
+
const local = localRoot2(root);
|
|
4073
|
+
const tag = buildTag2(p);
|
|
4074
|
+
const want = sha256Of(join5(p.build.dir, "MANIFEST.json"));
|
|
4075
|
+
const current = () => {
|
|
4076
|
+
const rel = openCached2(tag, o);
|
|
4077
|
+
return rel !== null && rel.receipt().files["MANIFEST.json"]?.sha256 === want ? rel : null;
|
|
4078
|
+
};
|
|
4079
|
+
const have = current();
|
|
4080
|
+
if (have !== null)
|
|
4081
|
+
return have;
|
|
4082
|
+
mkdirSync5(local, { recursive: true });
|
|
4083
|
+
const work = join5(local, scratchName("add"));
|
|
4084
|
+
try {
|
|
4085
|
+
const stage = join5(work, "stage");
|
|
4086
|
+
mkdirSync5(stage, { recursive: true });
|
|
4087
|
+
for (const f of buildFiles(p.build.dir)) {
|
|
4088
|
+
try {
|
|
4089
|
+
linkSync2(join5(p.build.dir, f), join5(stage, f));
|
|
4090
|
+
} catch {
|
|
4091
|
+
copyFileSync2(join5(p.build.dir, f), join5(stage, f));
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
const added = await new ReleaseManager2({ ...o, cache: join5(work, "cache") }).add(stage, tag);
|
|
4095
|
+
const receipt = added.receipt();
|
|
4096
|
+
receipt.source = `local:${p.build.dir}`;
|
|
4097
|
+
writeJsonAtomic2(receiptPath(added.dir), receipt);
|
|
4098
|
+
added.close();
|
|
4099
|
+
const dest = join5(local, tag);
|
|
4100
|
+
if (existsSync6(dest) && current() === null) {
|
|
4101
|
+
try {
|
|
4102
|
+
renameSync3(dest, join5(local, scratchName("old")));
|
|
4103
|
+
} catch {}
|
|
4104
|
+
}
|
|
4105
|
+
try {
|
|
4106
|
+
renameSync3(added.dir, dest);
|
|
4107
|
+
} catch {}
|
|
4108
|
+
} finally {
|
|
4109
|
+
rmSync5(work, { recursive: true, force: true });
|
|
4110
|
+
}
|
|
4111
|
+
const rel = current();
|
|
4112
|
+
if (rel === null)
|
|
4113
|
+
throw new Error(`archive-client: ${p.build.label} did not land in ${local}`);
|
|
4114
|
+
return rel;
|
|
4115
|
+
}
|
|
4116
|
+
function alive(pid) {
|
|
4117
|
+
try {
|
|
4118
|
+
process.kill(pid, 0);
|
|
4119
|
+
return true;
|
|
4120
|
+
} catch (e) {
|
|
4121
|
+
return e.code === "EPERM";
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
function sweepBuilds2(root, keep) {
|
|
4125
|
+
const local = localRoot2(root);
|
|
4126
|
+
if (!existsSync6(local))
|
|
4127
|
+
return [];
|
|
4128
|
+
const gone = [];
|
|
4129
|
+
for (const name of readdirSync4(local).sort()) {
|
|
4130
|
+
if (name === keep)
|
|
4131
|
+
continue;
|
|
4132
|
+
const m = /^\.(add|old)-(\d+)-/.exec(name);
|
|
4133
|
+
if (m !== null && m[1] === "add" && alive(Number(m[2])))
|
|
4134
|
+
continue;
|
|
4135
|
+
if (m === null && parseArchiveTag2(name) === null)
|
|
4136
|
+
continue;
|
|
4137
|
+
const path = join5(local, name);
|
|
4138
|
+
try {
|
|
4139
|
+
rmSync5(path, { recursive: true, force: true });
|
|
4140
|
+
gone.push(path);
|
|
4141
|
+
} catch {}
|
|
4142
|
+
}
|
|
4143
|
+
return gone;
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
4147
|
+
import { join as join6 } from "path";
|
|
3971
4148
|
var LATEST_CHECK_MS2 = 60 * 60 * 1000;
|
|
3972
4149
|
var LATEST_CHECK_BUDGET_MS2 = 1500;
|
|
3973
|
-
var latestCheckPath2 = (root) =>
|
|
4150
|
+
var latestCheckPath2 = (root) => join6(root, "LATEST.json");
|
|
3974
4151
|
function readLatestCheck2(root) {
|
|
3975
4152
|
const p = latestCheckPath2(root);
|
|
3976
|
-
if (!
|
|
4153
|
+
if (!existsSync7(p))
|
|
3977
4154
|
return null;
|
|
3978
4155
|
try {
|
|
3979
|
-
const v = JSON.parse(
|
|
4156
|
+
const v = JSON.parse(readFileSync6(p, "utf8"));
|
|
3980
4157
|
if (typeof v.repo !== "string" || typeof v.checkedAt !== "string")
|
|
3981
4158
|
return null;
|
|
3982
4159
|
return {
|
|
@@ -4055,4 +4232,4 @@ function staleWarning2(answered, latest, floor, tags = [], command = "idq") {
|
|
|
4055
4232
|
return `answered from ${answered}. ${floorTag ?? `cut ${floor.cut}`} is required${why}: run \`${command} use ${floor.cut}\` to get it`;
|
|
4056
4233
|
}
|
|
4057
4234
|
|
|
4058
|
-
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|
|
4235
|
+
export { DATABASES2, planAsset2, sha256File2, unzstdTo2, NAME_LEVELS2, nameLevel2, NO_CALENDAR2, FeisFinder2, ADVANCEMENT_DANCES2, entryRank2, FEIS_LOCAL_ID_FLOOR2, ResultFinder2, MajorsFinder2, LINEAGE_FILE2, linksOfLineage2, releaseSchoolGraph2, readsSpanishNames2, SchoolResolver2, initialsOnly2, nameOrderOf, DancerResolver2, readPopulation2, syllabusSourceOf2, canonicalOf2, CompResolver2, StaffFinder2, TeamFinder2, EventFinder2, defaultBuilders2, indexPath2, indexKey2, isCurrent2, buildIndex2, ensureIndex2, listIndexes2, readPin2, youngest2, dancerResolverOf2, RegistrationResolver2, ghRemote2, httpsRemote2, fallbackRemote2, setRemote2, defaultRemote, columnsOf2, FEATURES2, capabilityOf2, needsRelease2, resolveTag2, Release2, openRelease2, openCached2, DEFAULT_KEEP2, ReleaseManager2, releases2, LOCAL_DIR2, localRoot2, newerThan2, incomplete2, releaseVersion2, pickBuild2, buildTag2, lacks, openBuild2, sweepBuilds2, LATEST_CHECK_MS2, LATEST_CHECK_BUDGET_MS2, latestCheckPath2, readLatestCheck2, latestCheck2, within, staleWarning2 };
|
package/dist/cli.js
CHANGED
|
@@ -6,155 +6,397 @@ import {
|
|
|
6
6
|
} from "./chunks/index-hne1wadw.js";
|
|
7
7
|
import {
|
|
8
8
|
nameOrderOf,
|
|
9
|
+
defaultBuilders2,
|
|
10
|
+
readPin2,
|
|
9
11
|
defaultRemote,
|
|
10
12
|
openRelease2,
|
|
13
|
+
openCached2,
|
|
11
14
|
releases2,
|
|
15
|
+
releaseVersion2,
|
|
16
|
+
pickBuild2,
|
|
17
|
+
lacks,
|
|
18
|
+
openBuild2,
|
|
19
|
+
sweepBuilds2,
|
|
12
20
|
LATEST_CHECK_BUDGET_MS2,
|
|
13
21
|
latestCheck2,
|
|
14
22
|
within,
|
|
15
23
|
staleWarning2
|
|
16
|
-
} from "./chunks/index-
|
|
24
|
+
} from "./chunks/index-vsk6837c.js";
|
|
17
25
|
import"./chunks/index-hghdy980.js";
|
|
18
26
|
|
|
19
|
-
var
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
the
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
27
|
+
var USAGE_HEADER = "usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json] [--live]";
|
|
28
|
+
var GLOBAL_FLAGS = {
|
|
29
|
+
value: ["--cache", "--repo"],
|
|
30
|
+
bool: ["--json", "--live"]
|
|
31
|
+
};
|
|
32
|
+
var VERBS = [
|
|
33
|
+
{
|
|
34
|
+
verb: "config",
|
|
35
|
+
value: [],
|
|
36
|
+
bool: [],
|
|
37
|
+
usage: [
|
|
38
|
+
" config repo <owner/name> set the user-local repository the releases come from",
|
|
39
|
+
" config keep <N> how many of the newest releases a prune keeps (default 2)"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
verb: "list",
|
|
44
|
+
value: [],
|
|
45
|
+
bool: ["--remote"],
|
|
46
|
+
usage: [
|
|
47
|
+
" list [--remote] the cached releases (size, files, indexes, the pin), and",
|
|
48
|
+
" with --remote the published tags"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
verb: "fetch",
|
|
53
|
+
value: ["--release", "--assets"],
|
|
54
|
+
bool: [],
|
|
55
|
+
usage: [
|
|
56
|
+
" fetch [--release <spec>] [--assets results,majors,<file>...]",
|
|
57
|
+
" download, verify and cache a release (default: results)"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
verb: "update",
|
|
62
|
+
value: ["--assets", "--keep"],
|
|
63
|
+
bool: ["--no-prune"],
|
|
64
|
+
usage: [
|
|
65
|
+
" update [--assets ...] [--keep N] [--no-prune]",
|
|
66
|
+
" move to the newest published release: fetch it (verified),",
|
|
67
|
+
" build its indexes, pin it, then prune the cache to the N",
|
|
68
|
+
" newest releases (default: config keep, else 2), keeping the",
|
|
69
|
+
" new pin and the one before it"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
verb: "use",
|
|
74
|
+
value: ["--assets", "--keep"],
|
|
75
|
+
bool: ["--no-prune"],
|
|
76
|
+
usage: [
|
|
77
|
+
" use <spec> [--assets ...] [--keep N] [--no-prune]",
|
|
78
|
+
" the same for the release a spec names"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
verb: "pin",
|
|
83
|
+
value: [],
|
|
84
|
+
bool: [],
|
|
85
|
+
usage: [
|
|
86
|
+
' pin <spec> the user-local pin: what a bare open (spec "pinned") opens'
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
verb: "unpin",
|
|
91
|
+
value: [],
|
|
92
|
+
bool: [],
|
|
93
|
+
usage: [' unpin remove the pin (a bare open is then "latest")']
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
verb: "current",
|
|
97
|
+
value: [],
|
|
98
|
+
bool: [],
|
|
99
|
+
usage: [" current the pin, and whether it is cached"]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
verb: "add",
|
|
103
|
+
value: ["--tag"],
|
|
104
|
+
bool: [],
|
|
105
|
+
usage: [
|
|
106
|
+
" add <dir> --tag <tag> add a release built locally (its MANIFEST.json and files)",
|
|
107
|
+
" to the cache under its tag"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
verb: "index",
|
|
112
|
+
value: ["--release"],
|
|
113
|
+
bool: ["--force"],
|
|
114
|
+
usage: [
|
|
115
|
+
" index [--release <spec>] [<name>...] [--force]",
|
|
116
|
+
" build the per-tag indexes (default: every one)"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
verb: "verify",
|
|
121
|
+
value: ["--release"],
|
|
122
|
+
bool: [],
|
|
123
|
+
usage: [" verify [--release <spec>] re-hash every cached file against its receipt"]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
verb: "capabilities",
|
|
127
|
+
value: ["--release"],
|
|
128
|
+
bool: [],
|
|
129
|
+
usage: [
|
|
130
|
+
" capabilities [--release <spec>] what the release carries of what the client reads, from",
|
|
131
|
+
" its own schema: each feature full or missing (its calls",
|
|
132
|
+
" refuse, naming the first cut that publishes it)"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
verb: "prune",
|
|
137
|
+
value: ["--keep"],
|
|
138
|
+
bool: ["--dry-run"],
|
|
139
|
+
usage: [
|
|
140
|
+
" prune [--keep N] [--dry-run] remove all but the N newest cached releases (default:",
|
|
141
|
+
" config keep, else 2) and the pinned one"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
verb: "rm",
|
|
146
|
+
value: [],
|
|
147
|
+
bool: ["--dry-run"],
|
|
148
|
+
usage: [" rm <tag> [--dry-run] remove one cached release (not the pinned one)"]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
verb: "drop-indexes",
|
|
152
|
+
value: [],
|
|
153
|
+
bool: ["--dry-run"],
|
|
154
|
+
usage: [
|
|
155
|
+
" drop-indexes [<tag>] [--dry-run] remove the index files (of one release, or of every one)"
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
verb: "feis",
|
|
160
|
+
value: ["--release", "--platform", "--code", "--id", "--name", "--year"],
|
|
161
|
+
bool: [],
|
|
162
|
+
usage: [
|
|
163
|
+
" feis [--release <spec>] [--platform <p>] [--code <c>] [--id <id>] [--name <glob>] [--year <y>]",
|
|
164
|
+
" the feises a query names"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
verb: "series",
|
|
169
|
+
value: ["--release"],
|
|
170
|
+
bool: [],
|
|
171
|
+
usage: [
|
|
172
|
+
" series [--release <spec>] <name|host code|feis id>",
|
|
173
|
+
" the series a name, a host code (fweb:ABC) or any feis id",
|
|
174
|
+
" names: its years, hosts, codes and next instance"
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
verb: "school",
|
|
179
|
+
value: ["--release", "--region"],
|
|
180
|
+
bool: [],
|
|
181
|
+
usage: [
|
|
182
|
+
" school [--release <spec>] <print|school_id> [--region <code>]",
|
|
183
|
+
" a school print or id to the published schools"
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
verb: "dancer",
|
|
188
|
+
value: [
|
|
189
|
+
"--release",
|
|
190
|
+
"--surname",
|
|
191
|
+
"--like",
|
|
192
|
+
"--id",
|
|
193
|
+
"--order",
|
|
194
|
+
"--school",
|
|
195
|
+
"--yob",
|
|
196
|
+
"--band",
|
|
197
|
+
"--year",
|
|
198
|
+
"--comp",
|
|
199
|
+
"--as-of",
|
|
200
|
+
"--population",
|
|
201
|
+
"--oireachtas"
|
|
202
|
+
],
|
|
203
|
+
bool: ["--rows"],
|
|
204
|
+
usage: [
|
|
205
|
+
" dancer [--release <spec>] <name> | --surname <s> | --like <glob> | --id <dancer_id>",
|
|
206
|
+
" [--order surname-first|given-first] [--school <print|id>]",
|
|
207
|
+
" [--yob <y> | --band <U10> [--year <y>] | --comp <competition>] [--as-of <date>]",
|
|
208
|
+
" [--population girls|boys] [--oireachtas <region>[:<year>]] [--rows]",
|
|
209
|
+
" the dancers a name reaches, each with its evidence",
|
|
210
|
+
" (name level, age, school, population, region) and the arm;",
|
|
211
|
+
" --oireachtas is the regional the roster is for, its region in",
|
|
212
|
+
" the release's spelling (SRO, MAO), its year the --as-of year",
|
|
213
|
+
" where none is given; the results of",
|
|
214
|
+
" the one dancer where one answers (or --rows for each)"
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
verb: "results",
|
|
219
|
+
value: ["--release", "--dancer", "--feis", "--comp", "--school", "--year", "--limit"],
|
|
220
|
+
bool: [],
|
|
221
|
+
usage: [
|
|
222
|
+
" results [--release <spec>] [--dancer <id>] [--feis <id>] [--comp <competition>]",
|
|
223
|
+
" [--school <print|id>] [--year <y>] [--limit <n>]",
|
|
224
|
+
" the published result rows, prints and ids"
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
verb: "majors",
|
|
229
|
+
value: ["--release", "--event", "--year", "--comp", "--dancer"],
|
|
230
|
+
bool: [],
|
|
231
|
+
usage: [
|
|
232
|
+
" majors [--release <spec>] [--event <e>] [--year <y>] [--comp <competition>] [--dancer <id>]",
|
|
233
|
+
" the majors: every event and its years; an event's",
|
|
234
|
+
" competitions; a competition's, an event's or a dancer's rows"
|
|
235
|
+
]
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
verb: "stream",
|
|
239
|
+
value: [
|
|
240
|
+
"--release",
|
|
241
|
+
"--scope",
|
|
242
|
+
"--event",
|
|
243
|
+
"--year",
|
|
244
|
+
"--tier",
|
|
245
|
+
"--category",
|
|
246
|
+
"--level",
|
|
247
|
+
"--dancer",
|
|
248
|
+
"--school"
|
|
249
|
+
],
|
|
250
|
+
bool: ["--entries", "--primary"],
|
|
251
|
+
usage: [
|
|
252
|
+
" stream [--release <spec>] --scope majors|transcribed|platform|all [--entries] [--event <e,...>]",
|
|
253
|
+
" [--year <y> | --year <from>..<to>] [--tier <t,...>] [--category <c,...>]",
|
|
254
|
+
" [--level <feis_level,...>] [--dancer <id,...>] [--school <school_id>] [--primary]",
|
|
255
|
+
" every row a scope holds, one JSON line each, never the",
|
|
256
|
+
" whole table in memory; --entries one per address (the row",
|
|
257
|
+
" it stands for, with its recall order)"
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
verb: "records",
|
|
262
|
+
value: ["--release", "--dancer", "--year"],
|
|
263
|
+
bool: ["--years"],
|
|
264
|
+
usage: [
|
|
265
|
+
" records [--release <spec>] [--dancer <id,...>]",
|
|
266
|
+
" every dancer's record: display, appearances, birth window,",
|
|
267
|
+
" populations",
|
|
268
|
+
" records --years [--release <spec>] [--dancer <id,...>] [--year <y>]",
|
|
269
|
+
" each dancer's region, nationals and place per year"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
verb: "feis-dates",
|
|
274
|
+
value: ["--release"],
|
|
275
|
+
bool: [],
|
|
276
|
+
usage: [" feis-dates [--release <spec>] every feis's first and last day"]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
verb: "tabulated",
|
|
280
|
+
value: ["--release", "--min-round"],
|
|
281
|
+
bool: [],
|
|
282
|
+
usage: [
|
|
283
|
+
" tabulated [--release <spec>] [--min-round <n>]",
|
|
284
|
+
" the majors addresses the marks sheets tabulate to round n",
|
|
285
|
+
" or later (default 3)"
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
verb: "teams",
|
|
290
|
+
value: ["--release", "--event", "--year"],
|
|
291
|
+
bool: ["--rosters", "--joins"],
|
|
292
|
+
usage: [
|
|
293
|
+
" teams [--release <spec>] [--event <e>] [--year <y>] [--rosters | --joins]",
|
|
294
|
+
" the team result rows of an event-year; with --rosters its",
|
|
295
|
+
" roster teams and their dancers; with --joins how each roster",
|
|
296
|
+
" team meets the results"
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
verb: "events",
|
|
301
|
+
value: ["--release", "--event", "--year"],
|
|
302
|
+
bool: [],
|
|
303
|
+
usage: [
|
|
304
|
+
" events [--release <spec>] [--event <e>] [--year <y>]",
|
|
305
|
+
" each event-year's dates and place"
|
|
306
|
+
]
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
verb: "teacher",
|
|
310
|
+
value: ["--release"],
|
|
311
|
+
bool: [],
|
|
312
|
+
usage: [
|
|
313
|
+
" teacher [--release <spec>] <name|TD number>",
|
|
314
|
+
" the staff lists' people: where they taught, the register,",
|
|
315
|
+
" where they sat"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
verb: "adjudicator",
|
|
320
|
+
value: ["--release"],
|
|
321
|
+
bool: [],
|
|
322
|
+
usage: [
|
|
323
|
+
" adjudicator [--release <spec>] <name|TD number>",
|
|
324
|
+
" the register's and the panels' people: the same answer"
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
verb: "comp",
|
|
329
|
+
value: ["--release", "--year", "--title"],
|
|
330
|
+
bool: [],
|
|
331
|
+
usage: [
|
|
332
|
+
" comp [--release <spec>] <feis> <code> [--year <y>] [--title <t>]",
|
|
333
|
+
" a feis's own comp code to the comp it names, through that",
|
|
334
|
+
" feis's syllabus (the prior year's only where the platform",
|
|
335
|
+
" numbers every feis alike; elsewhere the title)"
|
|
336
|
+
]
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
verb: "syllabus",
|
|
340
|
+
value: ["--release", "--for"],
|
|
341
|
+
bool: [],
|
|
342
|
+
usage: [
|
|
343
|
+
" syllabus [--release <spec>] <feis> [year]",
|
|
344
|
+
" one feis-year's comps, in printed order",
|
|
345
|
+
" syllabus [--release <spec>] --for <series> [year]",
|
|
346
|
+
" a series' syllabus for a year: that year's where held,",
|
|
347
|
+
" else the newest, saying which and what it is read from"
|
|
348
|
+
]
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
verb: "resolve",
|
|
352
|
+
value: [
|
|
353
|
+
"--year",
|
|
354
|
+
"--title",
|
|
355
|
+
"--school",
|
|
356
|
+
"--comp",
|
|
357
|
+
"--yob",
|
|
358
|
+
"--band",
|
|
359
|
+
"--order",
|
|
360
|
+
"--as-of",
|
|
361
|
+
"--population",
|
|
362
|
+
"--oireachtas"
|
|
363
|
+
],
|
|
364
|
+
bool: [],
|
|
365
|
+
usage: [
|
|
366
|
+
" resolve comp [<feis> <code>] [--year <y>] [--title <t>]",
|
|
367
|
+
" resolve dancer [<name>] [--school <s>] [--comp <feis>/<code> | --yob <y> | --band <b> --year <y>]",
|
|
368
|
+
" [--order <o>] [--as-of <date>] [--population girls|boys]",
|
|
369
|
+
" [--oireachtas <region>[:<year>]]",
|
|
370
|
+
" resolve registrations",
|
|
371
|
+
" JSONL out, one answer per line; with no positional the",
|
|
372
|
+
" questions are JSONL on stdin, one per line (a comp:",
|
|
373
|
+
" {feis, code, year?, title?}, a dancer: {name, school?, age?,",
|
|
374
|
+
" population?, oireachtas?}, a registration: {name, school?,",
|
|
375
|
+
" codes[], feis, year?, population?, oireachtas?})"
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
];
|
|
379
|
+
var USAGE_FOOTER = [
|
|
380
|
+
" A query on the default spec prints one warning line on stderr when its release is older than",
|
|
381
|
+
" the newest published one (the remote asked at most once per hour, <cache>/LATEST.json); the",
|
|
382
|
+
" answer and the exit code are unchanged, and an offline check says nothing.",
|
|
383
|
+
"",
|
|
384
|
+
" Where the caller names local builds (a wrapper's option), a query with no --release answers",
|
|
385
|
+
" from the newest COMPLETE build newer than the pinned release, and says so in one line on",
|
|
386
|
+
" stderr; --release <spec> names a release, and --live forces the pinned one.",
|
|
387
|
+
"",
|
|
388
|
+
" <spec>: pinned (the default) | latest | a cut (42, 42.1) | a tag (archive-YYYY.MM.DD-N)"
|
|
389
|
+
];
|
|
390
|
+
function renderUsage() {
|
|
391
|
+
return [USAGE_HEADER, "", ...VERBS.flatMap((v) => v.usage), "", ...USAGE_FOOTER].join(`
|
|
392
|
+
`);
|
|
393
|
+
}
|
|
394
|
+
function valueFlags() {
|
|
395
|
+
return new Set([...GLOBAL_FLAGS.value, ...VERBS.flatMap((v) => v.value)]);
|
|
396
|
+
}
|
|
121
397
|
|
|
122
|
-
|
|
123
|
-
var VALUE =
|
|
124
|
-
"--cache",
|
|
125
|
-
"--repo",
|
|
126
|
-
"--release",
|
|
127
|
-
"--assets",
|
|
128
|
-
"--tag",
|
|
129
|
-
"--keep",
|
|
130
|
-
"--platform",
|
|
131
|
-
"--code",
|
|
132
|
-
"--id",
|
|
133
|
-
"--name",
|
|
134
|
-
"--year",
|
|
135
|
-
"--region",
|
|
136
|
-
"--order",
|
|
137
|
-
"--surname",
|
|
138
|
-
"--like",
|
|
139
|
-
"--school",
|
|
140
|
-
"--yob",
|
|
141
|
-
"--band",
|
|
142
|
-
"--comp",
|
|
143
|
-
"--as-of",
|
|
144
|
-
"--population",
|
|
145
|
-
"--oireachtas",
|
|
146
|
-
"--dancer",
|
|
147
|
-
"--feis",
|
|
148
|
-
"--limit",
|
|
149
|
-
"--event",
|
|
150
|
-
"--title",
|
|
151
|
-
"--for",
|
|
152
|
-
"--scope",
|
|
153
|
-
"--tier",
|
|
154
|
-
"--category",
|
|
155
|
-
"--level",
|
|
156
|
-
"--min-round"
|
|
157
|
-
]);
|
|
398
|
+
var USAGE = renderUsage();
|
|
399
|
+
var VALUE = valueFlags();
|
|
158
400
|
function parseArgs(argv) {
|
|
159
401
|
const positional = [];
|
|
160
402
|
const flags = new Map;
|
|
@@ -449,6 +691,10 @@ var ANSWERING = new Set([
|
|
|
449
691
|
"syllabus",
|
|
450
692
|
"resolve"
|
|
451
693
|
]);
|
|
694
|
+
var VERB_INDEXES = {
|
|
695
|
+
teams: ["teams"],
|
|
696
|
+
events: ["events"]
|
|
697
|
+
};
|
|
452
698
|
async function main(argv, io = {}) {
|
|
453
699
|
const say = io.say ?? ((s) => console.log(s));
|
|
454
700
|
const log = io.log ?? ((s) => console.error(s));
|
|
@@ -471,9 +717,43 @@ async function main(argv, io = {}) {
|
|
|
471
717
|
const spec = p.flags.get("--release") ?? "pinned";
|
|
472
718
|
const m = releases2(opts);
|
|
473
719
|
const fresh = io.freshness === false || spec.trim() !== "pinned" || verb === undefined || !ANSWERING.has(verb) ? null : io.freshness ?? {};
|
|
474
|
-
const answered = { tag: null };
|
|
720
|
+
const answered = { tag: null, build: null };
|
|
721
|
+
const local = io.local === undefined || io.local === false || p.flags.has("--release") || p.bools.has("--live") || verb === undefined || verb === "current" || !ANSWERING.has(verb) ? null : io.local;
|
|
722
|
+
const fromBuild = async (o) => {
|
|
723
|
+
if (local === null)
|
|
724
|
+
return null;
|
|
725
|
+
const root = cacheRoot2(o);
|
|
726
|
+
const builds = local.builds();
|
|
727
|
+
const pin = readPin2(root);
|
|
728
|
+
const baseTag = pin?.tag ?? m.cachedTags()[0] ?? null;
|
|
729
|
+
const baseRel = baseTag === null ? null : openCached2(baseTag, o);
|
|
730
|
+
const base = baseTag === null ? null : releaseVersion2(baseRel ?? { tag: baseTag, manifest: {} });
|
|
731
|
+
baseRel?.close();
|
|
732
|
+
const picked = builds.length === 0 ? null : pickBuild2(builds, base);
|
|
733
|
+
if (picked === null) {
|
|
734
|
+
sweepBuilds2(root, null);
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
const known = o.builders ?? defaultBuilders2();
|
|
738
|
+
const inputs = (VERB_INDEXES[verb] ?? []).flatMap((n) => known.find((x) => x.name === n)?.inputs ?? []);
|
|
739
|
+
const missing = lacks(picked.build, picked.manifest, inputs);
|
|
740
|
+
if (missing.length > 0) {
|
|
741
|
+
log(`${picked.build.label} (unpublished, ${picked.build.dir}) carries no ${missing.join(", ")}: answered from the published release`);
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
let rel;
|
|
745
|
+
try {
|
|
746
|
+
rel = await openBuild2(root, picked, o);
|
|
747
|
+
} catch (e) {
|
|
748
|
+
log(`${picked.build.label} (unpublished, ${picked.build.dir}) could not be read (${e.message}): answered from the published release`);
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
sweepBuilds2(root, rel.tag);
|
|
752
|
+
answered.build = picked;
|
|
753
|
+
return rel;
|
|
754
|
+
};
|
|
475
755
|
const open = async (s, o) => {
|
|
476
|
-
const rel = await openRelease2(s, o);
|
|
756
|
+
const rel = await fromBuild(o) ?? await openRelease2(s, o);
|
|
477
757
|
answered.tag = rel.tag;
|
|
478
758
|
return rel;
|
|
479
759
|
};
|
|
@@ -1015,21 +1295,30 @@ async function main(argv, io = {}) {
|
|
|
1015
1295
|
log(`idq ${verb}: ${e.message}`);
|
|
1016
1296
|
return 1;
|
|
1017
1297
|
} finally {
|
|
1298
|
+
const b = answered.build;
|
|
1299
|
+
if (b !== null)
|
|
1300
|
+
log(`answered from ${b.build.label} (unpublished, ${b.build.dir}). Pass --release <tag> for a published one, or --live for the pin.`);
|
|
1018
1301
|
if (fresh !== null && answered.tag !== null) {
|
|
1019
1302
|
const budget = fresh.budgetMs ?? LATEST_CHECK_BUDGET_MS2;
|
|
1020
1303
|
const c = check === null ? null : await within(check, budget - (now() - started));
|
|
1021
1304
|
const w = staleWarning2(answered.tag, c?.latest ?? null, fresh.floor ?? null, c?.tags ?? [], fresh.command);
|
|
1022
1305
|
if (w !== null)
|
|
1023
|
-
log(w);
|
|
1306
|
+
log(b === null ? w : w.replace(`answered from ${answered.tag}.`, `answered from ${b.build.label}.`));
|
|
1024
1307
|
}
|
|
1025
1308
|
}
|
|
1026
1309
|
}
|
|
1027
1310
|
if (import.meta.main)
|
|
1028
1311
|
process.exit(await main(process.argv.slice(2)));
|
|
1029
1312
|
export {
|
|
1313
|
+
GLOBAL_FLAGS,
|
|
1030
1314
|
USAGE,
|
|
1315
|
+
USAGE_FOOTER,
|
|
1316
|
+
USAGE_HEADER,
|
|
1317
|
+
VERBS,
|
|
1031
1318
|
jsonLines,
|
|
1032
1319
|
main,
|
|
1033
1320
|
parseArgs,
|
|
1034
|
-
|
|
1321
|
+
renderUsage,
|
|
1322
|
+
streamQueryOf,
|
|
1323
|
+
valueFlags
|
|
1035
1324
|
};
|
package/dist/index.js
CHANGED
|
@@ -53,13 +53,22 @@ import {
|
|
|
53
53
|
DEFAULT_KEEP2,
|
|
54
54
|
ReleaseManager2,
|
|
55
55
|
releases2,
|
|
56
|
+
LOCAL_DIR2,
|
|
57
|
+
localRoot2,
|
|
58
|
+
newerThan2,
|
|
59
|
+
incomplete2,
|
|
60
|
+
releaseVersion2,
|
|
61
|
+
pickBuild2,
|
|
62
|
+
buildTag2,
|
|
63
|
+
openBuild2,
|
|
64
|
+
sweepBuilds2,
|
|
56
65
|
LATEST_CHECK_MS2,
|
|
57
66
|
LATEST_CHECK_BUDGET_MS2,
|
|
58
67
|
latestCheckPath2,
|
|
59
68
|
readLatestCheck2,
|
|
60
69
|
latestCheck2,
|
|
61
70
|
staleWarning2
|
|
62
|
-
} from "./chunks/index-
|
|
71
|
+
} from "./chunks/index-vsk6837c.js";
|
|
63
72
|
import {
|
|
64
73
|
cacheRoot2,
|
|
65
74
|
repoOf2
|
|
@@ -87,6 +96,7 @@ export {
|
|
|
87
96
|
LATEST_CHECK_BUDGET_MS2 as LATEST_CHECK_BUDGET_MS,
|
|
88
97
|
LATEST_CHECK_MS2 as LATEST_CHECK_MS,
|
|
89
98
|
LINEAGE_FILE2 as LINEAGE_FILE,
|
|
99
|
+
LOCAL_DIR2 as LOCAL_DIR,
|
|
90
100
|
MajorsFinder2 as MajorsFinder,
|
|
91
101
|
NAME_LEVELS2 as NAME_LEVELS,
|
|
92
102
|
NO_CALENDAR2 as NO_CALENDAR,
|
|
@@ -98,6 +108,7 @@ export {
|
|
|
98
108
|
StaffFinder2 as StaffFinder,
|
|
99
109
|
TeamFinder2 as TeamFinder,
|
|
100
110
|
buildIndex2 as buildIndex,
|
|
111
|
+
buildTag2 as buildTag,
|
|
101
112
|
cacheRoot2 as cacheRoot,
|
|
102
113
|
canonicalOf2 as canonicalOf,
|
|
103
114
|
capabilityOf2 as capabilityOf,
|
|
@@ -111,6 +122,7 @@ export {
|
|
|
111
122
|
fallbackRemote2 as fallbackRemote,
|
|
112
123
|
ghRemote2 as ghRemote,
|
|
113
124
|
httpsRemote2 as httpsRemote,
|
|
125
|
+
incomplete2 as incomplete,
|
|
114
126
|
indexKey2 as indexKey,
|
|
115
127
|
indexPath2 as indexPath,
|
|
116
128
|
initialsOnly2 as initialsOnly,
|
|
@@ -119,12 +131,16 @@ export {
|
|
|
119
131
|
latestCheckPath2 as latestCheckPath,
|
|
120
132
|
linksOfLineage2 as linksOfLineage,
|
|
121
133
|
listIndexes2 as listIndexes,
|
|
134
|
+
localRoot2 as localRoot,
|
|
122
135
|
nameLevel2 as nameLevel,
|
|
123
136
|
needsRelease2 as needsRelease,
|
|
137
|
+
newerThan2 as newerThan,
|
|
138
|
+
openBuild2 as openBuild,
|
|
124
139
|
openCached2 as openCached,
|
|
125
140
|
openRelease2 as openRelease,
|
|
126
141
|
parseArchiveTag2 as parseArchiveTag,
|
|
127
142
|
parseReleaseSpec2 as parseReleaseSpec,
|
|
143
|
+
pickBuild2 as pickBuild,
|
|
128
144
|
pickTag2 as pickTag,
|
|
129
145
|
planAsset2 as planAsset,
|
|
130
146
|
readLatestCheck2 as readLatestCheck,
|
|
@@ -132,6 +148,7 @@ export {
|
|
|
132
148
|
readPopulation2 as readPopulation,
|
|
133
149
|
readsSpanishNames2 as readsSpanishNames,
|
|
134
150
|
releaseSchoolGraph2 as releaseSchoolGraph,
|
|
151
|
+
releaseVersion2 as releaseVersion,
|
|
135
152
|
releases2 as releases,
|
|
136
153
|
renderArchiveTag2 as renderArchiveTag,
|
|
137
154
|
repoOf2 as repoOf,
|
|
@@ -139,6 +156,7 @@ export {
|
|
|
139
156
|
setRemote2 as setRemote,
|
|
140
157
|
sha256File2 as sha256File,
|
|
141
158
|
staleWarning2 as staleWarning,
|
|
159
|
+
sweepBuilds2 as sweepBuilds,
|
|
142
160
|
syllabusSourceOf2 as syllabusSourceOf,
|
|
143
161
|
unzstdTo2 as unzstdTo,
|
|
144
162
|
youngest2 as youngest
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface VerbSpec {
|
|
2
|
+
verb: string;
|
|
3
|
+
value: readonly string[];
|
|
4
|
+
bool: readonly string[];
|
|
5
|
+
usage: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export declare const USAGE_HEADER = "usage: idq <verb> [--cache <dir>] [--repo <owner/name>] [--json] [--live]";
|
|
8
|
+
export declare const GLOBAL_FLAGS: {
|
|
9
|
+
value: readonly string[];
|
|
10
|
+
bool: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const VERBS: readonly VerbSpec[];
|
|
13
|
+
export declare const USAGE_FOOTER: readonly string[];
|
|
14
|
+
export declare function renderUsage(): string;
|
|
15
|
+
export declare function valueFlags(): Set<string>;
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { type FreshnessFloor } from "./freshness.js";
|
|
3
|
+
import { type LocalBuild } from "./local.js";
|
|
3
4
|
import type { OpenOptions } from "./release.js";
|
|
4
5
|
import type { StreamQuery } from "./stream.js";
|
|
5
|
-
export
|
|
6
|
+
export { GLOBAL_FLAGS, USAGE_FOOTER, USAGE_HEADER, VERBS, type VerbSpec, renderUsage, valueFlags, } from "./cli-spec.js";
|
|
7
|
+
export declare const USAGE: string;
|
|
6
8
|
export interface Parsed {
|
|
7
9
|
positional: string[];
|
|
8
10
|
flags: Map<string, string>;
|
|
@@ -18,6 +20,9 @@ type Line<T> = {
|
|
|
18
20
|
};
|
|
19
21
|
export declare function jsonLines<T>(text: string, check: (v: T) => string | null): Line<T>[];
|
|
20
22
|
export declare function streamQueryOf(p: Parsed): StreamQuery;
|
|
23
|
+
export interface LocalIO {
|
|
24
|
+
builds: () => readonly LocalBuild[];
|
|
25
|
+
}
|
|
21
26
|
export interface FreshnessIO {
|
|
22
27
|
floor?: FreshnessFloor | null;
|
|
23
28
|
command?: string;
|
|
@@ -30,5 +35,5 @@ export declare function main(argv: readonly string[], io?: {
|
|
|
30
35
|
opts?: OpenOptions;
|
|
31
36
|
stdin?: () => Promise<string>;
|
|
32
37
|
freshness?: FreshnessIO | false;
|
|
38
|
+
local?: LocalIO | false;
|
|
33
39
|
}): Promise<number>;
|
|
34
|
-
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { type Comp, type CompAnswer, type CompDance, type CompKind, type CompQue
|
|
|
7
7
|
export { type ClientOptions, cacheRoot, repoOf } from "./config.js";
|
|
8
8
|
export { type Feis, type FeisAnswer, FeisFinder, type FeisQuery, NO_CALENDAR, type Series, type SeriesAnswer, type SeriesInstance, type SeriesNext, } from "./feises.js";
|
|
9
9
|
export { type IndexBuilder, type IndexFile, buildIndex, defaultBuilders, ensureIndex, indexKey, indexPath, isCurrent, listIndexes, } from "./indexes.js";
|
|
10
|
+
export { type CutVersion, LOCAL_DIR, type LocalBuild, type PickedBuild, buildTag, incomplete, localRoot, newerThan, openBuild, pickBuild, releaseVersion, sweepBuilds, } from "./local.js";
|
|
10
11
|
export { type CachedRelease, DEFAULT_KEEP, type ReleaseList, ReleaseManager, type RemovalPlan, type UseResult, releases, } from "./manager.js";
|
|
11
12
|
export { type Registered, type Sat, type StaffAnswer, StaffFinder, type StaffPerson, type Taught, type TdLink, } from "./people.js";
|
|
12
13
|
export { type FreshnessFloor, LATEST_CHECK_BUDGET_MS, LATEST_CHECK_MS, type LatestCheck, latestCheck, latestCheckPath, readLatestCheck, staleWarning, } from "./freshness.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ReleaseManifest } from "./assets.js";
|
|
2
|
+
import { type OpenOptions, type Release } from "./release.js";
|
|
3
|
+
import type { Remote } from "./remote.js";
|
|
4
|
+
export interface LocalBuild {
|
|
5
|
+
dir: string;
|
|
6
|
+
label: string;
|
|
7
|
+
fraction?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface CutVersion {
|
|
10
|
+
cut: number;
|
|
11
|
+
fraction: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const LOCAL_DIR = "local";
|
|
14
|
+
export declare const localRoot: (root: string) => string;
|
|
15
|
+
export declare const newerThan: (a: CutVersion, b: CutVersion) => boolean;
|
|
16
|
+
export declare function incomplete(dir: string): string | null;
|
|
17
|
+
export declare function releaseVersion(rel: {
|
|
18
|
+
tag: string;
|
|
19
|
+
manifest: ReleaseManifest;
|
|
20
|
+
}): CutVersion | null;
|
|
21
|
+
export interface PickedBuild {
|
|
22
|
+
build: LocalBuild;
|
|
23
|
+
version: CutVersion;
|
|
24
|
+
manifest: ReleaseManifest;
|
|
25
|
+
}
|
|
26
|
+
export declare function pickBuild(builds: readonly LocalBuild[], base: CutVersion | null): PickedBuild | null;
|
|
27
|
+
export declare function buildTag(p: PickedBuild): string;
|
|
28
|
+
export declare function buildFiles(dir: string): string[];
|
|
29
|
+
export declare function lacks(b: LocalBuild, manifest: ReleaseManifest, inputs: readonly string[]): string[];
|
|
30
|
+
export declare function buildRemote(label: string): Remote;
|
|
31
|
+
export declare function buildOptions(root: string, label: string, opts: OpenOptions): OpenOptions;
|
|
32
|
+
export declare function openBuild(root: string, p: PickedBuild, opts: OpenOptions): Promise<Release>;
|
|
33
|
+
export declare function sweepBuilds(root: string, keep: string | null): string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finbheara/archive-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Open a versioned release of an Irish dance results archive: download, verify, decompress and cache it by tag, keep the cache, and resolve feises and schools against it",
|
|
5
5
|
"keywords": ["irish-dance", "results", "release", "cache", "sqlite"],
|
|
6
6
|
"license": "MIT",
|