source: Klonkt/scripts/export-archive.mjs@ a4fea5e

main
Last change on this file since a4fea5e was a4fea5e, checked in by roboburr <roboburr@…>, 5 weeks ago

De instance-naam is niet de site-slug, en vlagwaarden zijn geen argumenten

Vervolg op 6248497. Het instance-pad werkte, maar export-archive.mjs liz gaf
"onbekende site: liz" -- en liet je vervolgens raden.

## De naam van de instance is niet de slug van de site

De map onder de data-root en de systemd-unit heten liz; de SITE in die database
kan een andere slug hebben. Ze vallen vaak samen en soms niet, en dan stond je met
een foutmelding die niets prijsgaf.

Twee dingen veranderd:

  • de foutmelding zegt nu WAT er wel in die database staat, en als er helemaal geen sites in staan vraagt hij of DATABASE_PATH wel klopt
  • de site-slug is optioneel geworden. Staat er precies een site, dan is de keuze niet dubbelzinnig en hoef je hem niet te weten; hij meldt welke hij nam. Bij meerdere sites stopt hij en noemt ze.

node scripts/export-archive.mjs <instance> [site-slug]

## En een parseerfout die ik er zelf net in had gezet

args.filter(a => !a.startsWith('-')) pikt de WAARDE van een vlag op als
positioneel argument. Met liz --data-root /var/lib/klonkt werd /var/lib/klonkt
de site-slug. Gevonden bij het testen van het bovenstaande, en import-archive.mjs
had hem ook: daar zou het pad naar het archief verschoven zijn.

Nu een gedeelde splitsArgs() die weet welke vlaggen een waarde slikken.

Getoetst met een instance 'liz' waarvan de site 'lizzy' heet -- precies het geval
dat op productie omviel: zonder slug pakt hij lizzy en zegt dat, met de verkeerde
slug noemt hij wat er wel is, en met de juiste plus --out schrijft hij het archief.
Suite 577/577 onder UTC en Europe/Amsterdam.

  • Property mode set to 100644
