@fnndsc/brasa 0.55.3 → 0.56.1
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/dist/buildinfo.json +1 -1
- package/dist/builtins/berth/berth.d.ts +18 -0
- package/dist/builtins/berth/berth.js +471 -0
- package/dist/builtins/berth/berth.js.map +1 -0
- package/dist/builtins/berth/berthClose.d.ts +23 -0
- package/dist/builtins/berth/berthClose.js +475 -0
- package/dist/builtins/berth/berthClose.js.map +1 -0
- package/dist/builtins/berth/berthCube.d.ts +238 -0
- package/dist/builtins/berth/berthCube.js +366 -0
- package/dist/builtins/berth/berthCube.js.map +1 -0
- package/dist/builtins/berth/berthDisk.d.ts +13 -0
- package/dist/builtins/berth/berthDisk.js +34 -0
- package/dist/builtins/berth/berthDisk.js.map +1 -0
- package/dist/builtins/berth/berthProcesses.d.ts +47 -0
- package/dist/builtins/berth/berthProcesses.js +204 -0
- package/dist/builtins/berth/berthProcesses.js.map +1 -0
- package/dist/builtins/berth/berthRecord.d.ts +210 -0
- package/dist/builtins/berth/berthRecord.js +130 -0
- package/dist/builtins/berth/berthRecord.js.map +1 -0
- package/dist/builtins/berth/berthState.d.ts +139 -0
- package/dist/builtins/berth/berthState.js +194 -0
- package/dist/builtins/berth/berthState.js.map +1 -0
- package/dist/builtins/berth/berthWords.d.ts +87 -0
- package/dist/builtins/berth/berthWords.js +78 -0
- package/dist/builtins/berth/berthWords.js.map +1 -0
- package/dist/builtins/helpSections.js +59 -1
- package/dist/builtins/helpSections.js.map +1 -1
- package/dist/chris/chrisCommands.js +6 -0
- package/dist/chris/chrisCommands.js.map +1 -1
- package/dist/chris/help.js +50 -0
- package/dist/chris/help.js.map +1 -1
- package/dist/notes.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file `berth close`: the berth's one outgoing folder returned to ChRIS as
|
|
3
|
+
* one node, with no plugin of its own.
|
|
4
|
+
*
|
|
5
|
+
* The close writes `berth.json` into the outgoing folder, uploads the folder
|
|
6
|
+
* to the person's CUBE files at `/home/<user>/berth/<uuid>/`, and makes the
|
|
7
|
+
* node from it with the registered ds plugin `pl-dsdircopy`, whose `dir` is
|
|
8
|
+
* that folder. Where the node goes follows from the anchors: every anchor
|
|
9
|
+
* under one node of the person's feeds makes it a child of that node; no
|
|
10
|
+
* anchor under their feeds makes a new feed, its root `pl-dircopy` over
|
|
11
|
+
* every anchored path with the work its child, or with no anchor at all the
|
|
12
|
+
* root `pl-dircopy` over the work itself. Anchors of two nodes, or of a node
|
|
13
|
+
* and of none, are refused with the two choices, `--infeed <anchor>` and
|
|
14
|
+
* `--newfeed`.
|
|
15
|
+
*
|
|
16
|
+
* Before the upload it asks when the person's processes still run in the
|
|
17
|
+
* berth (`--force` answers), and says what changed in ChRIS under an anchor
|
|
18
|
+
* with no node since it was anchored. A close that cannot make the node
|
|
19
|
+
* keeps the upload and says so; nothing in the berth is removed, and a close
|
|
20
|
+
* that made its node sets the state's `lastClosedAt`.
|
|
21
|
+
*
|
|
22
|
+
* Key components:
|
|
23
|
+
* - close_run: the subcommand.
|
|
24
|
+
* - CLOSE_USAGE: its usage line.
|
|
25
|
+
* - WORK_PLUGIN, WORK_TITLE: the plugin the work's node runs, and the node's title unless one is given.
|
|
26
|
+
*
|
|
27
|
+
* Typical usage:
|
|
28
|
+
* ```ts
|
|
29
|
+
* await close_run(places, ['--title', 'seg run']);
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* Dependencies: the berth's places and state (berthState.ts); ChRIS through
|
|
33
|
+
* berthCube.ts; the berth's processes from `/proc` (berthProcesses.ts); the
|
|
34
|
+
* session's sink and question.
|
|
35
|
+
*
|
|
36
|
+
* @module
|
|
37
|
+
*/
|
|
38
|
+
import { randomUUID } from 'node:crypto';
|
|
39
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
40
|
+
import { hostname } from 'node:os';
|
|
41
|
+
import { join, posix } from 'node:path';
|
|
42
|
+
import chalk from 'chalk';
|
|
43
|
+
import { size_format } from '@fnndsc/fond';
|
|
44
|
+
import { envelope_ok } from '@fnndsc/menu';
|
|
45
|
+
import { exitCode_set } from '../../core/handlerRun.js';
|
|
46
|
+
import { repl_confirm } from '../../core/question.js';
|
|
47
|
+
import { sink_dataLine } from '../../core/sink.js';
|
|
48
|
+
import { berthHome_get, feedName_set, feedRoot_create, folderContents_upload, pluginChild_run, remoteEntry_read, remoteTree_list, } from './berthCube.js';
|
|
49
|
+
import { processesOwn_list } from './berthProcesses.js';
|
|
50
|
+
import { anchorChanges_any, anchorChanges_compare, BERTH_RECORD_FILE, berthRecord_write, berthSource_read, } from './berthRecord.js';
|
|
51
|
+
import { berthState_read, berthState_update } from './berthState.js';
|
|
52
|
+
import { anchorNode_show, BerthRefusal, count_say, columns_render } from './berthWords.js';
|
|
53
|
+
/** The subcommand's usage line. */
|
|
54
|
+
export const CLOSE_USAGE = 'berth close [--infeed <anchor> | --newfeed] [--name <feed>] [--title <text>] [--force]';
|
|
55
|
+
/** The registered ds plugin the work's node runs: it copies its `dir` and does nothing else. */
|
|
56
|
+
export const WORK_PLUGIN = 'pl-dsdircopy';
|
|
57
|
+
/** The work node's title unless one is given. */
|
|
58
|
+
export const WORK_TITLE = 'berth work';
|
|
59
|
+
/** The environment variable naming the berth's image. */
|
|
60
|
+
const BERTH_IMAGE_ENV = 'MISE_BERTH_IMAGE';
|
|
61
|
+
/** The folder under the person's home the work is uploaded into, one folder per close. */
|
|
62
|
+
const BERTH_FILES_FOLDER = 'berth';
|
|
63
|
+
/** The options that take a value. */
|
|
64
|
+
const VALUE_OPTIONS = new Set(['--infeed', '--name', '--title']);
|
|
65
|
+
/**
|
|
66
|
+
* Reads the option words of a close: `--opt value` and `--opt=value` alike.
|
|
67
|
+
*
|
|
68
|
+
* @param args - The words after `close`.
|
|
69
|
+
* @returns The options in order.
|
|
70
|
+
* @throws {BerthRefusal} For an operand, an unknown option, or an option missing its value.
|
|
71
|
+
*/
|
|
72
|
+
function closeWords_read(args) {
|
|
73
|
+
const words = [];
|
|
74
|
+
for (let at = 0; at < args.length; at += 1) {
|
|
75
|
+
const arg = args[at];
|
|
76
|
+
const equals = arg.indexOf('=');
|
|
77
|
+
const option = arg.startsWith('--') && equals !== -1 ? arg.slice(0, equals) : arg;
|
|
78
|
+
if (VALUE_OPTIONS.has(option)) {
|
|
79
|
+
const value = equals !== -1 && arg.startsWith('--') ? arg.slice(equals + 1) : args[(at += 1)];
|
|
80
|
+
if (value === undefined || value === '')
|
|
81
|
+
throw new BerthRefusal(`close: ${option} wants a value; ${CLOSE_USAGE}`);
|
|
82
|
+
words.push({ option, value });
|
|
83
|
+
}
|
|
84
|
+
else if (arg === '--newfeed' || arg === '--force' || arg === '-f') {
|
|
85
|
+
words.push({ option: arg === '-f' ? '--force' : arg, value: null });
|
|
86
|
+
}
|
|
87
|
+
else if (arg.startsWith('-')) {
|
|
88
|
+
throw new BerthRefusal(`close: unknown option ${arg}; ${CLOSE_USAGE}`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw new BerthRefusal(`close: takes no operand (${arg}); ${CLOSE_USAGE}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return words;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reads `berth close`'s words.
|
|
98
|
+
*
|
|
99
|
+
* @param args - The words after `close`.
|
|
100
|
+
* @returns The request.
|
|
101
|
+
* @throws {BerthRefusal} As {@link closeWords_read} does, and for `--infeed` with `--newfeed`.
|
|
102
|
+
*/
|
|
103
|
+
function closeRequest_parse(args) {
|
|
104
|
+
const words = closeWords_read(args);
|
|
105
|
+
const last = (option) => words.filter((word) => word.option === option).at(-1)?.value ?? null;
|
|
106
|
+
const has = (option) => words.some((word) => word.option === option);
|
|
107
|
+
const request = {
|
|
108
|
+
infeed: last('--infeed'),
|
|
109
|
+
newfeed: has('--newfeed'),
|
|
110
|
+
name: last('--name'),
|
|
111
|
+
title: last('--title') ?? WORK_TITLE,
|
|
112
|
+
force: has('--force'),
|
|
113
|
+
};
|
|
114
|
+
if (request.infeed !== null && request.newfeed)
|
|
115
|
+
throw new BerthRefusal('close: --infeed and --newfeed are two places; give one');
|
|
116
|
+
return request;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The files of the outgoing folder that are work: every file under it but
|
|
120
|
+
* the record a close writes at its top.
|
|
121
|
+
*
|
|
122
|
+
* @param outgoing - The outgoing folder.
|
|
123
|
+
* @returns Their paths and sizes.
|
|
124
|
+
*/
|
|
125
|
+
function outgoingFiles_list(outgoing) {
|
|
126
|
+
const entries = existsSync(outgoing) ? readdirSync(outgoing, { withFileTypes: true, recursive: true }) : [];
|
|
127
|
+
const record = join(outgoing, BERTH_RECORD_FILE);
|
|
128
|
+
const files = [];
|
|
129
|
+
for (const entry of entries) {
|
|
130
|
+
if (entry.isDirectory())
|
|
131
|
+
continue;
|
|
132
|
+
const path = join(entry.parentPath, entry.name);
|
|
133
|
+
if (path === record)
|
|
134
|
+
continue;
|
|
135
|
+
files.push({ name: path, size: statSync(path, { throwIfNoEntry: false })?.size ?? 0 });
|
|
136
|
+
}
|
|
137
|
+
return files;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The words for an anchor and its node: `sub-01 (pl-fshack_41)`.
|
|
141
|
+
*
|
|
142
|
+
* @param anchor - The anchor.
|
|
143
|
+
* @returns The words.
|
|
144
|
+
*/
|
|
145
|
+
function anchorWithNode_say(anchor) {
|
|
146
|
+
return anchor.node === null ? `${anchor.name} (no node)` : `${anchor.name} (${anchorNode_show(anchor)})`;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The work as a child of an anchor's node.
|
|
150
|
+
*
|
|
151
|
+
* @param anchor - The anchor, with a node.
|
|
152
|
+
* @param by - What decided it.
|
|
153
|
+
* @returns The placement.
|
|
154
|
+
*/
|
|
155
|
+
function childOf_place(anchor, by) {
|
|
156
|
+
return { kind: 'child', by, parent: anchor.node, parentName: anchorNode_show(anchor), feed: anchor.feed, anchor: by === '--infeed' ? anchor.name : null };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Where the work's node goes, from the anchors and the flags: a child of
|
|
160
|
+
* the one node every anchor is under, or a new feed when no anchor is under
|
|
161
|
+
* a node; `--infeed` and `--newfeed` choose, and anchors of two nodes, or of
|
|
162
|
+
* a node and of none, want one of them.
|
|
163
|
+
*
|
|
164
|
+
* @param anchors - The berth's anchors.
|
|
165
|
+
* @param request - What was asked.
|
|
166
|
+
* @returns The placement.
|
|
167
|
+
* @throws {BerthRefusal} For anchors that point two ways with no flag, an `--infeed` anchor that is not there or has no node, and `--name` for a node in a feed that stands.
|
|
168
|
+
*/
|
|
169
|
+
function closePlacement_decide(anchors, request) {
|
|
170
|
+
const name = request.name ?? request.title;
|
|
171
|
+
const inputs = anchors.map((anchor) => anchor.path);
|
|
172
|
+
let placement;
|
|
173
|
+
if (request.newfeed) {
|
|
174
|
+
placement = { kind: 'newFeed', by: '--newfeed', name, inputs };
|
|
175
|
+
}
|
|
176
|
+
else if (request.infeed !== null) {
|
|
177
|
+
const chosen = anchors.find((anchor) => anchor.name === request.infeed);
|
|
178
|
+
if (chosen === undefined)
|
|
179
|
+
throw new BerthRefusal(`close: --infeed: no anchor named ${request.infeed}`);
|
|
180
|
+
if (chosen.node === null)
|
|
181
|
+
throw new BerthRefusal(`close: --infeed: ${chosen.name} has no node; --infeed takes an anchor under a node of your feeds, or --newfeed makes a new feed`);
|
|
182
|
+
placement = childOf_place({ ...chosen, node: chosen.node }, '--infeed');
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
placement = anchorsPlacement_decide(anchors, name, inputs);
|
|
186
|
+
}
|
|
187
|
+
if (placement.kind === 'child' && request.name !== null) {
|
|
188
|
+
throw new BerthRefusal(`close: --name names a new feed; the work goes into feed ${placement.feed ?? '?'} under ${placement.parentName}`);
|
|
189
|
+
}
|
|
190
|
+
return placement;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Where the anchors alone put the work, with no flag given.
|
|
194
|
+
*
|
|
195
|
+
* @param anchors - The berth's anchors.
|
|
196
|
+
* @param name - The new feed's name, should there be one.
|
|
197
|
+
* @param inputs - Every anchored path.
|
|
198
|
+
* @returns The placement.
|
|
199
|
+
* @throws {BerthRefusal} For anchors of two nodes, or of a node and of none.
|
|
200
|
+
*/
|
|
201
|
+
function anchorsPlacement_decide(anchors, name, inputs) {
|
|
202
|
+
const noded = anchors.filter((anchor) => anchor.node !== null);
|
|
203
|
+
if (noded.length === 0)
|
|
204
|
+
return { kind: 'newFeed', by: 'anchors', name, inputs };
|
|
205
|
+
const first = noded[0];
|
|
206
|
+
const other = noded.find((anchor) => anchor.node !== first.node);
|
|
207
|
+
const none = anchors.find((anchor) => anchor.node === null);
|
|
208
|
+
const choices = 'a node has one parent: --infeed <anchor> makes the work a child of that anchor\'s node, --newfeed a new feed over every anchor';
|
|
209
|
+
if (other !== undefined) {
|
|
210
|
+
throw new BerthRefusal(`close: the anchors are under two nodes, ${anchorWithNode_say(first)} and ${anchorWithNode_say(other)}; ${choices}`);
|
|
211
|
+
}
|
|
212
|
+
if (none !== undefined) {
|
|
213
|
+
throw new BerthRefusal(`close: ${anchorWithNode_say(first)} is under a node and ${none.name} is under none; ${choices}`);
|
|
214
|
+
}
|
|
215
|
+
return childOf_place({ ...first, node: first.node }, 'anchors');
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Says the person's processes still running in the berth and asks whether
|
|
219
|
+
* to return the work while they run; `--force` answers yes. A question
|
|
220
|
+
* nobody can answer (a surface whose input is closed) is a no, and says so.
|
|
221
|
+
*
|
|
222
|
+
* @param outgoing - The outgoing folder.
|
|
223
|
+
* @param force - Whether the question is answered already.
|
|
224
|
+
* @returns True to go on, false when the person said no or could not answer.
|
|
225
|
+
*/
|
|
226
|
+
async function processes_settle(outgoing, force) {
|
|
227
|
+
const running = processesOwn_list(outgoing);
|
|
228
|
+
if (running.length === 0)
|
|
229
|
+
return true;
|
|
230
|
+
const rows = [
|
|
231
|
+
['PID', 'COMMAND', `OPEN UNDER ${outgoing}`],
|
|
232
|
+
...running.map((one) => [String(one.pid), one.command, one.open.length === 0 ? '-' : one.open.join(', ')]),
|
|
233
|
+
];
|
|
234
|
+
sink_dataLine(`berth: close: ${running.length} ${running.length === 1 ? 'process' : 'processes'} of yours still ${running.length === 1 ? 'runs' : 'run'} in the berth:`);
|
|
235
|
+
for (const line of columns_render(rows))
|
|
236
|
+
sink_dataLine(` ${line}`);
|
|
237
|
+
if (force)
|
|
238
|
+
return true;
|
|
239
|
+
try {
|
|
240
|
+
return await repl_confirm(`berth: close: return ${outgoing} while ${running.length === 1 ? 'it runs' : 'they run'}?`);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
244
|
+
sink_dataLine(`berth: close: not answered (${reason}); --force returns the work while they run`);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The files ChRIS holds at an anchor's path at the close, named as the anchor named them.
|
|
250
|
+
*
|
|
251
|
+
* @param anchor - The anchor.
|
|
252
|
+
* @returns The files with their sizes; none when nothing stands there.
|
|
253
|
+
* @throws {Error} When ChRIS cannot be read there.
|
|
254
|
+
*/
|
|
255
|
+
async function anchorFilesNow_read(anchor) {
|
|
256
|
+
const entry = await remoteEntry_read(anchor.path);
|
|
257
|
+
if (entry === null)
|
|
258
|
+
return [];
|
|
259
|
+
if (entry.kind === 'file')
|
|
260
|
+
return [{ name: posix.basename(anchor.path), size: entry.size }];
|
|
261
|
+
return (await remoteTree_list(anchor.path)).map((file) => ({ name: file.name, size: file.size }));
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Says what changed in one comparison: the counts, or why it could not be made.
|
|
265
|
+
*
|
|
266
|
+
* @param changes - The comparison.
|
|
267
|
+
* @returns The words.
|
|
268
|
+
*/
|
|
269
|
+
function changes_say(changes) {
|
|
270
|
+
if (changes.unreadable !== null)
|
|
271
|
+
return `cannot compare with ChRIS: ${changes.unreadable}`;
|
|
272
|
+
const parts = [];
|
|
273
|
+
if (changes.added.length > 0)
|
|
274
|
+
parts.push(`${count_say(changes.added.length, 'file')} added`);
|
|
275
|
+
if (changes.removed.length > 0)
|
|
276
|
+
parts.push(`${count_say(changes.removed.length, 'file')} gone`);
|
|
277
|
+
if (changes.resized.length > 0)
|
|
278
|
+
parts.push(`${count_say(changes.resized.length, 'file')} of another size`);
|
|
279
|
+
return `changed in ChRIS since anchored: ${parts.join(', ')}`;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Compares every anchor with no node against what ChRIS holds at the close, and says
|
|
283
|
+
* what differs; an anchor under a node is skipped, since a finished node
|
|
284
|
+
* does not change.
|
|
285
|
+
*
|
|
286
|
+
* @param anchors - The berth's anchors.
|
|
287
|
+
* @returns The anchors as the record holds them.
|
|
288
|
+
*/
|
|
289
|
+
async function anchorsChanges_read(anchors) {
|
|
290
|
+
const recorded = [];
|
|
291
|
+
for (const anchor of anchors) {
|
|
292
|
+
if (anchor.node !== null) {
|
|
293
|
+
recorded.push({ ...anchor, changes: null });
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
let changes;
|
|
297
|
+
try {
|
|
298
|
+
changes = anchorChanges_compare(anchor.files, await anchorFilesNow_read(anchor));
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
changes = { added: [], removed: [], resized: [], unreadable: error instanceof Error ? error.message : String(error) };
|
|
302
|
+
}
|
|
303
|
+
if (anchorChanges_any(changes))
|
|
304
|
+
sink_dataLine(`berth: close: ${anchor.name}: ${changes_say(changes)}; ${BERTH_RECORD_FILE} lists them`);
|
|
305
|
+
recorded.push({ ...anchor, changes });
|
|
306
|
+
}
|
|
307
|
+
return recorded;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Makes the work's node where the placement says.
|
|
311
|
+
*
|
|
312
|
+
* @param placement - Where it goes.
|
|
313
|
+
* @param folder - The uploaded folder in the person's CUBE files.
|
|
314
|
+
* @param title - The work node's title.
|
|
315
|
+
* @returns The node, or CUBE's reason.
|
|
316
|
+
*/
|
|
317
|
+
async function work_attach(placement, folder, title) {
|
|
318
|
+
if (placement.kind === 'child') {
|
|
319
|
+
const work = await pluginChild_run(WORK_PLUGIN, placement.parent, { dir: folder, title });
|
|
320
|
+
if (!work.ok)
|
|
321
|
+
return { attached: null, reason: work.reason, root: null };
|
|
322
|
+
return { attached: { feed: work.feed ?? placement.feed, node: work.instance, plugin: work.pluginName, root: null }, reason: null, root: null };
|
|
323
|
+
}
|
|
324
|
+
if (placement.inputs.length === 0) {
|
|
325
|
+
// No anchor: the work is the feed's root, so its title is the node's,
|
|
326
|
+
// and the feed is named after it unless a name was given.
|
|
327
|
+
const root = await feedRoot_create([folder], title);
|
|
328
|
+
if (!root.ok)
|
|
329
|
+
return { attached: null, reason: root.reason, root: null };
|
|
330
|
+
if (placement.name !== title && root.feed !== null) {
|
|
331
|
+
const refused = await feedName_set(root.feed, placement.name);
|
|
332
|
+
if (refused !== null)
|
|
333
|
+
sink_dataLine(`berth: close: feed ${root.feed} keeps the name ${title}: ${refused}`);
|
|
334
|
+
}
|
|
335
|
+
return { attached: { feed: root.feed, node: root.instance, plugin: root.pluginName, root: null }, reason: null, root: null };
|
|
336
|
+
}
|
|
337
|
+
const root = await feedRoot_create(placement.inputs, placement.name);
|
|
338
|
+
if (!root.ok)
|
|
339
|
+
return { attached: null, reason: root.reason, root: null };
|
|
340
|
+
const work = await pluginChild_run(WORK_PLUGIN, root.instance, { dir: folder, title });
|
|
341
|
+
if (!work.ok)
|
|
342
|
+
return { attached: null, reason: work.reason, root };
|
|
343
|
+
return { attached: { feed: root.feed, node: work.instance, plugin: work.pluginName, root: root.instance }, reason: null, root };
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Puts the node made into the session's job index, so `/proc` shows it at
|
|
347
|
+
* once, and follows its run until it settles.
|
|
348
|
+
*
|
|
349
|
+
* @param placement - Where it went.
|
|
350
|
+
* @param attached - The node made.
|
|
351
|
+
* @param who - The person.
|
|
352
|
+
*/
|
|
353
|
+
async function work_index(placement, attached, who) {
|
|
354
|
+
if (attached.feed === null)
|
|
355
|
+
return;
|
|
356
|
+
const { newFeed_cacheAdd, run_follow } = await import('../feedCreation.js');
|
|
357
|
+
if (placement.kind === 'child') {
|
|
358
|
+
const { procCache_get } = await import('@fnndsc/cumin');
|
|
359
|
+
procCache_get().instance_add({ id: attached.node, feedID: attached.feed, parentID: placement.parent, pluginName: attached.plugin, params: null, status: 'scheduled' });
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
newFeed_cacheAdd({
|
|
363
|
+
feedID: attached.feed,
|
|
364
|
+
title: placement.name,
|
|
365
|
+
ownerUsername: who,
|
|
366
|
+
rootInstanceID: attached.root ?? attached.node,
|
|
367
|
+
...(attached.root === null ? {} : { child: { id: attached.node, pluginName: attached.plugin } }),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
run_follow(attached.feed);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Where the work went, in words.
|
|
374
|
+
*
|
|
375
|
+
* @param placement - Where it was placed.
|
|
376
|
+
* @param attached - The node made.
|
|
377
|
+
* @returns The line.
|
|
378
|
+
*/
|
|
379
|
+
function whereWent_say(placement, attached) {
|
|
380
|
+
const node = `node ${attached.node} (${attached.plugin})`;
|
|
381
|
+
const feed = `feed ${attached.feed ?? '?'}`;
|
|
382
|
+
if (placement.kind === 'child')
|
|
383
|
+
return `${feed}, ${node}, a child of ${placement.parentName}`;
|
|
384
|
+
if (attached.root === null)
|
|
385
|
+
return `the new ${feed} "${placement.name}", ${node}, its root`;
|
|
386
|
+
return `the new ${feed} "${placement.name}", ${node}, a child of pl-dircopy_${attached.root} over ${count_say(placement.inputs.length, 'anchored path')}`;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The record of a close, before its node is made.
|
|
390
|
+
*
|
|
391
|
+
* @param places - The berth's places.
|
|
392
|
+
* @param who - The person.
|
|
393
|
+
* @param anchors - The anchors with what changed.
|
|
394
|
+
* @param folder - The CUBE files folder.
|
|
395
|
+
* @param placement - Where the node goes.
|
|
396
|
+
* @param title - The work node's title.
|
|
397
|
+
* @returns The record.
|
|
398
|
+
*/
|
|
399
|
+
function closeRecord_build(places, who, anchors, folder, placement, title) {
|
|
400
|
+
const image = process.env[BERTH_IMAGE_ENV];
|
|
401
|
+
return {
|
|
402
|
+
version: 1,
|
|
403
|
+
who,
|
|
404
|
+
session: hostname(),
|
|
405
|
+
image: image === undefined || image === '' ? null : image,
|
|
406
|
+
source: berthSource_read(process.cwd()),
|
|
407
|
+
closedAt: new Date().toISOString(),
|
|
408
|
+
title,
|
|
409
|
+
anchors,
|
|
410
|
+
outgoing: places.outgoing,
|
|
411
|
+
folder,
|
|
412
|
+
placement,
|
|
413
|
+
attached: null,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* `berth close [--infeed <anchor> | --newfeed] [--name <feed>] [--title <text>] [--force]`:
|
|
418
|
+
* returns the outgoing folder to ChRIS as one node.
|
|
419
|
+
*
|
|
420
|
+
* @param places - The berth's places.
|
|
421
|
+
* @param args - The words after `close`.
|
|
422
|
+
* @returns Where the work went and its files folder, or that nothing closed.
|
|
423
|
+
* @throws {BerthRefusal} For an empty outgoing folder, a placement the anchors do not decide, and an upload that fails.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* ```ts
|
|
427
|
+
* await close_run({ anchors: '/anchors', outgoing: '/outgoing' }, ['--newfeed', '--name', 'seg run']);
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
export async function close_run(places, args) {
|
|
431
|
+
const request = closeRequest_parse(args);
|
|
432
|
+
const work = outgoingFiles_list(places.outgoing);
|
|
433
|
+
if (work.length === 0)
|
|
434
|
+
throw new BerthRefusal(`close: ${places.outgoing} is empty; nothing to close`);
|
|
435
|
+
const state = berthState_read(places.anchors);
|
|
436
|
+
const placement = closePlacement_decide(state.anchors, request);
|
|
437
|
+
const home = (await berthHome_get()).replace(/\/$/, '');
|
|
438
|
+
if (home === '')
|
|
439
|
+
throw new BerthRefusal('close: the session names no ChRIS home to upload to; connect first');
|
|
440
|
+
if (!await processes_settle(places.outgoing, request.force)) {
|
|
441
|
+
exitCode_set(1);
|
|
442
|
+
return envelope_ok('berth: close: nothing closed\n');
|
|
443
|
+
}
|
|
444
|
+
const anchors = await anchorsChanges_read(state.anchors);
|
|
445
|
+
const who = posix.basename(home);
|
|
446
|
+
const folder = `${home}/${BERTH_FILES_FOLDER}/${randomUUID()}`;
|
|
447
|
+
const record = closeRecord_build(places, who, anchors, folder, placement, request.title);
|
|
448
|
+
berthRecord_write(places.outgoing, record);
|
|
449
|
+
const total = work.reduce((sum, file) => sum + file.size, 0);
|
|
450
|
+
sink_dataLine(`berth: close: uploading ${count_say(work.length, 'file')}, ${size_format(total)}, and ${BERTH_RECORD_FILE} to ${folder}`);
|
|
451
|
+
let sent;
|
|
452
|
+
try {
|
|
453
|
+
sent = await folderContents_upload(places.outgoing, folder);
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
throw new BerthRefusal(`close: upload to ${folder}: ${error instanceof Error ? error.message : String(error)}; nothing attached`);
|
|
457
|
+
}
|
|
458
|
+
if (sent.failed > 0) {
|
|
459
|
+
throw new BerthRefusal(`close: ${count_say(sent.failed, 'file')} did not reach ${folder}; nothing attached, and what did reach it stays there`);
|
|
460
|
+
}
|
|
461
|
+
const made = await work_attach(placement, folder, request.title);
|
|
462
|
+
if (made.attached === null) {
|
|
463
|
+
exitCode_set(1);
|
|
464
|
+
const root = made.root?.ok === true ? `; the new feed ${made.root.feed ?? '?'} holds the anchored paths under pl-dircopy_${made.root.instance}` : '';
|
|
465
|
+
return envelope_ok(`${chalk.yellow(`berth: close: uploaded, not attached: ${made.reason ?? 'CUBE gave no reason'}${root}`)}\n${chalk.gray(`berth: close: the work stays in ${folder}`)}\n`);
|
|
466
|
+
}
|
|
467
|
+
const written = berthRecord_write(places.outgoing, { ...record, attached: made.attached });
|
|
468
|
+
await work_index(placement, made.attached, who);
|
|
469
|
+
// The close is no older than the record it wrote last, so `berth clear`
|
|
470
|
+
// never counts that record as work not yet closed.
|
|
471
|
+
const closedAt = new Date(Math.ceil(Math.max(Date.now(), statSync(written).mtimeMs))).toISOString();
|
|
472
|
+
berthState_update(places.anchors, (now) => ({ ...now, lastClosedAt: closedAt }));
|
|
473
|
+
return envelope_ok(`${chalk.green(`berth: close: the work is ${whereWent_say(placement, made.attached)}`)}\n${chalk.gray(`berth: close: its files are in ${folder}`)}\n`);
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=berthClose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"berthClose.js","sourceRoot":"","sources":["../../../src/builtins/berth/berthClose.ts"],"names":[],"mappings":"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"}
|