@fnndsc/salsa 4.4.3 → 4.5.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.
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @file Reading a plugin's descriptor out of its container image.
3
+ *
4
+ * The last way `plugin add` finds a descriptor: pull the image (or use the
5
+ * local copy) and ask it, trying the three ways ChRIS plugins have printed
6
+ * one over the years, in chrisomatic's order — `chris_plugin_info` with the
7
+ * image named, `chris_plugin_info` bare, and the old chrisapp `<CMD> --json`.
8
+ *
9
+ * Every docker call is an argument vector run without a shell: an image
10
+ * reference is operator input and never reaches a command line as text.
11
+ *
12
+ * Key components:
13
+ * - DockerRun: the seam that runs one docker command (tests stub it).
14
+ * - docker_isAvailable: whether a docker daemon answers.
15
+ * - dockerImage_ensure: the image locally, pulled when absent.
16
+ * - descriptorFromImage_extract: the image's descriptor JSON, by the three ways.
17
+ *
18
+ * Typical usage:
19
+ * ```ts
20
+ * if (await docker_isAvailable() && await dockerImage_ensure(image)) {
21
+ * const descriptor: Record<string, unknown> | null = await descriptorFromImage_extract(image);
22
+ * }
23
+ * ```
24
+ *
25
+ * Dependencies: Node.js `child_process`; a `docker` CLI on the host.
26
+ *
27
+ * @module
28
+ */
29
+ /** What one docker command answered. */
30
+ export interface DockerAnswer {
31
+ /** True when the command exited zero. */
32
+ readonly ok: boolean;
33
+ /** Its standard output, trimmed. */
34
+ readonly stdout: string;
35
+ /** Its standard error or failure message, trimmed. */
36
+ readonly stderr: string;
37
+ }
38
+ /** Runs one docker command from its argument vector. */
39
+ export type DockerRun = (args: readonly string[]) => Promise<DockerAnswer>;
40
+ /**
41
+ * Runs `docker` with an argument vector, no shell.
42
+ *
43
+ * @param args - The arguments after `docker`.
44
+ * @returns What it answered; never throws.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const answer: DockerAnswer = await docker_run(['image', 'inspect', 'alpine']);
49
+ * ```
50
+ */
51
+ export declare const docker_run: DockerRun;
52
+ /**
53
+ * Reports whether a docker daemon answers.
54
+ *
55
+ * @param run - The docker seam.
56
+ * @returns True when `docker info` succeeds.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * await docker_isAvailable(); // false on a host without docker
61
+ * ```
62
+ */
63
+ export declare function docker_isAvailable(run?: DockerRun): Promise<boolean>;
64
+ /**
65
+ * Makes sure an image is present locally, pulling it when it is not.
66
+ *
67
+ * @param image - The image reference.
68
+ * @param run - The docker seam.
69
+ * @returns Null when the image is present; else why it could not be had.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * await dockerImage_ensure('fnndsc/pl-dircopy:2.1.1'); // null
74
+ * ```
75
+ */
76
+ export declare function dockerImage_ensure(image: string, run?: DockerRun): Promise<string | null>;
77
+ /**
78
+ * Reads a plugin's descriptor out of its image.
79
+ *
80
+ * @param image - The image reference.
81
+ * @param publicRepo - The plugin's repository, passed to `chris_plugin_info` when known.
82
+ * @param run - The docker seam.
83
+ * @returns The descriptor, or null when none of the three ways printed one.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const descriptor: Record<string, unknown> | null = await descriptorFromImage_extract('fnndsc/pl-dircopy:2.1.1');
88
+ * ```
89
+ */
90
+ export declare function descriptorFromImage_extract(image: string, publicRepo?: string, run?: DockerRun): Promise<Record<string, unknown> | null>;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * @file Reading a plugin's descriptor out of its container image.
4
+ *
5
+ * The last way `plugin add` finds a descriptor: pull the image (or use the
6
+ * local copy) and ask it, trying the three ways ChRIS plugins have printed
7
+ * one over the years, in chrisomatic's order — `chris_plugin_info` with the
8
+ * image named, `chris_plugin_info` bare, and the old chrisapp `<CMD> --json`.
9
+ *
10
+ * Every docker call is an argument vector run without a shell: an image
11
+ * reference is operator input and never reaches a command line as text.
12
+ *
13
+ * Key components:
14
+ * - DockerRun: the seam that runs one docker command (tests stub it).
15
+ * - docker_isAvailable: whether a docker daemon answers.
16
+ * - dockerImage_ensure: the image locally, pulled when absent.
17
+ * - descriptorFromImage_extract: the image's descriptor JSON, by the three ways.
18
+ *
19
+ * Typical usage:
20
+ * ```ts
21
+ * if (await docker_isAvailable() && await dockerImage_ensure(image)) {
22
+ * const descriptor: Record<string, unknown> | null = await descriptorFromImage_extract(image);
23
+ * }
24
+ * ```
25
+ *
26
+ * Dependencies: Node.js `child_process`; a `docker` CLI on the host.
27
+ *
28
+ * @module
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.docker_run = void 0;
32
+ exports.docker_isAvailable = docker_isAvailable;
33
+ exports.dockerImage_ensure = dockerImage_ensure;
34
+ exports.descriptorFromImage_extract = descriptorFromImage_extract;
35
+ const node_child_process_1 = require("node:child_process");
36
+ /** Longest a descriptor print may take: some images (TensorFlow, MINC) take minutes. */
37
+ const DESCRIPTOR_TIMEOUT_MS = 10 * 60 * 1000;
38
+ /** Largest output read from a docker command. */
39
+ const OUTPUT_MAX_BYTES = 32 * 1024 * 1024;
40
+ /**
41
+ * Runs `docker` with an argument vector, no shell.
42
+ *
43
+ * @param args - The arguments after `docker`.
44
+ * @returns What it answered; never throws.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const answer: DockerAnswer = await docker_run(['image', 'inspect', 'alpine']);
49
+ * ```
50
+ */
51
+ const docker_run = (args) => new Promise((resolve) => {
52
+ (0, node_child_process_1.execFile)('docker', [...args], { timeout: DESCRIPTOR_TIMEOUT_MS, maxBuffer: OUTPUT_MAX_BYTES }, (error, stdout, stderr) => {
53
+ resolve({ ok: error === null, stdout: String(stdout).trim(), stderr: String(stderr || error?.message || '').trim() });
54
+ });
55
+ });
56
+ exports.docker_run = docker_run;
57
+ /**
58
+ * Reports whether a docker daemon answers.
59
+ *
60
+ * @param run - The docker seam.
61
+ * @returns True when `docker info` succeeds.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * await docker_isAvailable(); // false on a host without docker
66
+ * ```
67
+ */
68
+ async function docker_isAvailable(run = exports.docker_run) {
69
+ return (await run(['info', '--format', '{{.ServerVersion}}'])).ok;
70
+ }
71
+ /**
72
+ * Makes sure an image is present locally, pulling it when it is not.
73
+ *
74
+ * @param image - The image reference.
75
+ * @param run - The docker seam.
76
+ * @returns Null when the image is present; else why it could not be had.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * await dockerImage_ensure('fnndsc/pl-dircopy:2.1.1'); // null
81
+ * ```
82
+ */
83
+ async function dockerImage_ensure(image, run = exports.docker_run) {
84
+ if ((await run(['image', 'inspect', '--format', '{{.Id}}', image])).ok)
85
+ return null;
86
+ const pulled = await run(['pull', '--quiet', image]);
87
+ return pulled.ok ? null : `docker pull ${image} failed: ${pulled.stderr || 'no reason given'}`;
88
+ }
89
+ /**
90
+ * Reads a plugin's descriptor out of its image.
91
+ *
92
+ * @param image - The image reference.
93
+ * @param publicRepo - The plugin's repository, passed to `chris_plugin_info` when known.
94
+ * @param run - The docker seam.
95
+ * @returns The descriptor, or null when none of the three ways printed one.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const descriptor: Record<string, unknown> | null = await descriptorFromImage_extract('fnndsc/pl-dircopy:2.1.1');
100
+ * ```
101
+ */
102
+ async function descriptorFromImage_extract(image, publicRepo, run = exports.docker_run) {
103
+ const withArgs = ['run', '--rm', image, 'chris_plugin_info', '--dock-image', image];
104
+ if (publicRepo !== undefined)
105
+ withArgs.push('--public-repo', publicRepo);
106
+ const attempts = [
107
+ () => run(withArgs),
108
+ () => run(['run', '--rm', image, 'chris_plugin_info']),
109
+ async () => {
110
+ const command = await imageCommand_get(image, run);
111
+ return command === null ? null : run(['run', '--rm', image, command, '--json']);
112
+ },
113
+ ];
114
+ for (const attempt of attempts) {
115
+ const answer = await attempt();
116
+ if (answer === null || !answer.ok || answer.stdout === '')
117
+ continue;
118
+ const parsed = descriptorJson_parse(answer.stdout);
119
+ if (parsed !== null)
120
+ return parsed;
121
+ }
122
+ return null;
123
+ }
124
+ /**
125
+ * Reads an image's default command, for the old chrisapp `--json` way.
126
+ *
127
+ * @param image - The image reference.
128
+ * @param run - The docker seam.
129
+ * @returns The first word of the image's CMD, or null when it has none.
130
+ */
131
+ async function imageCommand_get(image, run) {
132
+ const answer = await run(['image', 'inspect', '--format', '{{json .Config.Cmd}}', image]);
133
+ if (!answer.ok)
134
+ return null;
135
+ try {
136
+ const command = JSON.parse(answer.stdout);
137
+ return Array.isArray(command) && typeof command[0] === 'string' ? command[0] : null;
138
+ }
139
+ catch {
140
+ return null;
141
+ }
142
+ }
143
+ /**
144
+ * Parses a printed descriptor.
145
+ *
146
+ * @param text - What the image printed.
147
+ * @returns The descriptor object, or null when the text is not one.
148
+ */
149
+ function descriptorJson_parse(text) {
150
+ try {
151
+ const parsed = JSON.parse(text);
152
+ return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ }
158
+ //# sourceMappingURL=plugin_docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin_docker.js","sourceRoot":"","sources":["../../src/plugins/plugin_docker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @file Plugin indexes: where descriptors come from, and reading them.
3
+ *
4
+ * A plugin index is a set of plugin descriptors, one JSON file per plugin at
5
+ * its latest version, in the form CUBE's administrative upload takes, with
6
+ * the JSON Schema they follow beside them. FNNDSC/chris-plugins is the one
7
+ * that matters; a directory of `.json` files or a `.tar.gz` holding one is
8
+ * an index too, on CUBE (how a surface with no host access syncs) or on the
9
+ * host.
10
+ *
11
+ * Every source reads to the same {@link PluginIndex}: its descriptors as
12
+ * text (so a later check can quote the file), the schema when one came with
13
+ * them, and the commit when the source can name one. GitHub's archive of a
14
+ * ref is fetched once, whole; its pax global header names the exact commit.
15
+ *
16
+ * Layout read from any source: descriptors are the `.json` files at the root
17
+ * or under `plugins/`; the schema is `schema/plugin.schema.json` at the root
18
+ * or one level up (a `plugins/` directory handed over on its own).
19
+ *
20
+ * Key components:
21
+ * - PluginIndexSource: a parsed source (GitHub repository at a ref, CUBE path, host path).
22
+ * - PluginIndex: the descriptors, schema and commit read from a source.
23
+ * - pluginIndexSource_parse: read a source word (`FNNDSC/chris-plugins@main`, `host:./plugins`).
24
+ * - pluginIndexArchive_read: read an index from archive bytes.
25
+ * - pluginIndex_load: read an index from any source.
26
+ *
27
+ * Typical usage:
28
+ * ```ts
29
+ * const source: PluginIndexSource | null = pluginIndexSource_parse('FNNDSC/chris-plugins@main', 'cube');
30
+ * const loaded: Result<PluginIndex> = source ? await pluginIndex_load(source) : Err();
31
+ * ```
32
+ *
33
+ * Dependencies: Node.js built-ins (`node:fs`, `node:path`), `fetch` for the
34
+ * GitHub archive, salsa's CUBE file reads for CUBE paths.
35
+ *
36
+ * @module
37
+ */
38
+ import { type Result } from '@fnndsc/cumin';
39
+ /**
40
+ * Where an index is read from.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const source: PluginIndexSource = { kind: 'github', owner: 'FNNDSC', repo: 'chris-plugins', ref: 'main' };
45
+ * ```
46
+ */
47
+ export type PluginIndexSource = {
48
+ readonly kind: 'github';
49
+ readonly owner: string;
50
+ readonly repo: string;
51
+ readonly ref: string;
52
+ } | {
53
+ readonly kind: 'cube';
54
+ readonly path: string;
55
+ } | {
56
+ readonly kind: 'host';
57
+ readonly path: string;
58
+ };
59
+ /**
60
+ * One descriptor file of an index.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const descriptor: IndexDescriptor = { file: 'pl-dircopy.json', text: '{"name":"pl-dircopy"}' };
65
+ * ```
66
+ */
67
+ export interface IndexDescriptor {
68
+ /** The file's name (`pl-dircopy.json`), which rule 3 holds to the plugin's name. */
69
+ readonly file: string;
70
+ /** The file's text, as read. */
71
+ readonly text: string;
72
+ }
73
+ /**
74
+ * An index, read.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const index: PluginIndex = pluginIndexArchive_read(bytes, 'FNNDSC/chris-plugins@main');
79
+ * index.descriptors.length;
80
+ * ```
81
+ */
82
+ export interface PluginIndex {
83
+ /** The source as the operator would write it. */
84
+ readonly source: string;
85
+ /** A short name for headers: `chris-plugins @ 8c9a1f6`. */
86
+ readonly label: string;
87
+ /** The full commit the descriptors were read at, when the source names one. */
88
+ readonly commit: string | null;
89
+ /** Every descriptor, sorted by file name. */
90
+ readonly descriptors: IndexDescriptor[];
91
+ /** The parsed JSON Schema, or null when none came with the descriptors. */
92
+ readonly schema: unknown;
93
+ }
94
+ /**
95
+ * Parses an index source word.
96
+ *
97
+ * `owner/repo[@ref]` is a GitHub repository; `host:<path>` a host path;
98
+ * `cube:<path>` a CUBE path. Any other word is a path, read where `bare`
99
+ * says: `plugin sync` reads a bare path on CUBE, `plugin validate` (which
100
+ * needs no CUBE) on the host.
101
+ *
102
+ * @param word - The source as typed.
103
+ * @param bare - Where a path with no prefix is read.
104
+ * @param ref - A ref overriding the word's own (`--ref`), for a GitHub source.
105
+ * @returns The parsed source, or null for an empty word.
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * pluginIndexSource_parse('FNNDSC/chris-plugins@v1', 'cube'); // { kind: 'github', …, ref: 'v1' }
110
+ * pluginIndexSource_parse('host:./plugins', 'cube'); // { kind: 'host', path: './plugins' }
111
+ * ```
112
+ */
113
+ export declare function pluginIndexSource_parse(word: string, bare: 'cube' | 'host', ref?: string): PluginIndexSource | null;
114
+ /**
115
+ * Renders a source as the operator would write it.
116
+ *
117
+ * @param source - The parsed source.
118
+ * @returns The source word (`FNNDSC/chris-plugins@main`, `host:./plugins`, `cube:/home/u/plugins`).
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * pluginIndexSource_format({ kind: 'host', path: './plugins' }); // 'host:./plugins'
123
+ * ```
124
+ */
125
+ export declare function pluginIndexSource_format(source: PluginIndexSource): string;
126
+ /**
127
+ * Reads an index from archive bytes.
128
+ *
129
+ * A single top folder (GitHub's `FNNDSC-chris-plugins-<sha>/`) is the root;
130
+ * the pax global header's `comment` is the commit.
131
+ *
132
+ * @param bytes - The archive, gzipped or plain.
133
+ * @param source - The source word, for the index's `source` and `label`.
134
+ * @returns The index.
135
+ * @throws {Error} When the archive is unreadable, an entry's path is unsafe,
136
+ * or the schema it carries is not JSON.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const index: PluginIndex = pluginIndexArchive_read(readFileSync('index.tar.gz'), 'FNNDSC/chris-plugins@main');
141
+ * ```
142
+ */
143
+ export declare function pluginIndexArchive_read(bytes: Buffer, source: string): PluginIndex;
144
+ /**
145
+ * Reads an index from its source.
146
+ *
147
+ * @param source - The parsed source.
148
+ * @param fetcher - The fetch used for GitHub; the global one by default.
149
+ * @returns The index, or an error on the error stack (the fetch failed, the
150
+ * path is not there, the archive is unreadable).
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const loaded: Result<PluginIndex> = await pluginIndex_load({ kind: 'host', path: './plugins' });
155
+ * ```
156
+ */
157
+ export declare function pluginIndex_load(source: PluginIndexSource, fetcher?: typeof fetch): Promise<Result<PluginIndex>>;