@ibgib/vcs-gib 0.0.18 → 0.0.21
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/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/bootstrap/node-bootstrap.d.mts.map +1 -1
- package/dist/bootstrap/node-bootstrap.mjs +2 -2
- package/dist/bootstrap/node-bootstrap.mjs.map +1 -1
- package/dist/cli/commands/branch-cmd.d.mts.map +1 -1
- package/dist/cli/commands/branch-cmd.mjs.map +1 -1
- package/dist/cli/commands/merge-cmd.d.mts.map +1 -1
- package/dist/cli/commands/merge-cmd.mjs +1 -1
- package/dist/cli/commands/merge-cmd.mjs.map +1 -1
- package/dist/engine/item/item-helper.d.mts +1 -0
- package/dist/engine/item/item-helper.d.mts.map +1 -1
- package/dist/engine/item/item-helper.mjs +13 -3
- package/dist/engine/item/item-helper.mjs.map +1 -1
- package/dist/engine/item/item-types.d.mts +1 -0
- package/dist/engine/item/item-types.d.mts.map +1 -1
- package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts +12 -2
- package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts.map +1 -1
- package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs +384 -236
- package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs.map +1 -1
- package/dist/engine/merge/b2tfs-3way-merge-types.d.mts +41 -0
- package/dist/engine/merge/b2tfs-3way-merge-types.d.mts.map +1 -0
- package/dist/engine/merge/b2tfs-3way-merge-types.mjs +2 -0
- package/dist/engine/merge/b2tfs-3way-merge-types.mjs.map +1 -0
- package/package.json +5 -5
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/bootstrap/node-bootstrap.mts +4 -3
- package/src/cli/commands/branch-checkout-cmd.respec.log +111 -0
- package/src/cli/commands/branch-cmd.mts +2 -4
- package/src/cli/commands/merge-cmd.mts +2 -6
- package/src/engine/item/item-helper.mts +15 -9
- package/src/engine/item/item-types.mts +2 -1
- package/src/engine/merge/b2tfs-3way-merge-strategy.mts +388 -261
- package/src/engine/merge/b2tfs-3way-merge-strategy.respec.log +39 -0
- package/src/engine/merge/{b2tfs-merge-strategy.respec.mts → b2tfs-3way-merge-strategy.respec.mts} +16 -13
- package/src/engine/merge/b2tfs-3way-merge-types.mts +42 -0
- package/tsconfig.json +3 -2
- package/tsconfig.test.json +10 -0
- package/tsconfig.test.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/assumptions.respec.d.mts +0 -2
- package/dist/assumptions.respec.d.mts.map +0 -1
- package/dist/assumptions.respec.mjs +0 -41
- package/dist/assumptions.respec.mjs.map +0 -1
- package/dist/bootstrap/node-bootstrap.respec.d.mts +0 -7
- package/dist/bootstrap/node-bootstrap.respec.d.mts.map +0 -1
- package/dist/bootstrap/node-bootstrap.respec.mjs +0 -28
- package/dist/bootstrap/node-bootstrap.respec.mjs.map +0 -1
- package/dist/cli/cli-arg-parser.respec.d.mts +0 -7
- package/dist/cli/cli-arg-parser.respec.d.mts.map +0 -1
- package/dist/cli/cli-arg-parser.respec.mjs +0 -35
- package/dist/cli/cli-arg-parser.respec.mjs.map +0 -1
- package/dist/cli/cli-e2e.respec.d.mts +0 -8
- package/dist/cli/cli-e2e.respec.d.mts.map +0 -1
- package/dist/cli/cli-e2e.respec.mjs +0 -263
- package/dist/cli/cli-e2e.respec.mjs.map +0 -1
- package/dist/cli/commands/branch-checkout-cmd.respec.d.mts +0 -7
- package/dist/cli/commands/branch-checkout-cmd.respec.d.mts.map +0 -1
- package/dist/cli/commands/branch-checkout-cmd.respec.mjs +0 -452
- package/dist/cli/commands/branch-checkout-cmd.respec.mjs.map +0 -1
- package/dist/cli/commands/commit-log-cmd.respec.d.mts +0 -7
- package/dist/cli/commands/commit-log-cmd.respec.d.mts.map +0 -1
- package/dist/cli/commands/commit-log-cmd.respec.mjs +0 -251
- package/dist/cli/commands/commit-log-cmd.respec.mjs.map +0 -1
- package/dist/cli/commands/init-cmd.respec.d.mts +0 -7
- package/dist/cli/commands/init-cmd.respec.d.mts.map +0 -1
- package/dist/cli/commands/init-cmd.respec.mjs +0 -40
- package/dist/cli/commands/init-cmd.respec.mjs.map +0 -1
- package/dist/cli/commands/reset-restore-cmd.respec.d.mts +0 -7
- package/dist/cli/commands/reset-restore-cmd.respec.d.mts.map +0 -1
- package/dist/cli/commands/reset-restore-cmd.respec.mjs +0 -185
- package/dist/cli/commands/reset-restore-cmd.respec.mjs.map +0 -1
- package/dist/cli/commands/status-add-cmd.respec.d.mts +0 -7
- package/dist/cli/commands/status-add-cmd.respec.d.mts.map +0 -1
- package/dist/cli/commands/status-add-cmd.respec.mjs +0 -239
- package/dist/cli/commands/status-add-cmd.respec.mjs.map +0 -1
- package/dist/engine/branch/branch-space.respec.d.mts +0 -8
- package/dist/engine/branch/branch-space.respec.d.mts.map +0 -1
- package/dist/engine/branch/branch-space.respec.mjs +0 -143
- package/dist/engine/branch/branch-space.respec.mjs.map +0 -1
- package/dist/engine/diff/line-diff-helper.respec.d.mts +0 -7
- package/dist/engine/diff/line-diff-helper.respec.d.mts.map +0 -1
- package/dist/engine/diff/line-diff-helper.respec.mjs +0 -66
- package/dist/engine/diff/line-diff-helper.respec.mjs.map +0 -1
- package/dist/engine/filter/glob-helper.respec.d.mts +0 -7
- package/dist/engine/filter/glob-helper.respec.d.mts.map +0 -1
- package/dist/engine/filter/glob-helper.respec.mjs +0 -78
- package/dist/engine/filter/glob-helper.respec.mjs.map +0 -1
- package/dist/engine/item/item.respec.d.mts +0 -7
- package/dist/engine/item/item.respec.d.mts.map +0 -1
- package/dist/engine/item/item.respec.mjs +0 -75
- package/dist/engine/item/item.respec.mjs.map +0 -1
- package/dist/engine/merge/b2tfs-merge-strategy.respec.d.mts +0 -7
- package/dist/engine/merge/b2tfs-merge-strategy.respec.d.mts.map +0 -1
- package/dist/engine/merge/b2tfs-merge-strategy.respec.mjs +0 -335
- package/dist/engine/merge/b2tfs-merge-strategy.respec.mjs.map +0 -1
- package/dist/vcs-gib.respec.d.mts +0 -8
- package/dist/vcs-gib.respec.d.mts.map +0 -1
- package/dist/vcs-gib.respec.mjs +0 -82
- package/dist/vcs-gib.respec.mjs.map +0 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import crypto from 'node:crypto';
|
|
8
8
|
|
|
9
|
-
import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
9
|
+
import { extractErrorMsg, hash, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
10
10
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
11
11
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
12
12
|
import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
@@ -29,12 +29,15 @@ import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.m
|
|
|
29
29
|
|
|
30
30
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
31
31
|
import { isBinaryBuffer, decodeToLines, computeLineLcsDiff } from '../diff/line-diff-helper.mjs';
|
|
32
|
-
import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME } from '../item/item-types.mjs';
|
|
33
|
-
import { evolveB2tFSItemIbGib } from '../item/item-helper.mjs';
|
|
32
|
+
import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME, B2tFSType } from '../item/item-types.mjs';
|
|
33
|
+
import { evolveB2tFSItemIbGib, isB2tFSItemIbGib } from '../item/item-helper.mjs';
|
|
34
34
|
import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
|
|
35
|
+
import { B2TFS_ITEM_ATOM } from '../item/item-atom-helper.mjs';
|
|
36
|
+
import { B2tFS3WayAddlGraftDetails } from './b2tfs-3way-merge-types.mjs';
|
|
35
37
|
|
|
36
38
|
const lcFile = `[b2tfs-3way-merge-strategy]`;
|
|
37
|
-
const logalot = GLOBAL_LOG_A_LOT;
|
|
39
|
+
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
40
|
+
const mergeDiag = `[MERGE DIAGNOSTIC]`;
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
43
|
* 3-way text line diff merge result.
|
|
@@ -158,24 +161,36 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
158
161
|
readonly strategyId: string = 'B2tFS3WayGraftStrategy';
|
|
159
162
|
private lc = '[B2tFS3WayGraftStrategy]';
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Returns true only if the graft context has two tips that are text-based file b2tfs item ibgibs.
|
|
166
|
+
*
|
|
167
|
+
* ## notes
|
|
168
|
+
*
|
|
169
|
+
* atow (08/12/2026) implementation is guantlet style: if cannot graft, return early
|
|
170
|
+
*
|
|
171
|
+
* @param context info about the divergent timelines {@link GraftContext}
|
|
172
|
+
*
|
|
173
|
+
* @returns true if it's a text file item ibgib, else false
|
|
174
|
+
*/
|
|
169
175
|
async canGraft(context: GraftContext): Promise<boolean> {
|
|
170
176
|
const lc = `${this.lc}[${this.canGraft.name}]`;
|
|
171
177
|
try {
|
|
172
178
|
const { conflictStrategy, timelineAddrsA, timelineAddrsB, ibGibReadCache, space } = context;
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
|
|
180
|
+
// todo: refactor conflict strategy to be more generic: 'graft' | 'abort' | maybe something else.
|
|
181
|
+
const hasRelevantStrategy = conflictStrategy === SyncConflictStrategy.optimisticWithLCS || (conflictStrategy as string) === 'b2tfs3WayMerge';
|
|
182
|
+
if (!hasRelevantStrategy) {
|
|
183
|
+
// immediately return false because we are not the chosen strategy.
|
|
184
|
+
// todo: after refactor, really this should be out of the hands of the implementation and we should have a discriminator as part of the strategy interface. So the graft strategy pipeline executor can just check that first, and then if multiple found, it will delegate to this `canGraft` method.
|
|
185
|
+
return false; /* <<<< returns early */
|
|
175
186
|
}
|
|
187
|
+
|
|
176
188
|
const tipAddrA = timelineAddrsA.at(-1);
|
|
177
189
|
const tipAddrB = timelineAddrsB.at(-1);
|
|
178
|
-
if (!tipAddrA || !tipAddrB) {
|
|
190
|
+
if (!tipAddrA || !tipAddrB) {
|
|
191
|
+
if (logalot) { console.log(`${lc} we don't have two tip addrs? how was a graft decided upon? (I: b20b6de462c35e0e74360cc8d317f126)`); }
|
|
192
|
+
return false; /* <<<< returns early */
|
|
193
|
+
}
|
|
179
194
|
|
|
180
195
|
const [tipA, tipB] = await getIbGibsFromCache_fallbackToSpaces({
|
|
181
196
|
addrs: [tipAddrA, tipAddrB],
|
|
@@ -183,14 +198,34 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
183
198
|
space,
|
|
184
199
|
});
|
|
185
200
|
|
|
186
|
-
|
|
201
|
+
if (!tipA) { throw new Error(`(UNEXPECTED) tipA falsy? couldn't get tipA? should have been available to us in the temp space or cache.(E: 752101026888140f074614e893531826)`); }
|
|
202
|
+
if (!tipB) { throw new Error(`(UNEXPECTED) tipB falsy? couldn't get tipB? should have been available to us in the temp space or cache. (E: d4d4a876cad8c7869830d33832bfde26)`); }
|
|
203
|
+
|
|
204
|
+
const bothTipsAreB2tFSNodes = isB2tFSItemIbGib(tipA) && isB2tFSItemIbGib(tipB);
|
|
205
|
+
|
|
206
|
+
if (!bothTipsAreB2tFSNodes) {
|
|
207
|
+
// at this point, we're returning false. But I'm being extra defensive since this algorithm is so difficult to implement. So throw if somehow only one is a b2tfs item
|
|
208
|
+
if (isB2tFSItemIbGib(tipA) || isB2tFSItemIbGib(tipB)) {
|
|
209
|
+
console.error(`${lc}${mergeDiag} (UNEXPECTED)(NOT THROWN) only tipA or tipB but not both are b2tfs items? (E: cacb38796da881268898e9d1af245826)`)
|
|
210
|
+
}
|
|
211
|
+
return false; /* <<<< returns early */
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (tipA.data.fsType !== tipB.data.fsType) { throw new Error(`(UNEXPECTED) tipA.data.fsType (${tipA.data.fsType}) !== tipB.data.fsType (${tipB.data.fsType})? both tips are expected to be the same B2tFSType. (E: c01c1885ac738f679813117852c48426)`); }
|
|
215
|
+
|
|
216
|
+
// only do files. folders can use the replay dna strategy.
|
|
217
|
+
const isFile = tipA.data.fsType === B2tFSType.file;
|
|
218
|
+
if (!isFile) { return false; /* <<<< returns early */ }
|
|
219
|
+
|
|
220
|
+
// passed gauntlet, we have a b2tfs file item that we can merge
|
|
221
|
+
return true;
|
|
187
222
|
} catch (error) {
|
|
188
223
|
console.error(`${lc} ${extractErrorMsg(error)} (E: 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e)`);
|
|
189
224
|
return false;
|
|
190
225
|
}
|
|
191
226
|
}
|
|
192
227
|
|
|
193
|
-
async graft(context: GraftContext): Promise<GraftTimelinesResult> {
|
|
228
|
+
async graft(context: GraftContext): Promise<GraftTimelinesResult | undefined> {
|
|
194
229
|
const lc = `${lcFile}[${this.strategyId}][${this.graft.name}]`;
|
|
195
230
|
try {
|
|
196
231
|
if (logalot) {
|
|
@@ -241,12 +276,12 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
241
276
|
branchB_receiver_sinceLCA,
|
|
242
277
|
});
|
|
243
278
|
|
|
244
|
-
|
|
245
|
-
|
|
246
279
|
const baseTipAddr = getIbGibAddr({ ibGib: baseTip });
|
|
247
280
|
const baseBranchAddrs = baseBranch.map(x => getIbGibAddr({ ibGib: x }));
|
|
248
281
|
const orphanTipAddr = getIbGibAddr({ ibGib: orphanTip });
|
|
249
282
|
const orphanBranchAddrs = orphanBranch.map(x => getIbGibAddr({ ibGib: x }));
|
|
283
|
+
if (logalot) { console.log(`${lc} baseBranchAddrs:\n${baseBranchAddrs.join('\n')}\n(I: 2cad420d7bc822f798b8a8785f1f8c26)`); }
|
|
284
|
+
if (logalot) { console.log(`${lc} orphanBranchAddrs:\n${orphanBranchAddrs.join('\n')}\n(I: cc86489d6737e2aced42b585cba13526)`); }
|
|
250
285
|
|
|
251
286
|
// 3. Replay orphan branch transforms onto base tip
|
|
252
287
|
const [latestCommonFrameIbGib] = await getIbGibsFromCache_fallbackToSpaces({
|
|
@@ -254,138 +289,302 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
254
289
|
space,
|
|
255
290
|
});
|
|
256
291
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
292
|
+
// It is non-trivial and not at all obvious, but the following approach is WRONG!!
|
|
293
|
+
//
|
|
294
|
+
// This is not a generic timeline, rather, this is a timeline that
|
|
295
|
+
// is restricted to a b2tfs node, which itself has two
|
|
296
|
+
// possibilities: file or folder. So we can't replay dna blindly
|
|
297
|
+
// between the two branches and then try to do some kind of text
|
|
298
|
+
// merge later. We must analyze each branch and decide how to handle
|
|
299
|
+
// each change.
|
|
300
|
+
//
|
|
301
|
+
// NOTE: I have tweaked canGraft to only return true on
|
|
302
|
+
// B2tFSType.file and not folders, to see if the dna replay is good
|
|
303
|
+
// enough for folders, so we can concentrate on just files. Keep
|
|
304
|
+
// that in mind when I discuss the following notes.
|
|
305
|
+
//
|
|
306
|
+
// what we know at this point:
|
|
307
|
+
// * graft was invoked, so the sync engine detected divergence in
|
|
308
|
+
// the two spaces, i.e., our two branches (branch-per-space)
|
|
309
|
+
// * IOW, this is NOT a FF merge. That would have already been
|
|
310
|
+
// applied and not triggered this graft.
|
|
311
|
+
// * This is either a file or a folder b2tfs item.
|
|
312
|
+
// * If it is a folder...
|
|
313
|
+
// * How does git handle two folders merging, or does it?
|
|
314
|
+
// * git is file-based, and handles folders only secondarily.
|
|
315
|
+
// * How does our current vcs-gib diffing engine even detect if a
|
|
316
|
+
// folder has moved? does it?
|
|
317
|
+
// * If it is a file...
|
|
318
|
+
// * Is there anything that can happen besides the related binary file changing?
|
|
319
|
+
// * If there are multiple changes to the binary file, should we
|
|
320
|
+
// do each of those file changes in the graft?
|
|
321
|
+
// * we need to game out multiple scenarios to answer this.
|
|
322
|
+
// * What about multiple changes to each branch? Do we squash
|
|
323
|
+
// the orphan to a single change and then merge the final?
|
|
324
|
+
// * It is possible we can even parameterize this in this
|
|
325
|
+
// strategy object, but the caller would need to configure
|
|
326
|
+
// this strategy ahead of each sync call if that is the case I
|
|
327
|
+
// think.
|
|
328
|
+
// * One thing to parameterize would be how to handle graft
|
|
329
|
+
// points, as I just realized in the context of version
|
|
330
|
+
// control systems, it is possible that we may want to
|
|
331
|
+
// configure the sync/merge to drop/do something with large
|
|
332
|
+
// binaries (or just files in general) in a specific way.
|
|
333
|
+
|
|
334
|
+
// const dnaAddrsAlreadyAccountedFor: IbGibAddr[] = (latestCommonFrameIbGib?.rel8ns?.dna ?? []).concat();
|
|
335
|
+
// const dnaAddrsToApply: IbGibAddr[] = [];
|
|
336
|
+
// for (const orphanFrame of orphanBranch) {
|
|
337
|
+
// if (!orphanFrame.rel8ns) { throw new Error(`(UNEXPECTED) orphanFrame.rel8ns falsy? (E: bc9a78ef8dbcd9748305d898bf1b2826)`); }
|
|
338
|
+
// // I don't know if this is expected or not, but seems like if
|
|
339
|
+
// // we're doing a merge, we are expecting the ibgib frames to
|
|
340
|
+
// // have dna
|
|
341
|
+
// if (!orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0) {
|
|
342
|
+
// throw new Error(`(UNEXPECTED) !orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0? How can we be grafting when the orphan slice has no dna? (E: 7e58797aa2f98dfa811e8fa88c693826)`);
|
|
343
|
+
// }
|
|
344
|
+
// const orphanDnaAddrsToApply = getUniqueDnas({
|
|
345
|
+
// base: dnaAddrsAlreadyAccountedFor,
|
|
346
|
+
// extended: orphanFrame.rel8ns.dna,
|
|
347
|
+
// throwIfExtendedDoesntContainBase: true,
|
|
348
|
+
// });
|
|
349
|
+
// orphanDnaAddrsToApply.forEach(x => dnaAddrsAlreadyAccountedFor.push(x));
|
|
350
|
+
// orphanDnaAddrsToApply.forEach(x => dnaAddrsToApply.push(x));
|
|
351
|
+
// }
|
|
352
|
+
|
|
353
|
+
// const dnaIbGibsToApply = await getIbGibsFromCache_fallbackToSpaces({
|
|
354
|
+
// addrs: dnaAddrsToApply,
|
|
355
|
+
// readCache_graph: ibGibReadCache,
|
|
356
|
+
// space,
|
|
357
|
+
// });
|
|
358
|
+
|
|
359
|
+
// if (logalot) { console.log(`${lc}${mergeDiag} dnaAddrsToApply addrs (${dnaAddrsToApply.length}): ${dnaAddrsToApply} (I: 78a8a82f540d520682664aa806f1b826)`); }
|
|
360
|
+
|
|
361
|
+
// const createdIbGibs_Running: IbGib_V1[] = [];
|
|
362
|
+
// const newGraftedIntermediateIbGibs_ordered: IbGib_V1[] = [];
|
|
363
|
+
// const newGraftDnaIbGibs: IbGib_V1[] = [];
|
|
364
|
+
|
|
365
|
+
// let currentGraftTip = await applyTransforms({
|
|
366
|
+
// src: baseTip,
|
|
367
|
+
// dnaAddrsToApplyToStoreVersion_MUTATES_IN_PLACE: dnaAddrsToApply.concat(),
|
|
368
|
+
// allLocalIbGibs: dnaIbGibsToApply,
|
|
369
|
+
// createdIbGibs_Running,
|
|
370
|
+
// });
|
|
371
|
+
|
|
372
|
+
// if (createdIbGibs_Running.length > 0) {
|
|
373
|
+
// await putInSpace({ space, ibGibs: createdIbGibs_Running });
|
|
374
|
+
// const { mapWithTjp_YesDna: newGraftedIbGibsMap } = splitPerTjpAndOrDna({ ibGibs: createdIbGibs_Running });
|
|
375
|
+
// const newGraftedIbGibs_orderNotGuaranteed = Object.values(newGraftedIbGibsMap);
|
|
376
|
+
// const newGraftedIbGibsByTjp = getTimelinesGroupedByTjp({ ibGibs: newGraftedIbGibs_orderNotGuaranteed });
|
|
377
|
+
// if (Object.keys(newGraftedIbGibsByTjp).length > 0) {
|
|
378
|
+
// Object.values(newGraftedIbGibsByTjp)[0].forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
|
|
379
|
+
// for (const item of newGraftedIntermediateIbGibs_ordered) {
|
|
380
|
+
// await registerNewIbGib({ ibGib: item, space });
|
|
381
|
+
// }
|
|
382
|
+
// }
|
|
383
|
+
// }
|
|
384
|
+
|
|
385
|
+
// 4. Perform 3-way filesystem tree merge across lcaItem, baseItem, orphanItem
|
|
386
|
+
const lcaNode = await this.fetchIbGib({ addr: latestCommonFrameAddr, space, readCache_graph: ibGibReadCache });
|
|
387
|
+
if (!lcaNode) { throw new Error(`(UNEXPECTED) lcaNode falsy? (E: a8b2d80dc4f8ba1448fa280d89dfb626)`); }
|
|
388
|
+
const lcaItem = await this.resolveRootItemNode({ nodeOrAddr: lcaNode, space, readCache_graph: ibGibReadCache });
|
|
389
|
+
if (!lcaItem) { throw new Error(`(UNEXPECTED) lcaItem falsy? (E: 0944f88dde58cbabf82342b814955826)`); }
|
|
390
|
+
const baseItem = await this.resolveRootItemNode({ nodeOrAddr: baseTip, space, readCache_graph: ibGibReadCache });
|
|
391
|
+
if (!baseItem) { throw new Error(`(UNEXPECTED) baseItem falsy? (E: fac3087884cbebc7083e580514002826)`); }
|
|
392
|
+
const orphanItem = await this.resolveRootItemNode({ nodeOrAddr: orphanTip, space, readCache_graph: ibGibReadCache });
|
|
393
|
+
if (!orphanItem) { throw new Error(`(UNEXPECTED) orphanItem falsy? (E: 8e7e383753a8814f283280ee82156826)`); }
|
|
394
|
+
|
|
395
|
+
if (lcaItem.data.fsType !== baseItem.data.fsType) { throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== baseItem.data.fsType? (E: 794608f3e678a399ed670388629a6826)`); }
|
|
396
|
+
if (lcaItem.data.fsType !== orphanItem.data.fsType) { throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== orphanItem.data.fsType? (E: 2813981c8c422b41f85a02fd8aa88226)`); }
|
|
397
|
+
// all three fsTypes are equal
|
|
398
|
+
|
|
399
|
+
const fsType = lcaItem.data.fsType;
|
|
400
|
+
if (fsType === B2tFSType.folder) {
|
|
401
|
+
throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder? I have tweaked the canGraft so we should only be handling files atow (08/11/2026) (E: b282b8f77b18575378edb902bd80a826)`);
|
|
267
402
|
}
|
|
268
403
|
|
|
269
|
-
|
|
270
|
-
addrs: dnaAddrsToApply,
|
|
271
|
-
readCache_graph: ibGibReadCache,
|
|
272
|
-
space,
|
|
273
|
-
});
|
|
404
|
+
if (fsType !== B2tFSType.file) { throw new Error(`(UNEXPECTED) fsType (${fsType}) is not a file? (E: 272418fe2067ea3e16dac028e86d1a26)`); }
|
|
274
405
|
|
|
275
|
-
const createdIbGibs_Running: IbGib_V1[] = [];
|
|
276
|
-
const newGraftedIntermediateIbGibs_ordered: IbGib_V1[] = [];
|
|
277
|
-
const newGraftDnaIbGibs: IbGib_V1[] = [];
|
|
278
406
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
407
|
+
const lcaPayload = await this.getFilePayloadBuffer({
|
|
408
|
+
fileItem: lcaItem, space, readCache_graph: ibGibReadCache
|
|
409
|
+
});
|
|
410
|
+
if (lcaPayload === undefined) {
|
|
411
|
+
if (logalot) { console.log(`${lc}${mergeDiag} lcaPayload undefined? (I: 59b25835cce856cea883cf989ceb3826)`); }
|
|
412
|
+
}
|
|
413
|
+
const basePayload = await this.getFilePayloadBuffer({
|
|
414
|
+
fileItem: baseItem, space, readCache_graph: ibGibReadCache
|
|
415
|
+
});
|
|
416
|
+
if (basePayload === undefined) {
|
|
417
|
+
if (logalot) { console.log(`${lc}${mergeDiag} basePayload undefined? (I: 54f05406dca85eb98821b79f7325c826)`); }
|
|
418
|
+
}
|
|
419
|
+
const orphanPayload = await this.getFilePayloadBuffer({
|
|
420
|
+
fileItem: orphanItem, space, readCache_graph: ibGibReadCache
|
|
284
421
|
});
|
|
422
|
+
if (orphanPayload === undefined) {
|
|
423
|
+
if (logalot) { console.log(`${lc}${mergeDiag} orphanPayload undefined? (I: cd8b785875b43fc6684c65d818edd826)`); }
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const isBaseBin = basePayload ? isBinaryBuffer(basePayload.buffer) : false;
|
|
427
|
+
const isOrphanBin = orphanPayload ? isBinaryBuffer(orphanPayload.buffer) : false;
|
|
428
|
+
const isLcaBin = lcaPayload ? isBinaryBuffer(lcaPayload.buffer) : false;
|
|
285
429
|
|
|
286
|
-
if (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const newGraftedIbGibs_orderNotGuaranteed = Object.values(newGraftedIbGibsMap);
|
|
290
|
-
const newGraftedIbGibsByTjp = getTimelinesGroupedByTjp({ ibGibs: newGraftedIbGibs_orderNotGuaranteed });
|
|
291
|
-
if (Object.keys(newGraftedIbGibsByTjp).length > 0) {
|
|
292
|
-
Object.values(newGraftedIbGibsByTjp)[0].forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
|
|
293
|
-
for (const item of newGraftedIntermediateIbGibs_ordered) {
|
|
294
|
-
await registerNewIbGib({ ibGib: item, space });
|
|
295
|
-
}
|
|
430
|
+
if (isBaseBin || isOrphanBin || isLcaBin) {
|
|
431
|
+
if (logalot) {
|
|
432
|
+
console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
|
|
296
433
|
}
|
|
434
|
+
|
|
435
|
+
// even though we've gotten this far into this `graft` method,
|
|
436
|
+
// we can still return `undefined` early if we decide we can't
|
|
437
|
+
// handle it and we haven't persisted/registered any ibgibs. In
|
|
438
|
+
// this particular case of 3-way text merges, we don't graft
|
|
439
|
+
// non-text binary divergences, e.g., pics, sound files, etc.
|
|
440
|
+
|
|
441
|
+
return undefined; /* <<<< returns early */
|
|
297
442
|
}
|
|
298
443
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const
|
|
444
|
+
if (!lcaPayload) { throw new Error(`(UNEXPECTED) lcaPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 0b82892204482f5538a430b8915b7826)`); }
|
|
445
|
+
if (!basePayload) { throw new Error(`(UNEXPECTED) basePayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: af1f68a020280b3a5d6ed4a812acd426)`); }
|
|
446
|
+
if (!orphanPayload) { throw new Error(`(UNEXPECTED) orphanPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 6a521b684763862c3a2e0ca315d62826)`); }
|
|
447
|
+
|
|
448
|
+
const textLCA = decodeToLines(lcaPayload.buffer).join('\n');
|
|
449
|
+
const textBase = decodeToLines(basePayload.buffer).join('\n');
|
|
450
|
+
const textOrphan = decodeToLines(orphanPayload.buffer).join('\n');
|
|
451
|
+
|
|
452
|
+
console.log(`${lc}${mergeDiag} file: ${baseItem.data.name}`);
|
|
453
|
+
console.log(`${lc}${mergeDiag} textLCA:\n${textLCA}`);
|
|
454
|
+
console.log(`${lc}${mergeDiag} textBase:\n${textBase}`);
|
|
455
|
+
console.log(`${lc}${mergeDiag} textOrphan:\n${textOrphan}`);
|
|
456
|
+
|
|
457
|
+
const { mergedText } = perform3WayTextLineMerge({ textLCA, textBase, textOrphan });
|
|
458
|
+
console.log(`${lc}${mergeDiag} mergedText:\n${mergedText}`);
|
|
304
459
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
orphanItem,
|
|
311
|
-
space,
|
|
312
|
-
readCache_graph: ibGibReadCache,
|
|
313
|
-
newGraftDnaIbGibs,
|
|
314
|
-
newGraftedIntermediateIbGibs_ordered,
|
|
315
|
-
});
|
|
460
|
+
const dataBuffer = Buffer.from(mergedText, 'utf8');
|
|
461
|
+
const fileHash = await hash({ s: mergedText });
|
|
462
|
+
|
|
463
|
+
if (baseItem.data.fileExt !== orphanItem.data.fileExt) {
|
|
464
|
+
console.warn(`${lc} baseItem.data.fileExt (${baseItem.data.fileExt}) !== orphanItem.data.fileExt (${orphanItem.data.fileExt})? Using baseItem.data.fileExt for merged fileExt (W: a999b54235bb231fa49224842e212326)`);
|
|
316
465
|
}
|
|
317
466
|
|
|
467
|
+
const fileExt = baseItem.data.fileExt;
|
|
468
|
+
const binIb = getBinIb({
|
|
469
|
+
binHash: fileHash,
|
|
470
|
+
binExt: fileExt,
|
|
471
|
+
binEncoding: 'utf8',
|
|
472
|
+
});
|
|
473
|
+
const binIbGib: BinIbGib_V1 = {
|
|
474
|
+
ib: binIb,
|
|
475
|
+
data: dataBuffer,
|
|
476
|
+
};
|
|
477
|
+
binIbGib.gib = await getGib({ ibGib: binIbGib, hasTjp: false });
|
|
478
|
+
|
|
479
|
+
const binAddr = getIbGibAddr({ ibGib: binIbGib });
|
|
480
|
+
|
|
481
|
+
// at this point, we are committed to performing the 3-way merge.
|
|
482
|
+
await putInSpace({ ibGib: binIbGib, space });
|
|
483
|
+
await registerNewIbGib({ ibGib: binIbGib, space });
|
|
484
|
+
|
|
318
485
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (currentGraftTip.ib?.startsWith('b2tfs_branch') || currentGraftTip.data?.classname === 'B2tFSBranchIbGib_V1') {
|
|
325
|
-
if (mergedRootAddr !== currentRootAddr) {
|
|
326
|
-
const resRel8Branch = await rel8({
|
|
327
|
-
src: currentGraftTip,
|
|
328
|
-
rel8nsToAddByAddr: {
|
|
329
|
-
b2tfs_item: [mergedRootAddr],
|
|
330
|
-
},
|
|
331
|
-
dna: true,
|
|
332
|
-
nCounter: true,
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
const newGraftTip = await this.applyTransformAndRegister({
|
|
336
|
-
resTransform: resRel8Branch,
|
|
337
|
-
space,
|
|
338
|
-
newGraftDnaIbGibs,
|
|
339
|
-
newGraftedIntermediateIbGibs_ordered,
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
currentGraftTip = newGraftTip;
|
|
343
|
-
}
|
|
344
|
-
} else if (currentGraftTip.ib?.startsWith('b2tfs_item') || currentGraftTip.data?.classname === 'B2tFSItemIbGib_V1') {
|
|
345
|
-
if (mergedRootAddr !== getIbGibAddr({ ibGib: currentGraftTip })) {
|
|
346
|
-
currentGraftTip = mergedRootItem;
|
|
347
|
-
}
|
|
486
|
+
const fnGetN: (item: B2tFSItemIbGib_V1) => number = (item: B2tFSItemIbGib_V1) => {
|
|
487
|
+
if (item.data.n || item.data.n === 0) {
|
|
488
|
+
return item.data.n!;
|
|
489
|
+
} else {
|
|
490
|
+
throw new Error(`(UNEXPECTED) item.data.n not a number? (E: 896ceae089c83ca67817fff826be5826)`);
|
|
348
491
|
}
|
|
349
492
|
}
|
|
493
|
+
const baseItemDataN = fnGetN(baseItem);
|
|
494
|
+
const orphanItemDataN = fnGetN(orphanItem);
|
|
495
|
+
const lowestDataN = baseItemDataN <= orphanItemDataN ?
|
|
496
|
+
baseItemDataN :
|
|
497
|
+
orphanItemDataN;
|
|
498
|
+
|
|
499
|
+
const evolveRes = await evolveB2tFSItemIbGib({
|
|
500
|
+
existingItem: baseItem,
|
|
501
|
+
dataToUpdate: {
|
|
502
|
+
fileHash,
|
|
503
|
+
n: lowestDataN + 1,
|
|
504
|
+
},
|
|
505
|
+
rel8nsToUpdate: {
|
|
506
|
+
[BINARY_REL8N_NAME]: [binAddr],
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// sanity checks
|
|
511
|
+
if (!evolveRes.dnas) { throw new Error(`(UNEXPECTED) evolveRes.dnas falsy? We should be using dna when working with B2tFS items. (E: e640e892cc76c77f98f3881301035826)`); }
|
|
512
|
+
if (!evolveRes.newIbGib) { throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? we just did the merge, so this should be truthy. (E: 9e488d07772827b66a2aff4801905426)`); }
|
|
513
|
+
const newItemWithNewBinPayload = evolveRes.newIbGib as B2tFSItemIbGib_V1;
|
|
514
|
+
const newItemAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
|
|
515
|
+
if (logalot) { console.log(`${lc} newItemAddr: ${newItemAddr} (I: d23eef651b88be1248ee29ca179eff26)`); }
|
|
516
|
+
|
|
517
|
+
const newGraftDnaIbGibs: IbGib_V1[] = [];
|
|
518
|
+
const newGraftedIntermediateIbGibs_ordered: IbGib_V1[] = [];
|
|
519
|
+
|
|
520
|
+
newGraftDnaIbGibs.push(...evolveRes.dnas);
|
|
521
|
+
if (evolveRes.intermediateIbGibs) {
|
|
522
|
+
// todo: when we have this completed, we should know whether or not there are intermediate ibgibs in all cases, some cases, or no cases (never). we should change this from an `if` block with no else to throw an unexpected error (assertion) if it is indeed unexpected
|
|
523
|
+
evolveRes.intermediateIbGibs.forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
await persistTransformResult({ resTransform: evolveRes, space });
|
|
527
|
+
await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
|
|
528
|
+
|
|
529
|
+
const baseItemAddr = getIbGibAddr({ ibGib: baseItem });
|
|
530
|
+
const mergedRootAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
|
|
531
|
+
const currentRootAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* stupid word "details" is plural and I have this set to be an
|
|
535
|
+
* array. don't have the ability to refactor right now, so this will
|
|
536
|
+
* be mildly confusing unfortunately. Agents should not try to just
|
|
537
|
+
* refactor this on the fly.
|
|
538
|
+
*/
|
|
539
|
+
const b2tfsAddlGraftDetails: B2tFS3WayAddlGraftDetails = {
|
|
540
|
+
baseTextB2tFSItemAddr: baseTipAddr,
|
|
541
|
+
baseTextBinAddr: basePayload.binIbGib ? getIbGibAddr({ ibGib: basePayload.binIbGib }) : undefined,
|
|
542
|
+
orphanTextB2tFSItemAddr: orphanTipAddr,
|
|
543
|
+
orphanTextBinAddr: orphanPayload.binIbGib ? getIbGibAddr({ ibGib: orphanPayload.binIbGib }) : undefined,
|
|
544
|
+
}
|
|
350
545
|
|
|
351
546
|
// 6. Attach GraftInfo frame
|
|
352
547
|
const graftInfo = await createGraftInfo({
|
|
353
548
|
conflictStrategy,
|
|
354
|
-
details: `
|
|
355
|
-
addlGraftDetails:
|
|
549
|
+
details: `Merged orphan tip text with the baseTip as a starting point.`,
|
|
550
|
+
addlGraftDetails: [b2tfsAddlGraftDetails],
|
|
356
551
|
latestCommonFrameAddr,
|
|
357
552
|
baseAddrsSinceLCA: baseBranchAddrs,
|
|
358
553
|
orphanAddrsSinceLCA: orphanBranchAddrs,
|
|
359
|
-
dnaAddrsApplied:
|
|
554
|
+
dnaAddrsApplied: [],
|
|
360
555
|
});
|
|
361
556
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
557
|
+
await putInSpace({ ibGib: graftInfo, space });
|
|
558
|
+
await registerNewIbGib({ ibGib: graftInfo, space });
|
|
365
559
|
const graftInfoAddr = getIbGibAddr({ ibGib: graftInfo });
|
|
560
|
+
|
|
366
561
|
const resRel8GraftInfo = await rel8({
|
|
367
|
-
src:
|
|
562
|
+
src: newItemWithNewBinPayload,
|
|
368
563
|
rel8nsToAddByAddr: {
|
|
369
564
|
[GRAFT_INFO_REL8N_NAME]: [graftInfoAddr],
|
|
370
565
|
},
|
|
371
566
|
dna: true,
|
|
372
|
-
nCounter:
|
|
567
|
+
nCounter: true,
|
|
373
568
|
});
|
|
569
|
+
if (!resRel8GraftInfo.dnas) { throw new Error(`(UNEXPECTED) resRel8GraftInfo.dnas falsy? (E: f3f4a83d3a08bd8de84250c389aed826)`); }
|
|
570
|
+
const finalGraftTip = resRel8GraftInfo.newIbGib;
|
|
571
|
+
const finalGraftTipAddr = getIbGibAddr({ ibGib: finalGraftTip });
|
|
572
|
+
if (logalot) { console.log(`${lc} finalGraftTipAddr: ${finalGraftTipAddr} (I: 583ac81fb0a84827b85c3076ffeeaf26)`); }
|
|
374
573
|
|
|
375
|
-
|
|
574
|
+
newGraftedIntermediateIbGibs_ordered.push(newItemWithNewBinPayload);
|
|
575
|
+
|
|
576
|
+
for (const dna of resRel8GraftInfo.dnas) {
|
|
376
577
|
newGraftDnaIbGibs.push(dna);
|
|
377
578
|
}
|
|
378
|
-
if (space) {
|
|
379
|
-
await persistTransformResult({ resTransform: resRel8GraftInfo, space });
|
|
380
|
-
await registerNewIbGib({ ibGib: resRel8GraftInfo.newIbGib, space });
|
|
381
|
-
}
|
|
382
579
|
|
|
383
|
-
|
|
580
|
+
await persistTransformResult({ resTransform: resRel8GraftInfo, space });
|
|
581
|
+
await registerNewIbGib({ ibGib: finalGraftTip, space });
|
|
384
582
|
|
|
385
583
|
return {
|
|
386
|
-
dnasReplayed:
|
|
584
|
+
dnasReplayed: [],
|
|
387
585
|
dnasCreatedInGraft: newGraftDnaIbGibs,
|
|
388
586
|
intermediateIbGibsCreatedInGraft: newGraftedIntermediateIbGibs_ordered,
|
|
587
|
+
ancillaryIbGibsCreated: [binIbGib],
|
|
389
588
|
newGraftTip: finalGraftTip,
|
|
390
589
|
graftInfoCreated: graftInfo,
|
|
391
590
|
};
|
|
@@ -405,7 +604,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
405
604
|
readCache_graph,
|
|
406
605
|
}: {
|
|
407
606
|
addr?: string;
|
|
408
|
-
space
|
|
607
|
+
space: IbGibSpaceAny;
|
|
409
608
|
readCache_graph?: FlatIbGibGraph;
|
|
410
609
|
}): Promise<IbGib_V1 | undefined> {
|
|
411
610
|
if (!addr) { return undefined; }
|
|
@@ -416,7 +615,6 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
416
615
|
const matchingKey = Object.keys(readCache_graph).find(k => k === cleanAddr || k.startsWith(cleanAddr + '^') || (k.includes('^') && k.split('^')[0] === cleanAddr));
|
|
417
616
|
if (matchingKey) { return readCache_graph[matchingKey]; }
|
|
418
617
|
}
|
|
419
|
-
if (!space) { return undefined; }
|
|
420
618
|
try {
|
|
421
619
|
const res = await getFromSpace({ space, addrs: [addr, cleanAddr] });
|
|
422
620
|
if (res && res.success && res.ibGibs && res.ibGibs.length > 0) {
|
|
@@ -425,6 +623,8 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
425
623
|
}
|
|
426
624
|
} catch {
|
|
427
625
|
// Suppress fetch error if address not found
|
|
626
|
+
// why suppress? any ibgibs available to us here should be in space
|
|
627
|
+
// (the temp space of the sync receiver)
|
|
428
628
|
}
|
|
429
629
|
return undefined;
|
|
430
630
|
}
|
|
@@ -436,32 +636,26 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
436
636
|
readCache_graph,
|
|
437
637
|
}: {
|
|
438
638
|
nodeOrAddr: IbGib_V1 | string | undefined;
|
|
439
|
-
space
|
|
639
|
+
space: IbGibSpaceAny;
|
|
440
640
|
readCache_graph?: FlatIbGibGraph;
|
|
441
641
|
}): Promise<B2tFSItemIbGib_V1 | undefined> {
|
|
442
|
-
if (!nodeOrAddr) {
|
|
642
|
+
if (!nodeOrAddr) { throw new Error(`(UNEXPECTED) nodeOrAddr falsy? (E: 524108327b9caa00586207ea399f7226)`); }
|
|
643
|
+
|
|
443
644
|
let node: IbGib_V1 | undefined;
|
|
444
645
|
if (typeof nodeOrAddr === 'string') {
|
|
445
646
|
node = await this.fetchIbGib({ addr: nodeOrAddr, space, readCache_graph });
|
|
446
647
|
} else {
|
|
447
648
|
node = nodeOrAddr;
|
|
448
649
|
}
|
|
449
|
-
if (!node) {
|
|
450
|
-
|
|
451
|
-
if (node.ib?.startsWith('b2tfs_branch') || node.data?.classname === 'B2tFSBranchIbGib_V1') {
|
|
452
|
-
const rootItemAddr = node.rel8ns?.b2tfs_item?.at(-1);
|
|
453
|
-
if (rootItemAddr) {
|
|
454
|
-
const rootNode = await this.fetchIbGib({ addr: rootItemAddr, space, readCache_graph });
|
|
455
|
-
return rootNode as B2tFSItemIbGib_V1;
|
|
456
|
-
}
|
|
457
|
-
return undefined;
|
|
458
|
-
}
|
|
650
|
+
if (!node) { throw new Error(`(UNEXPECTED) node falsy? couldn't get node? (E: bd7d1c3b4a3881ff882746281869d826)`); }
|
|
459
651
|
|
|
460
|
-
if (
|
|
461
|
-
|
|
652
|
+
if (isB2tFSItemIbGib(node)) {
|
|
653
|
+
// it's an item ibgib
|
|
654
|
+
return node;
|
|
655
|
+
} else {
|
|
656
|
+
// not an item ibgib
|
|
657
|
+
throw new Error(`(UNEXPECTED) node is not a B2tFSItemIbGib_V1? canGraft should have returned false then and we should never have gotten here. (E: ddabb281ccb2fb1a181109a82046b826)`);
|
|
462
658
|
}
|
|
463
|
-
|
|
464
|
-
return undefined;
|
|
465
659
|
}
|
|
466
660
|
|
|
467
661
|
private async getFilePayloadBuffer({
|
|
@@ -470,7 +664,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
470
664
|
readCache_graph,
|
|
471
665
|
}: {
|
|
472
666
|
fileItem?: B2tFSItemIbGib_V1;
|
|
473
|
-
space
|
|
667
|
+
space: IbGibSpaceAny;
|
|
474
668
|
readCache_graph?: FlatIbGibGraph;
|
|
475
669
|
}): Promise<{ buffer: Uint8Array; binIbGib?: IbGib_V1 } | undefined> {
|
|
476
670
|
if (!fileItem || !fileItem.rel8ns) { return undefined; }
|
|
@@ -479,7 +673,8 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
479
673
|
if (!latestBinAddr) { return undefined; }
|
|
480
674
|
|
|
481
675
|
const binIbGib = await this.fetchIbGib({ addr: latestBinAddr, space, readCache_graph });
|
|
482
|
-
if (!binIbGib
|
|
676
|
+
if (!binIbGib) { throw new Error(`(UNEXPECTED) couldn't fetch binIbGib? latestBinAddr: ${latestBinAddr}. space.ib: ${space.ib} (E: 3d1238b3a348924038a79f88264d8226)`); }
|
|
677
|
+
if (binIbGib.data === undefined) { return undefined; } // what if it's an empty file. will data be undefined? do we handle this at the b2tfs item level for fsType === 'file'?
|
|
483
678
|
|
|
484
679
|
let fileData: Uint8Array;
|
|
485
680
|
const dataObj = binIbGib.data as any;
|
|
@@ -512,7 +707,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
512
707
|
readCache_graph,
|
|
513
708
|
}: {
|
|
514
709
|
folderItem?: B2tFSItemIbGib_V1;
|
|
515
|
-
space
|
|
710
|
+
space: IbGibSpaceAny;
|
|
516
711
|
readCache_graph?: FlatIbGibGraph;
|
|
517
712
|
}): Promise<Map<string, B2tFSItemIbGib_V1>> {
|
|
518
713
|
const map = new Map<string, B2tFSItemIbGib_V1>();
|
|
@@ -539,7 +734,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
539
734
|
lcaItem?: B2tFSItemIbGib_V1;
|
|
540
735
|
baseItem?: B2tFSItemIbGib_V1;
|
|
541
736
|
orphanItem?: B2tFSItemIbGib_V1;
|
|
542
|
-
space
|
|
737
|
+
space: IbGibSpaceAny;
|
|
543
738
|
readCache_graph?: FlatIbGibGraph;
|
|
544
739
|
newGraftDnaIbGibs: IbGib_V1[];
|
|
545
740
|
newGraftedIntermediateIbGibs_ordered: IbGib_V1[];
|
|
@@ -588,134 +783,66 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
588
783
|
const fsType = baseItem.data?.fsType || orphanItem.data?.fsType;
|
|
589
784
|
|
|
590
785
|
if (fsType === 'file') {
|
|
591
|
-
const lcaPayload = await this.getFilePayloadBuffer({ fileItem: lcaItem, space, readCache_graph });
|
|
592
|
-
const basePayload = await this.getFilePayloadBuffer({ fileItem: baseItem, space, readCache_graph });
|
|
593
|
-
const orphanPayload = await this.getFilePayloadBuffer({ fileItem: orphanItem, space, readCache_graph });
|
|
594
|
-
|
|
595
|
-
const isBaseBin = basePayload ? isBinaryBuffer(basePayload.buffer) : false;
|
|
596
|
-
const isOrphanBin = orphanPayload ? isBinaryBuffer(orphanPayload.buffer) : false;
|
|
597
|
-
const isLcaBin = lcaPayload ? isBinaryBuffer(lcaPayload.buffer) : false;
|
|
598
|
-
|
|
599
|
-
if (isBaseBin || isOrphanBin || isLcaBin) {
|
|
600
|
-
if (logalot) {
|
|
601
|
-
console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
|
|
602
|
-
}
|
|
603
|
-
return baseItem;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
const textLCA = lcaPayload ? decodeToLines(lcaPayload.buffer).join('\n') : '';
|
|
607
|
-
const textBase = basePayload ? decodeToLines(basePayload.buffer).join('\n') : '';
|
|
608
|
-
const textOrphan = orphanPayload ? decodeToLines(orphanPayload.buffer).join('\n') : '';
|
|
609
|
-
|
|
610
|
-
console.log(`${lc} [MERGE DIAGNOSTIC] file: ${baseItem.data?.name}`);
|
|
611
|
-
console.log(`${lc} [MERGE DIAGNOSTIC] textLCA:\n${textLCA}`);
|
|
612
|
-
console.log(`${lc} [MERGE DIAGNOSTIC] textBase:\n${textBase}`);
|
|
613
|
-
console.log(`${lc} [MERGE DIAGNOSTIC] textOrphan:\n${textOrphan}`);
|
|
614
|
-
|
|
615
|
-
const { mergedText } = perform3WayTextLineMerge({ textLCA, textBase, textOrphan });
|
|
616
|
-
console.log(`${lc} [MERGE DIAGNOSTIC] mergedText:\n${mergedText}`);
|
|
617
|
-
|
|
618
|
-
const dataBuffer = Buffer.from(mergedText, 'utf8');
|
|
619
|
-
const fileHash = await hash({ s: mergedText });
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const fileExt = baseItem.data?.fileExt || (baseItem.data?.name?.includes('.') ? baseItem.data.name.split('.').pop() || 'txt' : 'txt');
|
|
623
|
-
const binIb = getBinIb({
|
|
624
|
-
binHash: fileHash,
|
|
625
|
-
binExt: fileExt,
|
|
626
|
-
binEncoding: 'utf8',
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
const binIbGib: BinIbGib_V1 = {
|
|
630
|
-
ib: binIb,
|
|
631
|
-
data: dataBuffer,
|
|
632
|
-
};
|
|
633
|
-
binIbGib.gib = await getGib({ ibGib: binIbGib, hasTjp: false });
|
|
634
|
-
|
|
635
|
-
const binAddr = getIbGibAddr({ ibGib: binIbGib });
|
|
636
|
-
if (space) {
|
|
637
|
-
await putInSpace({ ibGib: binIbGib, space });
|
|
638
|
-
await registerNewIbGib({ ibGib: binIbGib, space });
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const evolveRes = await evolveB2tFSItemIbGib({
|
|
642
|
-
existingItem: baseItem,
|
|
643
|
-
dataToUpdate: {
|
|
644
|
-
fileHash,
|
|
645
|
-
},
|
|
646
|
-
rel8nsToUpdate: {
|
|
647
|
-
[BINARY_REL8N_NAME]: [binAddr],
|
|
648
|
-
},
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
if (evolveRes.dnas) { newGraftDnaIbGibs.push(...evolveRes.dnas); }
|
|
652
|
-
if (evolveRes.newIbGib) { newGraftedIntermediateIbGibs_ordered.push(evolveRes.newIbGib); }
|
|
653
|
-
if (space) {
|
|
654
|
-
await persistTransformResult({ resTransform: evolveRes, space });
|
|
655
|
-
await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
return evolveRes.newIbGib as B2tFSItemIbGib_V1;
|
|
659
786
|
} else if (fsType === 'folder') {
|
|
660
|
-
const lcaChildrenMap = await this.getChildItemsMap({ folderItem: lcaItem, space, readCache_graph });
|
|
661
|
-
const baseChildrenMap = await this.getChildItemsMap({ folderItem: baseItem, space, readCache_graph });
|
|
662
|
-
const orphanChildrenMap = await this.getChildItemsMap({ folderItem: orphanItem, space, readCache_graph });
|
|
663
|
-
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
]);
|
|
669
|
-
|
|
670
|
-
const mergedChildAddrs: string[] = [];
|
|
671
|
-
|
|
672
|
-
for (const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
const currentChildAddrs = baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
|
|
694
|
-
const addrsChanged = mergedChildAddrs.length !== currentChildAddrs.length ||
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (!addrsChanged) {
|
|
698
|
-
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
const evolveRes = await evolveB2tFSItemIbGib({
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
if (evolveRes.dnas) { newGraftDnaIbGibs.push(...evolveRes.dnas); }
|
|
712
|
-
if (evolveRes.newIbGib) { newGraftedIntermediateIbGibs_ordered.push(evolveRes.newIbGib); }
|
|
713
|
-
if (space) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
return evolveRes.newIbGib as B2tFSItemIbGib_V1;
|
|
787
|
+
// const lcaChildrenMap = await this.getChildItemsMap({ folderItem: lcaItem, space, readCache_graph });
|
|
788
|
+
// const baseChildrenMap = await this.getChildItemsMap({ folderItem: baseItem, space, readCache_graph });
|
|
789
|
+
// const orphanChildrenMap = await this.getChildItemsMap({ folderItem: orphanItem, space, readCache_graph });
|
|
790
|
+
|
|
791
|
+
// const allChildAddrs = new Set([
|
|
792
|
+
// ...lcaChildrenMap.keys(),
|
|
793
|
+
// ...baseChildrenMap.keys(),
|
|
794
|
+
// ...orphanChildrenMap.keys(),
|
|
795
|
+
// ]);
|
|
796
|
+
|
|
797
|
+
// const mergedChildAddrs: string[] = [];
|
|
798
|
+
|
|
799
|
+
// for (const childItemAddr of allChildAddrs) {
|
|
800
|
+
// const childLCA = lcaChildrenMap.get(childItemAddr);
|
|
801
|
+
// const childBase = baseChildrenMap.get(childItemAddr);
|
|
802
|
+
// const childOrphan = orphanChildrenMap.get(childItemAddr);
|
|
803
|
+
|
|
804
|
+
// const mergedChild = await this.mergeTreeNodes({
|
|
805
|
+
// lcaItem: childLCA,
|
|
806
|
+
// baseItem: childBase,
|
|
807
|
+
// orphanItem: childOrphan,
|
|
808
|
+
// space,
|
|
809
|
+
// readCache_graph,
|
|
810
|
+
// newGraftDnaIbGibs,
|
|
811
|
+
// newGraftedIntermediateIbGibs_ordered,
|
|
812
|
+
// });
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
// if (mergedChild) {
|
|
816
|
+
// mergedChildAddrs.push(getIbGibAddr({ ibGib: mergedChild }));
|
|
817
|
+
// }
|
|
818
|
+
// }
|
|
819
|
+
|
|
820
|
+
// const currentChildAddrs = baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
|
|
821
|
+
// const addrsChanged = mergedChildAddrs.length !== currentChildAddrs.length ||
|
|
822
|
+
// mergedChildAddrs.some((addr, idx) => addr !== currentChildAddrs[idx]);
|
|
823
|
+
|
|
824
|
+
// if (!addrsChanged) {
|
|
825
|
+
// return baseItem;
|
|
826
|
+
// }
|
|
827
|
+
|
|
828
|
+
// const evolveRes = await evolveB2tFSItemIbGib({
|
|
829
|
+
// existingItem: baseItem,
|
|
830
|
+
// rel8nsToUpdate: {
|
|
831
|
+
// [B2TFS_CHILD_ITEM_REL8N_NAME]: mergedChildAddrs,
|
|
832
|
+
// },
|
|
833
|
+
// rel8nsToRemove: {
|
|
834
|
+
// [B2TFS_CHILD_ITEM_REL8N_NAME]: baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [],
|
|
835
|
+
// },
|
|
836
|
+
// });
|
|
837
|
+
|
|
838
|
+
// if (evolveRes.dnas) { newGraftDnaIbGibs.push(...evolveRes.dnas); }
|
|
839
|
+
// if (evolveRes.newIbGib) { newGraftedIntermediateIbGibs_ordered.push(evolveRes.newIbGib); }
|
|
840
|
+
// if (space) {
|
|
841
|
+
// await persistTransformResult({ resTransform: evolveRes, space });
|
|
842
|
+
// await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
|
|
843
|
+
// }
|
|
844
|
+
|
|
845
|
+
// return evolveRes.newIbGib as B2tFSItemIbGib_V1;
|
|
719
846
|
}
|
|
720
847
|
|
|
721
848
|
return baseItem;
|