gitnexus 1.6.4-rc.79 → 1.6.4-rc.80
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fsp from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { createHash } from 'node:crypto';
|
|
3
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
4
4
|
import lbug from '@ladybugdb/core';
|
|
5
5
|
import { BRIDGE_SCHEMA_QUERIES, BRIDGE_SCHEMA_VERSION } from './bridge-schema.js';
|
|
6
6
|
import { closeLbugConnection, openLbugConnection, } from '../lbug/lbug-config.js';
|
|
@@ -17,7 +17,7 @@ import { dedupeContracts, dedupeCrossLinks } from './normalization.js';
|
|
|
17
17
|
* - `.shadow` — non-blocking concurrent checkpoint sidecar (added in
|
|
18
18
|
* LadybugDB 0.15.4); same pairing constraint as `.wal`.
|
|
19
19
|
*
|
|
20
|
-
* `bridge-db` writes to a `bridge.lbug.tmp
|
|
20
|
+
* `bridge-db` writes to a `bridge.lbug.tmp.<random>` file and then atomically renames
|
|
21
21
|
* it into place. The rename only moves the main file; sidecars must be
|
|
22
22
|
* cleaned up explicitly or the next writer trips the database-id check.
|
|
23
23
|
*/
|
|
@@ -33,6 +33,24 @@ async function removeLbugFile(basePath) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Remove all stale `bridge.lbug.tmp.*` files (and their sidecars) from a
|
|
38
|
+
* group directory. With randomBytes-based temp names, a crashed writeBridge
|
|
39
|
+
* leaves behind a uniquely-named tmp file that no future run will target by
|
|
40
|
+
* name — so we glob for the prefix and clean up everything matching.
|
|
41
|
+
*/
|
|
42
|
+
async function cleanStaleBridgeTmpFiles(groupDir) {
|
|
43
|
+
try {
|
|
44
|
+
const entries = await fsp.readdir(groupDir);
|
|
45
|
+
const staleBases = entries.filter((e) => e.startsWith('bridge.lbug.tmp.') && !LBUG_SIDECAR_SUFFIXES.some((s) => e.endsWith(s)));
|
|
46
|
+
for (const name of staleBases) {
|
|
47
|
+
await removeLbugFile(path.join(groupDir, name));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* best-effort: directory may not exist yet */
|
|
52
|
+
}
|
|
53
|
+
}
|
|
36
54
|
export function contractNodeId(repo, contractId, role, filePath) {
|
|
37
55
|
return createHash('sha256').update(`${repo}\0${contractId}\0${role}\0${filePath}`).digest('hex');
|
|
38
56
|
}
|
|
@@ -211,7 +229,7 @@ export async function retryRename(src, dst, attempts = 3) {
|
|
|
211
229
|
/* ------------------------------------------------------------------ */
|
|
212
230
|
export async function writeBridgeMeta(groupDir, meta) {
|
|
213
231
|
const target = path.join(groupDir, 'meta.json');
|
|
214
|
-
const tmp = `${target}.tmp.${
|
|
232
|
+
const tmp = `${target}.tmp.${randomBytes(8).toString('hex')}`;
|
|
215
233
|
await fsp.writeFile(tmp, JSON.stringify(meta, null, 2), 'utf-8');
|
|
216
234
|
// Use retryRename for consistency with writeBridge's atomic swap — on
|
|
217
235
|
// Windows a concurrent reader can cause EBUSY/EPERM even on a tiny
|
|
@@ -244,7 +262,7 @@ export async function writeBridge(groupDir, input) {
|
|
|
244
262
|
const contracts = dedupeContracts(input.contracts);
|
|
245
263
|
const crossLinks = dedupeCrossLinks(input.crossLinks);
|
|
246
264
|
const finalPath = path.join(groupDir, 'bridge.lbug');
|
|
247
|
-
const tmpPath = path.join(groupDir,
|
|
265
|
+
const tmpPath = path.join(groupDir, `bridge.lbug.tmp.${randomBytes(8).toString('hex')}`);
|
|
248
266
|
const bakPath = path.join(groupDir, 'bridge.lbug.bak');
|
|
249
267
|
const report = {
|
|
250
268
|
contractsInserted: 0,
|
|
@@ -261,11 +279,12 @@ export async function writeBridge(groupDir, input) {
|
|
|
261
279
|
report.sampleErrors.push({ kind, id, message: errMessage(err) });
|
|
262
280
|
}
|
|
263
281
|
};
|
|
264
|
-
// Clean up
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
|
|
282
|
+
// Clean up stale tmp files left behind by previously crashed writeBridge
|
|
283
|
+
// runs. With randomBytes-based names each run picks a unique path, so
|
|
284
|
+
// the old fixed-name `removeLbugFile(tmpPath)` was a no-op — stale
|
|
285
|
+
// artifacts accumulated. The glob-based helper finds *all* leftover
|
|
286
|
+
// `bridge.lbug.tmp.*` entries and removes them (including sidecars).
|
|
287
|
+
await cleanStaleBridgeTmpFiles(groupDir);
|
|
269
288
|
// 1. Create temp DB, insert all data.
|
|
270
289
|
//
|
|
271
290
|
// Everything after `openBridgeDb` must run inside a try/finally so that
|
|
@@ -2,6 +2,7 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as fsp from 'node:fs/promises';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import * as os from 'node:os';
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
5
6
|
const CONTRACTS_FILE = 'contracts.json';
|
|
6
7
|
export function getDefaultGitnexusDir() {
|
|
7
8
|
return process.env.GITNEXUS_HOME || path.join(os.homedir(), '.gitnexus');
|
|
@@ -21,7 +22,7 @@ export function getGroupDir(gitnexusDir, groupName) {
|
|
|
21
22
|
}
|
|
22
23
|
export async function writeContractRegistry(groupDir, registry) {
|
|
23
24
|
const targetPath = path.join(groupDir, CONTRACTS_FILE);
|
|
24
|
-
const tmpPath = `${targetPath}.tmp.${
|
|
25
|
+
const tmpPath = `${targetPath}.tmp.${randomBytes(8).toString('hex')}`;
|
|
25
26
|
await fsp.writeFile(tmpPath, JSON.stringify(registry, null, 2), 'utf-8');
|
|
26
27
|
await fsp.rename(tmpPath, targetPath);
|
|
27
28
|
}
|
package/package.json
CHANGED