File size: 4.8 KB
Line 
1#!/usr/bin/env node
2//
3// Exporteer het inhoudsarchief van een site (shaer-1a6).
4//
5// node scripts/export-archive.mjs <slug> --dry-run
6// node scripts/export-archive.mjs <slug> --out boiert.zip
7// node scripts/export-archive.mjs <slug> --dir ./archief
8//
9// Op een machine met meerdere instances leest hij de .env van die instance zelf
10// (standaard /var/lib/klonkt/<slug>/.env). Dat is niet netjesheid maar noodzaak:
11// zonder die .env opent hij de database die toevallig in de code-map ligt, en op
12// een server die ooit de enkelvoudige opzet draaide is dat een oude lege. Dan
13// komt er een archief uit dat MELDT dat het gelukt is en nul posts bevat.
14//
15// --data-root <map> waar de instances staan (standaard /var/lib/klonkt)
16// --env <pad> een .env rechtstreeks aanwijzen
17//
18// Het formaat staat in docs/EXPORT-FORMAT.md.
19//
20// Dit is NIET de storage-zip: er zit geen sleutel, sessie, wachtwoordhash of
21// DM van een ander in. Wel je eigen concepten, en -- als je die hebt -- de
22// volledige inhoud van betaalde posts. Behandel het bestand als de inhoud zelf.
23
24import fs from 'fs';
25import path from 'path';
26import { kiesInstance, eisOrigin, splitsArgs } from './instance-env.mjs';
27
28const args = process.argv.slice(2);
29// Twee namen, en ze zijn niet hetzelfde. De eerste is de INSTANCE (de map onder
30// de data-root, de systemd-unit); de tweede, optioneel, is de slug van de SITE in
31// die database. Laat je hem weg en er staat er precies een, dan is de keuze niet
32// dubbelzinnig en hoef je hem niet te weten.
33const { vrij, vlaggen } = splitsArgs(args, ['--data-root', '--env', '--out', '--dir']);
34const instance = vrij[0];
35let slug = vrij[1] || null;
36const vlag = (naam) => vlaggen[naam] ?? null;
37
38if (!instance) {
39 console.error('gebruik: node scripts/export-archive.mjs <instance> [site-slug] [--data-root <map>] [--env <pad>] [--dry-run | --out <zip> | --dir <map>]');
40 process.exit(1);
41}
42
43// EERST de instance kiezen, DAN pas de service laden: src/config/database.js
44// leest DATABASE_PATH bij import en opent de database meteen.
45let gekozen;
46try {
47 gekozen = kiesInstance(instance, {
48 dataRoot: typeof vlag('--data-root') === 'string' ? vlag('--data-root') : null,
49 envPad: typeof vlag('--env') === 'string' ? vlag('--env') : null,
50 });
51} catch (e) { console.error(e.message); process.exit(1); }
52eisOrigin(gekozen.bron);
53
54const { buildArchive, zipArchive, writeArchiveDir } = await import('../src/services/ArchiveExportService.js');
55const { default: db } = await import('../src/config/database.js');
56
57// Geen slug gegeven? Dan mag de database het zeggen, mits het antwoord eenduidig is.
58if (!slug) {
59 let sites = [];
60 try { sites = db.prepare('SELECT slug FROM sites ORDER BY rowid').all().map((r) => r.slug); } catch { /* geen tabel */ }
61 if (sites.length === 1) {
62 [slug] = sites;
63 console.log(`site niet opgegeven, en er staat er precies een: ${slug}`);
64 } else if (sites.length === 0) {
65 console.error(`in ${process.env.DATABASE_PATH || 'deze database'} staat geen enkele site.`);
66 process.exit(1);
67 } else {
68 console.error(`meerdere sites in deze database: ${sites.join(', ')}\nGeef er een op: node scripts/export-archive.mjs ${instance} <site-slug>`);
69 process.exit(1);
70 }
71}
72
73let uit;
74try { uit = buildArchive(slug); }
75catch (e) {
76 console.error(`${e.message}`);
77 if (gekozen.bron) console.error(`(gelezen uit ${gekozen.bron})`);
78 else console.error('(geen instance-.env gevonden -- op een split install: --data-root /var/lib/klonkt)');
79 process.exit(1);
80}
81const t = uit.counts;
82console.log(`site : ${uit.manifest.site.slug} (${uit.manifest.origin})`);
83console.log(`instellingen uit: ${gekozen.bron || 'de omgeving'}`);
84console.log(`database : ${process.env.DATABASE_PATH || '(standaard in de code-map)'}`);
85console.log(`posts : ${t.posts}`);
86console.log(`antwoorden: ${t.replies} (alleen-lezen archief)`);
87console.log(`media : ${t.media} meegenomen, ${t.mediaMissing} ontbrekend`);
88
89// Ontbrekende media worden GETELD en GEMELD, nooit stil overgeslagen: een post
90// waarvan het plaatje verdwenen is hoort dat te zeggen.
91if (uit.missing.length) {
92 console.log('\nontbrekende media:');
93 for (const m of uit.missing.slice(0, 20)) console.log(` ${m.post} ${m.url}`);
94 if (uit.missing.length > 20) console.log(` ... en nog ${uit.missing.length - 20}`);
95}
96
97if (args.includes('--dry-run')) {
98 console.log(`\n--dry-run: ${uit.files.size} bestand(en) zouden geschreven worden. Niets geschreven.`);
99 process.exit(0);
100}
101
102const dir = vlag('--dir');
103if (dir && typeof dir === 'string') {
104 writeArchiveDir(uit.files, dir);
105 console.log(`\ngeschreven naar ${path.resolve(dir)}`);
106 process.exit(0);
107}
108
109const out = (typeof vlag('--out') === 'string' ? vlag('--out') : null) || `${slug}-archief.zip`;
110fs.writeFileSync(out, zipArchive(uit.files));
111console.log(`\ngeschreven: ${out} (${fs.statSync(out).size} bytes)`);
Note: See TracBrowser for help on using the repository browser.