amalgm 0.1.188 → 0.1.189
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/package.json
CHANGED
|
@@ -341,6 +341,37 @@ test('the live service hears a commit through the git-dir doorbell', async () =>
|
|
|
341
341
|
assert.ok(repoCardServiceStats().doorbellRings >= 1);
|
|
342
342
|
});
|
|
343
343
|
|
|
344
|
+
test('the live service hears nested branch creation and deletion', async () => {
|
|
345
|
+
const repo = await makeRepo('projects/belled-refs');
|
|
346
|
+
const projects = path.join(tempRoot, 'projects');
|
|
347
|
+
upsertWorkspace({ path: projects, name: 'Projects', source: 'computer' });
|
|
348
|
+
startRepoCardService();
|
|
349
|
+
await refreshRepoCards();
|
|
350
|
+
const branch = 'storm/nested-short';
|
|
351
|
+
const before = findCard(listRepoCards(), repo);
|
|
352
|
+
|
|
353
|
+
await run(repo, 'branch', branch);
|
|
354
|
+
let deadline = Date.now() + 5_000;
|
|
355
|
+
let created = findCard(listRepoCards(), repo);
|
|
356
|
+
while (!created.refs.some((ref) => ref.name === branch) && Date.now() < deadline) {
|
|
357
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
358
|
+
created = findCard(listRepoCards(), repo);
|
|
359
|
+
}
|
|
360
|
+
assert.ok(created.refs.some((ref) => ref.name === branch));
|
|
361
|
+
|
|
362
|
+
await run(repo, 'branch', '-D', branch);
|
|
363
|
+
deadline = Date.now() + 5_000;
|
|
364
|
+
let deleted = findCard(listRepoCards(), repo);
|
|
365
|
+
while (deleted.refs.some((ref) => ref.name === branch) && Date.now() < deadline) {
|
|
366
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
367
|
+
deleted = findCard(listRepoCards(), repo);
|
|
368
|
+
}
|
|
369
|
+
stopRepoCardService();
|
|
370
|
+
|
|
371
|
+
assert.equal(deleted.refs.some((ref) => ref.name === branch), false);
|
|
372
|
+
assert.equal(deleted.generation, before.generation + 2);
|
|
373
|
+
});
|
|
374
|
+
|
|
344
375
|
test('the live service hears an uncommitted nested edit without a polling pass', async () => {
|
|
345
376
|
const repo = await makeRepo('projects/live-dirty');
|
|
346
377
|
const projects = path.join(tempRoot, 'projects');
|
|
@@ -413,24 +413,49 @@ function ringDoorbell(replicaId) {
|
|
|
413
413
|
bell.timer = setTimeout(() => {
|
|
414
414
|
bell.timer = null;
|
|
415
415
|
refreshRepoCard(replicaId)
|
|
416
|
-
.then(() =>
|
|
416
|
+
.then((card) => {
|
|
417
|
+
if (card) rebuildDoorbell(replicaId, card);
|
|
418
|
+
return require('./checkpoint').publishCheckpoints(replicaId);
|
|
419
|
+
})
|
|
417
420
|
.catch((error) => console.warn('[RepoCards] doorbell refresh failed:', error.message));
|
|
418
421
|
}, DOORBELL_QUIET_MS);
|
|
419
422
|
bell.timer.unref?.();
|
|
420
423
|
}
|
|
421
424
|
|
|
425
|
+
function nestedDirectories(root) {
|
|
426
|
+
const directories = [];
|
|
427
|
+
const pending = [root];
|
|
428
|
+
while (pending.length > 0) {
|
|
429
|
+
const current = pending.pop();
|
|
430
|
+
let entries;
|
|
431
|
+
try {
|
|
432
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
433
|
+
} catch {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
directories.push(current);
|
|
437
|
+
for (const entry of entries) {
|
|
438
|
+
if (entry.isDirectory()) pending.push(path.join(current, entry.name));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return directories;
|
|
442
|
+
}
|
|
443
|
+
|
|
422
444
|
function watchGitDir(card) {
|
|
423
445
|
const watchers = [];
|
|
424
446
|
const ring = () => ringDoorbell(card.replica);
|
|
425
447
|
// The git dir itself carries HEAD, index, and operation markers; logs/
|
|
426
448
|
// carries the reflog, which moves on every commit, checkout, and reset.
|
|
427
449
|
const common = card.commonGitDir || card.gitDir;
|
|
428
|
-
|
|
450
|
+
const direct = [
|
|
429
451
|
card.gitDir,
|
|
430
452
|
path.join(card.gitDir, 'logs'),
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
453
|
+
];
|
|
454
|
+
const refDirectories = [
|
|
455
|
+
...nestedDirectories(path.join(common, 'refs', 'heads')),
|
|
456
|
+
...nestedDirectories(path.join(common, 'logs', 'refs', 'heads')),
|
|
457
|
+
];
|
|
458
|
+
for (const dir of new Set([...direct, ...refDirectories])) {
|
|
434
459
|
try {
|
|
435
460
|
const watcher = fs.watch(dir, ring);
|
|
436
461
|
watcher.on('error', () => watcher.close());
|
|
@@ -455,6 +480,14 @@ function watchGitDir(card) {
|
|
|
455
480
|
return watchers;
|
|
456
481
|
}
|
|
457
482
|
|
|
483
|
+
function rebuildDoorbell(replicaId, card) {
|
|
484
|
+
const bell = service.doorbells.get(replicaId);
|
|
485
|
+
if (!bell) return;
|
|
486
|
+
const previous = bell.watchers;
|
|
487
|
+
bell.watchers = watchGitDir(card);
|
|
488
|
+
for (const watcher of previous) watcher.close();
|
|
489
|
+
}
|
|
490
|
+
|
|
458
491
|
function dropDoorbell(replicaId) {
|
|
459
492
|
const bell = service.doorbells.get(replicaId);
|
|
460
493
|
if (!bell) return;
|