@ibgib/vcs-gib 0.0.21 → 0.0.26
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/CHANGELOG.md +19 -0
- package/VCS_CLI_USER_GUIDE.md +94 -89
- package/dist/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/bootstrap/node-bootstrap.mjs +1 -1
- package/dist/cli/cli-arg-parser.d.mts +1 -0
- package/dist/cli/cli-arg-parser.d.mts.map +1 -1
- package/dist/cli/cli-arg-parser.mjs +5 -1
- package/dist/cli/cli-arg-parser.mjs.map +1 -1
- package/dist/cli/cli-constants.d.mts +6 -0
- package/dist/cli/cli-constants.d.mts.map +1 -1
- package/dist/cli/cli-constants.mjs +12 -0
- package/dist/cli/cli-constants.mjs.map +1 -1
- package/dist/cli/commands/add-cmd.d.mts.map +1 -1
- package/dist/cli/commands/add-cmd.mjs +5 -2
- package/dist/cli/commands/add-cmd.mjs.map +1 -1
- package/dist/cli/commands/commit-cmd.d.mts +5 -4
- package/dist/cli/commands/commit-cmd.d.mts.map +1 -1
- package/dist/cli/commands/commit-cmd.mjs +149 -33
- package/dist/cli/commands/commit-cmd.mjs.map +1 -1
- package/dist/cli/commands/generate-comment-cmd.d.mts +19 -0
- package/dist/cli/commands/generate-comment-cmd.d.mts.map +1 -0
- package/dist/cli/commands/generate-comment-cmd.mjs +140 -0
- package/dist/cli/commands/generate-comment-cmd.mjs.map +1 -0
- package/dist/cli/commands/log-cmd.d.mts +12 -3
- package/dist/cli/commands/log-cmd.d.mts.map +1 -1
- package/dist/cli/commands/log-cmd.mjs +236 -38
- package/dist/cli/commands/log-cmd.mjs.map +1 -1
- package/dist/cli/commands/merge-cmd.d.mts +21 -8
- package/dist/cli/commands/merge-cmd.d.mts.map +1 -1
- package/dist/cli/commands/merge-cmd.mjs +138 -70
- package/dist/cli/commands/merge-cmd.mjs.map +1 -1
- package/dist/cli/commands/status-cmd.d.mts +5 -6
- package/dist/cli/commands/status-cmd.d.mts.map +1 -1
- package/dist/cli/commands/status-cmd.mjs +50 -205
- package/dist/cli/commands/status-cmd.mjs.map +1 -1
- package/dist/cli/vcs-cli-main.d.mts.map +1 -1
- package/dist/cli/vcs-cli-main.mjs +27 -6
- package/dist/cli/vcs-cli-main.mjs.map +1 -1
- package/dist/engine/index/index-helper.d.mts.map +1 -1
- package/dist/engine/index/index-helper.mjs +3 -0
- package/dist/engine/index/index-helper.mjs.map +1 -1
- package/dist/engine/item/item-helper.d.mts +31 -1
- package/dist/engine/item/item-helper.d.mts.map +1 -1
- package/dist/engine/item/item-helper.mjs +44 -2
- package/dist/engine/item/item-helper.mjs.map +1 -1
- package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts +74 -0
- package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts.map +1 -0
- package/dist/engine/merge/{b2tfs-3way-merge-strategy.mjs → b2tfs-3way-graft-strategy.mjs} +133 -304
- package/dist/engine/merge/b2tfs-3way-graft-strategy.mjs.map +1 -0
- package/dist/engine/merge/{b2tfs-3way-merge-types.d.mts → b2tfs-3way-graft-types.d.mts} +2 -9
- package/dist/engine/merge/b2tfs-3way-graft-types.d.mts.map +1 -0
- package/dist/engine/merge/b2tfs-3way-graft-types.mjs +2 -0
- package/dist/engine/merge/b2tfs-3way-graft-types.mjs.map +1 -0
- package/dist/engine/status/status-helper.d.mts +89 -0
- package/dist/engine/status/status-helper.d.mts.map +1 -0
- package/dist/engine/status/status-helper.mjs +285 -0
- package/dist/engine/status/status-helper.mjs.map +1 -0
- package/dist/test/test-helpers.d.mts +51 -0
- package/dist/test/test-helpers.d.mts.map +1 -0
- package/dist/test/test-helpers.mjs +135 -0
- package/dist/test/test-helpers.mjs.map +1 -0
- package/package.json +4 -4
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/bootstrap/node-bootstrap.mts +1 -1
- package/src/cli/cli-arg-parser.mts +5 -0
- package/src/cli/cli-constants.mts +13 -0
- package/src/cli/commands/add-cmd.mts +5 -2
- package/src/cli/commands/branch-checkout-cmd.respec.log +8 -101
- package/src/cli/commands/branch-checkout-cmd.respec.mts +11 -10
- package/src/cli/commands/commit-cmd.mts +165 -42
- package/src/cli/commands/commit-log-cmd.respec.mts +216 -3
- package/src/cli/commands/generate-comment-cmd.mts +171 -0
- package/src/cli/commands/log-cmd.mts +288 -41
- package/src/cli/commands/merge-cmd.mts +154 -76
- package/src/cli/commands/status-cmd.mts +57 -256
- package/src/cli/vcs-cli-main.mts +28 -7
- package/src/engine/index/index-helper.mts +3 -0
- package/src/engine/item/item-helper.mts +76 -3
- package/src/engine/merge/{b2tfs-3way-merge-strategy.mts → b2tfs-3way-graft-strategy.mts} +152 -374
- package/src/engine/merge/{b2tfs-3way-merge-strategy.respec.mts → b2tfs-3way-graft-strategy.respec.mts} +27 -122
- package/src/engine/merge/{b2tfs-3way-merge-types.mts → b2tfs-3way-graft-types.mts} +34 -42
- package/src/engine/merge/b2tfs-sync-comments.respec.mts +399 -0
- package/src/engine/status/status-helper.mts +380 -0
- package/src/test/test-helpers.mts +168 -0
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts +0 -48
- package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts.map +0 -1
- package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs.map +0 -1
- package/dist/engine/merge/b2tfs-3way-merge-types.d.mts.map +0 -1
- package/dist/engine/merge/b2tfs-3way-merge-types.mjs +0 -2
- package/dist/engine/merge/b2tfs-3way-merge-types.mjs.map +0 -1
|
@@ -1,42 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @module b2tfs-3way-
|
|
2
|
+
* @module b2tfs-3way-graft-strategy
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* ⚠️ CRITICAL GRAFT STRATEGY GUIDANCE WARNING ⚠️
|
|
6
|
+
* BEFORE MAKING ANY CHANGES TO THIS FILE, YOU MUST CONSULT AND CAREFULLY READ:
|
|
7
|
+
* libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md
|
|
8
|
+
*
|
|
9
|
+
* Graft strategies must strictly fulfill the `GraftTimelinesResult` contract,
|
|
10
|
+
* ensure timeline `n` monotonicity (using Math.max over base/orphan branch frames),
|
|
11
|
+
* and include ALL newly referenced ancillary dependency nodes (comments, binary
|
|
12
|
+
* stones, DNAs) in `ancillaryIbGibsCreated` so that the destination branch
|
|
13
|
+
* space is completely self-contained.
|
|
14
|
+
* ============================================================================
|
|
15
|
+
*
|
|
16
|
+
* 3-way text line diff graft strategy for B2tFS file item timelines.
|
|
17
|
+
* Reconciles diverging file content via 3-way line diff (LCA, Base, Orphan)
|
|
18
|
+
* and inserts Git conflict markers when line edits collide.
|
|
19
|
+
*
|
|
20
|
+
* Non-text binaries and non-file items return early / false in `canGraft` and
|
|
21
|
+
* fall through to `DefaultDnaReplayGraftStrategy`.
|
|
22
|
+
* Folder hierarchies are re-synchronized post-merge via `reifyB2tFSHierarchy`.
|
|
5
23
|
*/
|
|
6
24
|
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import { extractErrorMsg, hash, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
25
|
+
import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
10
26
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
11
27
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
12
|
-
import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
28
|
+
import { getGib, isDna } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
|
|
13
29
|
import { rel8 } from '@ibgib/ts-gib/dist/V1/transforms/rel8.mjs';
|
|
14
|
-
import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
|
|
15
30
|
|
|
16
31
|
import { GraftMergeStrategyBase_V1 } from '@ibgib/core-gib/dist/sync/graft-info/graft-merge-strategy-base-v1.mjs';
|
|
17
|
-
import { GraftContext,
|
|
32
|
+
import { GraftContext, GraftStrategy, GraftTimelinesResult } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-types.mjs';
|
|
18
33
|
import { FlatIbGibGraph } from '@ibgib/core-gib/dist/common/other/graph-types.mjs';
|
|
19
|
-
|
|
20
|
-
|
|
21
34
|
import { getFromSpace, persistTransformResult, registerNewIbGib, putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
|
|
22
|
-
import { getBinIb, getIbGibsFromCache_fallbackToSpaces,
|
|
23
|
-
|
|
24
|
-
import { applyTransforms, getUniqueDnas } from '@ibgib/core-gib/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs';
|
|
35
|
+
import { getBinIb, getIbGibsFromCache_fallbackToSpaces, splitPerTjpAndOrDna, getTimelinesGroupedByTjp } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
|
|
36
|
+
import { getDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
|
|
25
37
|
import { createGraftInfo } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-helpers.mjs';
|
|
26
38
|
import { GRAFT_INFO_REL8N_NAME } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-constants.mjs';
|
|
27
39
|
import { BinIbGib_V1 } from '@ibgib/core-gib/dist/common/bin/bin-types.mjs';
|
|
28
40
|
import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
|
|
41
|
+
import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
|
|
29
42
|
|
|
30
43
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
31
44
|
import { isBinaryBuffer, decodeToLines, computeLineLcsDiff } from '../diff/line-diff-helper.mjs';
|
|
32
|
-
import { B2tFSItemIbGib_V1,
|
|
45
|
+
import { B2tFSItemIbGib_V1, BINARY_REL8N_NAME, B2tFSType } from '../item/item-types.mjs';
|
|
33
46
|
import { evolveB2tFSItemIbGib, isB2tFSItemIbGib } from '../item/item-helper.mjs';
|
|
34
|
-
import {
|
|
35
|
-
import { B2TFS_ITEM_ATOM } from '../item/item-atom-helper.mjs';
|
|
36
|
-
import { B2tFS3WayAddlGraftDetails } from './b2tfs-3way-merge-types.mjs';
|
|
47
|
+
import { B2tFS3WayAddlGraftDetails } from './b2tfs-3way-graft-types.mjs';
|
|
37
48
|
|
|
38
|
-
const lcFile = `[b2tfs-3way-
|
|
39
|
-
const logalot = GLOBAL_LOG_A_LOT
|
|
49
|
+
const lcFile = `[b2tfs-3way-graft-strategy]`;
|
|
50
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
40
51
|
const mergeDiag = `[MERGE DIAGNOSTIC]`;
|
|
41
52
|
|
|
42
53
|
/**
|
|
@@ -61,9 +72,6 @@ export function perform3WayTextLineMerge({
|
|
|
61
72
|
textBase: string;
|
|
62
73
|
textOrphan: string;
|
|
63
74
|
}): Text3WayMergeResult {
|
|
64
|
-
console.log(`[DEBUG 3WAY] textLCA: ${JSON.stringify(textLCA)}`);
|
|
65
|
-
console.log(`[DEBUG 3WAY] textBase: ${JSON.stringify(textBase)}`);
|
|
66
|
-
console.log(`[DEBUG 3WAY] textOrphan: ${JSON.stringify(textOrphan)}`);
|
|
67
75
|
if (textBase === textOrphan) {
|
|
68
76
|
return { mergedText: textBase, hasConflict: false };
|
|
69
77
|
}
|
|
@@ -74,7 +82,6 @@ export function perform3WayTextLineMerge({
|
|
|
74
82
|
return { mergedText: textBase, hasConflict: false };
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
|
|
78
85
|
const linesLCA = textLCA.split(/\r?\n/);
|
|
79
86
|
const linesBase = textBase.split(/\r?\n/);
|
|
80
87
|
const linesOrphan = textOrphan.split(/\r?\n/);
|
|
@@ -157,6 +164,12 @@ export function perform3WayTextLineMerge({
|
|
|
157
164
|
};
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
/**
|
|
168
|
+
* 3-way text line diff graft strategy for B2tFS file item timelines.
|
|
169
|
+
*
|
|
170
|
+
* ⚠️ **IMPORTANT**: Before making ANY changes to this class or its methods, consult:
|
|
171
|
+
* `libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md`.
|
|
172
|
+
*/
|
|
160
173
|
export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements GraftStrategy {
|
|
161
174
|
readonly strategyId: string = 'B2tFS3WayGraftStrategy';
|
|
162
175
|
private lc = '[B2tFS3WayGraftStrategy]';
|
|
@@ -164,12 +177,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
164
177
|
/**
|
|
165
178
|
* Returns true only if the graft context has two tips that are text-based file b2tfs item ibgibs.
|
|
166
179
|
*
|
|
167
|
-
* ## notes
|
|
168
|
-
*
|
|
169
|
-
* atow (08/12/2026) implementation is guantlet style: if cannot graft, return early
|
|
170
|
-
*
|
|
171
180
|
* @param context info about the divergent timelines {@link GraftContext}
|
|
172
|
-
*
|
|
173
181
|
* @returns true if it's a text file item ibgib, else false
|
|
174
182
|
*/
|
|
175
183
|
async canGraft(context: GraftContext): Promise<boolean> {
|
|
@@ -177,19 +185,16 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
177
185
|
try {
|
|
178
186
|
const { conflictStrategy, timelineAddrsA, timelineAddrsB, ibGibReadCache, space } = context;
|
|
179
187
|
|
|
180
|
-
// todo: refactor conflict strategy to be more generic: 'graft' | 'abort' | maybe something else.
|
|
181
188
|
const hasRelevantStrategy = conflictStrategy === SyncConflictStrategy.optimisticWithLCS || (conflictStrategy as string) === 'b2tfs3WayMerge';
|
|
182
189
|
if (!hasRelevantStrategy) {
|
|
183
|
-
|
|
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 */
|
|
190
|
+
return false;
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
const tipAddrA = timelineAddrsA.at(-1);
|
|
189
194
|
const tipAddrB = timelineAddrsB.at(-1);
|
|
190
195
|
if (!tipAddrA || !tipAddrB) {
|
|
191
|
-
if (logalot) { console.log(`${lc} we don't have two tip addrs?
|
|
192
|
-
return false;
|
|
196
|
+
if (logalot) { console.log(`${lc} we don't have two tip addrs? (I: b20b6de462c35e0e74360cc8d317f126)`); }
|
|
197
|
+
return false;
|
|
193
198
|
}
|
|
194
199
|
|
|
195
200
|
const [tipA, tipB] = await getIbGibsFromCache_fallbackToSpaces({
|
|
@@ -198,26 +203,26 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
198
203
|
space,
|
|
199
204
|
});
|
|
200
205
|
|
|
201
|
-
if (!tipA) { throw new Error(`(UNEXPECTED) tipA falsy?
|
|
202
|
-
if (!tipB) { throw new Error(`(UNEXPECTED) tipB falsy?
|
|
206
|
+
if (!tipA) { throw new Error(`(UNEXPECTED) tipA falsy? (E: 752101026888140f074614e893531826)`); }
|
|
207
|
+
if (!tipB) { throw new Error(`(UNEXPECTED) tipB falsy? (E: d4d4a876cad8c7869830d33832bfde26)`); }
|
|
203
208
|
|
|
204
209
|
const bothTipsAreB2tFSNodes = isB2tFSItemIbGib(tipA) && isB2tFSItemIbGib(tipB);
|
|
205
210
|
|
|
206
211
|
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
212
|
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)`)
|
|
213
|
+
console.error(`${lc}${mergeDiag} (UNEXPECTED)(NOT THROWN) only tipA or tipB but not both are b2tfs items? (E: cacb38796da881268898e9d1af245826)`);
|
|
210
214
|
}
|
|
211
|
-
return false;
|
|
215
|
+
return false;
|
|
212
216
|
}
|
|
213
217
|
|
|
214
|
-
if (tipA.data.fsType !== tipB.data.fsType) {
|
|
218
|
+
if (tipA.data.fsType !== tipB.data.fsType) {
|
|
219
|
+
throw new Error(`(UNEXPECTED) tipA.data.fsType (${tipA.data.fsType}) !== tipB.data.fsType (${tipB.data.fsType})? (E: c01c1885ac738f679813117852c48426)`);
|
|
220
|
+
}
|
|
215
221
|
|
|
216
|
-
// only do files. folders
|
|
222
|
+
// only do files. folders and other containers fall back to DefaultDnaReplayGraftStrategy.
|
|
217
223
|
const isFile = tipA.data.fsType === B2tFSType.file;
|
|
218
|
-
if (!isFile) { return false;
|
|
224
|
+
if (!isFile) { return false; }
|
|
219
225
|
|
|
220
|
-
// passed gauntlet, we have a b2tfs file item that we can merge
|
|
221
226
|
return true;
|
|
222
227
|
} catch (error) {
|
|
223
228
|
console.error(`${lc} ${extractErrorMsg(error)} (E: 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e)`);
|
|
@@ -225,6 +230,16 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
225
230
|
}
|
|
226
231
|
}
|
|
227
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Executes 3-way line diff text graft across LCA, Base, and Orphan file items.
|
|
235
|
+
*
|
|
236
|
+
* ⚠️ **CRITICAL CONTRACT**: Before modifying this method, review:
|
|
237
|
+
* `libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md`
|
|
238
|
+
* Ensure:
|
|
239
|
+
* 1. Monotonic `n` counter (`highestDataN = Math.max(...)`)
|
|
240
|
+
* 2. Full dependency graph inclusion in `ancillaryIbGibsCreated` (comments, bin stones, DNAs)
|
|
241
|
+
* 3. Self-contained destination branch space
|
|
242
|
+
*/
|
|
228
243
|
async graft(context: GraftContext): Promise<GraftTimelinesResult | undefined> {
|
|
229
244
|
const lc = `${lcFile}[${this.strategyId}][${this.graft.name}]`;
|
|
230
245
|
try {
|
|
@@ -242,7 +257,6 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
242
257
|
graftPreference,
|
|
243
258
|
} = context;
|
|
244
259
|
|
|
245
|
-
|
|
246
260
|
// 1. Fetch branch slices since LCA (timeline A = Sender, timeline B = Receiver)
|
|
247
261
|
const indexLCA_A = timelineAddrsA.lastIndexOf(latestCommonFrameAddr);
|
|
248
262
|
const addrsA_sinceLCA = timelineAddrsA.slice(indexLCA_A + 1);
|
|
@@ -262,7 +276,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
262
276
|
});
|
|
263
277
|
const tipB_receiver = branchB_receiver_sinceLCA.at(-1)!;
|
|
264
278
|
|
|
265
|
-
// 2. Base & Orphan
|
|
279
|
+
// 2. Base & Orphan resolution via DRY helper
|
|
266
280
|
const {
|
|
267
281
|
baseTip,
|
|
268
282
|
baseBranch,
|
|
@@ -280,109 +294,13 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
280
294
|
const baseBranchAddrs = baseBranch.map(x => getIbGibAddr({ ibGib: x }));
|
|
281
295
|
const orphanTipAddr = getIbGibAddr({ ibGib: orphanTip });
|
|
282
296
|
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)`); }
|
|
285
297
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
});
|
|
298
|
+
if (logalot) {
|
|
299
|
+
console.log(`${lc} baseBranchAddrs:\n${baseBranchAddrs.join('\n')} (I: 2cad420d7bc822f798b8a8785f1f8c26)`);
|
|
300
|
+
console.log(`${lc} orphanBranchAddrs:\n${orphanBranchAddrs.join('\n')} (I: cc86489d6737e2aced42b585cba13526)`);
|
|
301
|
+
}
|
|
291
302
|
|
|
292
|
-
//
|
|
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
|
|
303
|
+
// 3. Perform 3-way filesystem tree merge across lcaItem, baseItem, orphanItem
|
|
386
304
|
const lcaNode = await this.fetchIbGib({ addr: latestCommonFrameAddr, space, readCache_graph: ibGibReadCache });
|
|
387
305
|
if (!lcaNode) { throw new Error(`(UNEXPECTED) lcaNode falsy? (E: a8b2d80dc4f8ba1448fa280d89dfb626)`); }
|
|
388
306
|
const lcaItem = await this.resolveRootItemNode({ nodeOrAddr: lcaNode, space, readCache_graph: ibGibReadCache });
|
|
@@ -394,68 +312,49 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
394
312
|
|
|
395
313
|
if (lcaItem.data.fsType !== baseItem.data.fsType) { throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== baseItem.data.fsType? (E: 794608f3e678a399ed670388629a6826)`); }
|
|
396
314
|
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
315
|
|
|
399
316
|
const fsType = lcaItem.data.fsType;
|
|
400
317
|
if (fsType === B2tFSType.folder) {
|
|
401
|
-
throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder?
|
|
318
|
+
throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder? Folders fall back to DefaultDnaReplayGraftStrategy and reification. (E: b282b8f77b18575378edb902bd80a826)`);
|
|
402
319
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
|
421
|
-
});
|
|
422
|
-
if (orphanPayload === undefined) {
|
|
423
|
-
if (logalot) { console.log(`${lc}${mergeDiag} orphanPayload undefined? (I: cd8b785875b43fc6684c65d818edd826)`); }
|
|
320
|
+
if (fsType !== B2tFSType.file) {
|
|
321
|
+
throw new Error(`(UNEXPECTED) fsType (${fsType}) is not a file? (E: 272418fe2067ea3e16dac028e86d1a26)`);
|
|
424
322
|
}
|
|
425
323
|
|
|
324
|
+
const lcaPayload = await this.getFilePayloadBuffer({ fileItem: lcaItem, space, readCache_graph: ibGibReadCache });
|
|
325
|
+
const basePayload = await this.getFilePayloadBuffer({ fileItem: baseItem, space, readCache_graph: ibGibReadCache });
|
|
326
|
+
const orphanPayload = await this.getFilePayloadBuffer({ fileItem: orphanItem, space, readCache_graph: ibGibReadCache });
|
|
327
|
+
|
|
426
328
|
const isBaseBin = basePayload ? isBinaryBuffer(basePayload.buffer) : false;
|
|
427
329
|
const isOrphanBin = orphanPayload ? isBinaryBuffer(orphanPayload.buffer) : false;
|
|
428
330
|
const isLcaBin = lcaPayload ? isBinaryBuffer(lcaPayload.buffer) : false;
|
|
429
331
|
|
|
430
332
|
if (isBaseBin || isOrphanBin || isLcaBin) {
|
|
431
333
|
if (logalot) {
|
|
432
|
-
console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
|
|
334
|
+
console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff and falling through. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
|
|
433
335
|
}
|
|
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 */
|
|
336
|
+
return undefined;
|
|
442
337
|
}
|
|
443
338
|
|
|
444
|
-
if (!lcaPayload) { throw new Error(`(UNEXPECTED) lcaPayload falsy?
|
|
445
|
-
if (!basePayload) { throw new Error(`(UNEXPECTED) basePayload falsy?
|
|
446
|
-
if (!orphanPayload) { throw new Error(`(UNEXPECTED) orphanPayload falsy?
|
|
339
|
+
if (!lcaPayload) { throw new Error(`(UNEXPECTED) lcaPayload falsy? (E: 0b82892204482f5538a430b8915b7826)`); }
|
|
340
|
+
if (!basePayload) { throw new Error(`(UNEXPECTED) basePayload falsy? (E: af1f68a020280b3a5d6ed4a812acd426)`); }
|
|
341
|
+
if (!orphanPayload) { throw new Error(`(UNEXPECTED) orphanPayload falsy? (E: 6a521b684763862c3a2e0ca315d62826)`); }
|
|
447
342
|
|
|
448
343
|
const textLCA = decodeToLines(lcaPayload.buffer).join('\n');
|
|
449
344
|
const textBase = decodeToLines(basePayload.buffer).join('\n');
|
|
450
345
|
const textOrphan = decodeToLines(orphanPayload.buffer).join('\n');
|
|
451
346
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
347
|
+
if (logalot) {
|
|
348
|
+
console.log(`${lc}${mergeDiag} file: ${baseItem.data.name}`);
|
|
349
|
+
console.log(`${lc}${mergeDiag} textLCA:\n${textLCA}`);
|
|
350
|
+
console.log(`${lc}${mergeDiag} textBase:\n${textBase}`);
|
|
351
|
+
console.log(`${lc}${mergeDiag} textOrphan:\n${textOrphan}`);
|
|
352
|
+
}
|
|
456
353
|
|
|
457
354
|
const { mergedText } = perform3WayTextLineMerge({ textLCA, textBase, textOrphan });
|
|
458
|
-
|
|
355
|
+
if (logalot) {
|
|
356
|
+
console.log(`${lc}${mergeDiag} mergedText:\n${mergedText}`);
|
|
357
|
+
}
|
|
459
358
|
|
|
460
359
|
const dataBuffer = Buffer.from(mergedText, 'utf8');
|
|
461
360
|
const fileHash = await hash({ s: mergedText });
|
|
@@ -478,38 +377,84 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
478
377
|
|
|
479
378
|
const binAddr = getIbGibAddr({ ibGib: binIbGib });
|
|
480
379
|
|
|
481
|
-
// at this point, we are committed to performing the 3-way merge.
|
|
482
380
|
await putInSpace({ ibGib: binIbGib, space });
|
|
483
381
|
await registerNewIbGib({ ibGib: binIbGib, space });
|
|
484
382
|
|
|
485
|
-
|
|
486
|
-
const fnGetN: (item: B2tFSItemIbGib_V1) => number = (item: B2tFSItemIbGib_V1) => {
|
|
383
|
+
const fnGetN = (item: B2tFSItemIbGib_V1): number => {
|
|
487
384
|
if (item.data.n || item.data.n === 0) {
|
|
488
385
|
return item.data.n!;
|
|
489
386
|
} else {
|
|
490
387
|
throw new Error(`(UNEXPECTED) item.data.n not a number? (E: 896ceae089c83ca67817fff826be5826)`);
|
|
491
388
|
}
|
|
492
|
-
}
|
|
389
|
+
};
|
|
493
390
|
const baseItemDataN = fnGetN(baseItem);
|
|
494
391
|
const orphanItemDataN = fnGetN(orphanItem);
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
392
|
+
const highestDataN = Math.max(baseItemDataN, orphanItemDataN);
|
|
393
|
+
|
|
394
|
+
const lcaCommentAddrs = lcaItem.rel8ns?.comment || [];
|
|
395
|
+
const lcaCommentAddrsSet = new Set(lcaCommentAddrs);
|
|
396
|
+
const mergedCommentAddrsSinceLCA_base = (baseItem.rel8ns?.comment || []).filter(addr => !lcaCommentAddrsSet.has(addr));
|
|
397
|
+
const mergedCommentAddrsSinceLCA_orphan = (orphanItem.rel8ns?.comment || []).filter(addr => !lcaCommentAddrsSet.has(addr));
|
|
398
|
+
const newCommentAddrs = Array.from(new Set([...mergedCommentAddrsSinceLCA_base, ...mergedCommentAddrsSinceLCA_orphan]));
|
|
399
|
+
const allMergedCommentAddrs = Array.from(new Set([...lcaCommentAddrs, ...newCommentAddrs]));
|
|
400
|
+
|
|
401
|
+
const commentDepIbGibs: IbGib_V1[] = [];
|
|
402
|
+
if (newCommentAddrs.length > 0) {
|
|
403
|
+
for (const cAddr of newCommentAddrs) {
|
|
404
|
+
const cIb = await this.fetchIbGib({ addr: cAddr, space, readCache_graph: ibGibReadCache });
|
|
405
|
+
if (!cIb) {
|
|
406
|
+
throw new Error(`(UNEXPECTED) Comment ibgib for address '${cAddr}' not found in cache or space (E: a1b2c3d4e5f67a8b9c0d1e2f3a4b5c6d)`);
|
|
407
|
+
}
|
|
408
|
+
commentDepIbGibs.push(cIb);
|
|
409
|
+
const cDepGraph = await getDependencyGraph({
|
|
410
|
+
ibGib: cIb,
|
|
411
|
+
space,
|
|
412
|
+
ibGibs: ibGibReadCache ? Object.values(ibGibReadCache) : undefined,
|
|
413
|
+
});
|
|
414
|
+
for (const depNode of Object.values(cDepGraph)) {
|
|
415
|
+
const depAddr = getIbGibAddr({ ibGib: depNode });
|
|
416
|
+
if (!commentDepIbGibs.some(x => getIbGibAddr({ ibGib: x }) === depAddr)) {
|
|
417
|
+
commentDepIbGibs.push(depNode);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const { mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: commentDepIbGibs });
|
|
423
|
+
|
|
424
|
+
// Put DNA and non-timeline stones into space with isDna flag
|
|
425
|
+
for (const dnaOrStone of Object.values(mapWithoutTjps)) {
|
|
426
|
+
if (space) {
|
|
427
|
+
await putInSpace({ ibGib: dnaOrStone, space, isDna: isDna({ ibGib: dnaOrStone }) });
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Register timeline frames in order
|
|
432
|
+
const timelinesByTjp = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
|
|
433
|
+
for (const tjpAddr of Object.keys(timelinesByTjp)) {
|
|
434
|
+
const timeline = timelinesByTjp[tjpAddr];
|
|
435
|
+
for (const frame of timeline) {
|
|
436
|
+
if (space) {
|
|
437
|
+
await putInSpace({ ibGib: frame, space });
|
|
438
|
+
await registerNewIbGib({ ibGib: frame, space });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
498
443
|
|
|
499
444
|
const evolveRes = await evolveB2tFSItemIbGib({
|
|
500
445
|
existingItem: baseItem,
|
|
501
446
|
dataToUpdate: {
|
|
502
447
|
fileHash,
|
|
503
|
-
n:
|
|
448
|
+
n: highestDataN + 1,
|
|
504
449
|
},
|
|
505
450
|
rel8nsToUpdate: {
|
|
506
451
|
[BINARY_REL8N_NAME]: [binAddr],
|
|
452
|
+
...(allMergedCommentAddrs.length > 0 ? { comment: allMergedCommentAddrs } : {}),
|
|
507
453
|
},
|
|
508
454
|
});
|
|
509
455
|
|
|
510
|
-
|
|
511
|
-
if (!evolveRes.
|
|
512
|
-
if (!evolveRes.newIbGib) { throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? we just did the merge, so this should be truthy. (E: 9e488d07772827b66a2aff4801905426)`); }
|
|
456
|
+
if (!evolveRes.dnas) { throw new Error(`(UNEXPECTED) evolveRes.dnas falsy? (E: e640e892cc76c77f98f3881301035826)`); }
|
|
457
|
+
if (!evolveRes.newIbGib) { throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? (E: 9e488d07772827b66a2aff4801905426)`); }
|
|
513
458
|
const newItemWithNewBinPayload = evolveRes.newIbGib as B2tFSItemIbGib_V1;
|
|
514
459
|
const newItemAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
|
|
515
460
|
if (logalot) { console.log(`${lc} newItemAddr: ${newItemAddr} (I: d23eef651b88be1248ee29ca179eff26)`); }
|
|
@@ -519,31 +464,20 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
519
464
|
|
|
520
465
|
newGraftDnaIbGibs.push(...evolveRes.dnas);
|
|
521
466
|
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
467
|
evolveRes.intermediateIbGibs.forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
|
|
524
468
|
}
|
|
525
469
|
|
|
526
470
|
await persistTransformResult({ resTransform: evolveRes, space });
|
|
527
471
|
await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
|
|
528
472
|
|
|
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
473
|
const b2tfsAddlGraftDetails: B2tFS3WayAddlGraftDetails = {
|
|
540
474
|
baseTextB2tFSItemAddr: baseTipAddr,
|
|
541
475
|
baseTextBinAddr: basePayload.binIbGib ? getIbGibAddr({ ibGib: basePayload.binIbGib }) : undefined,
|
|
542
476
|
orphanTextB2tFSItemAddr: orphanTipAddr,
|
|
543
477
|
orphanTextBinAddr: orphanPayload.binIbGib ? getIbGibAddr({ ibGib: orphanPayload.binIbGib }) : undefined,
|
|
544
|
-
}
|
|
478
|
+
};
|
|
545
479
|
|
|
546
|
-
//
|
|
480
|
+
// 4. Attach GraftInfo frame
|
|
547
481
|
const graftInfo = await createGraftInfo({
|
|
548
482
|
conflictStrategy,
|
|
549
483
|
details: `Merged orphan tip text with the baseTip as a starting point.`,
|
|
@@ -584,7 +518,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
584
518
|
dnasReplayed: [],
|
|
585
519
|
dnasCreatedInGraft: newGraftDnaIbGibs,
|
|
586
520
|
intermediateIbGibsCreatedInGraft: newGraftedIntermediateIbGibs_ordered,
|
|
587
|
-
ancillaryIbGibsCreated: [binIbGib],
|
|
521
|
+
ancillaryIbGibsCreated: [binIbGib, ...commentDepIbGibs],
|
|
588
522
|
newGraftTip: finalGraftTip,
|
|
589
523
|
graftInfoCreated: graftInfo,
|
|
590
524
|
};
|
|
@@ -608,28 +542,24 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
608
542
|
readCache_graph?: FlatIbGibGraph;
|
|
609
543
|
}): Promise<IbGib_V1 | undefined> {
|
|
610
544
|
if (!addr) { return undefined; }
|
|
611
|
-
const cleanAddr = addr.includes('^') ? addr.split('^')[0] : addr;
|
|
612
545
|
if (readCache_graph) {
|
|
613
|
-
if (readCache_graph[cleanAddr]) { return readCache_graph[cleanAddr]; }
|
|
614
546
|
if (readCache_graph[addr]) { return readCache_graph[addr]; }
|
|
615
|
-
const
|
|
547
|
+
const gib = addr.includes('^') ? addr.substring(addr.lastIndexOf('^') + 1) : addr;
|
|
548
|
+
const matchingKey = Object.keys(readCache_graph).find(k => k === addr || (gib && k.endsWith('^' + gib)));
|
|
616
549
|
if (matchingKey) { return readCache_graph[matchingKey]; }
|
|
617
550
|
}
|
|
618
551
|
try {
|
|
619
|
-
const res = await getFromSpace({ space, addrs: [addr
|
|
620
|
-
if (res
|
|
621
|
-
const found = res.ibGibs.find((x: any) => !!x);
|
|
552
|
+
const res = await getFromSpace({ space, addrs: [addr] });
|
|
553
|
+
if (res) {
|
|
554
|
+
const found = res.ibGibs?.find((x: any) => !!x) || (res.rawResultIbGib as any)?.ibGibs?.find((x: any) => !!x);
|
|
622
555
|
if (found) { return found; }
|
|
623
556
|
}
|
|
624
557
|
} catch {
|
|
625
558
|
// 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)
|
|
628
559
|
}
|
|
629
560
|
return undefined;
|
|
630
561
|
}
|
|
631
562
|
|
|
632
|
-
|
|
633
563
|
private async resolveRootItemNode({
|
|
634
564
|
nodeOrAddr,
|
|
635
565
|
space,
|
|
@@ -650,11 +580,9 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
650
580
|
if (!node) { throw new Error(`(UNEXPECTED) node falsy? couldn't get node? (E: bd7d1c3b4a3881ff882746281869d826)`); }
|
|
651
581
|
|
|
652
582
|
if (isB2tFSItemIbGib(node)) {
|
|
653
|
-
// it's an item ibgib
|
|
654
583
|
return node;
|
|
655
584
|
} else {
|
|
656
|
-
|
|
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)`);
|
|
585
|
+
throw new Error(`(UNEXPECTED) node is not a B2tFSItemIbGib_V1? (E: ddabb281ccb2fb1a181109a82046b826)`);
|
|
658
586
|
}
|
|
659
587
|
}
|
|
660
588
|
|
|
@@ -674,7 +602,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
674
602
|
|
|
675
603
|
const binIbGib = await this.fetchIbGib({ addr: latestBinAddr, space, readCache_graph });
|
|
676
604
|
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; }
|
|
605
|
+
if (binIbGib.data === undefined) { return undefined; }
|
|
678
606
|
|
|
679
607
|
let fileData: Uint8Array;
|
|
680
608
|
const dataObj = binIbGib.data as any;
|
|
@@ -697,156 +625,6 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
|
|
|
697
625
|
fileData = new Uint8Array(0);
|
|
698
626
|
}
|
|
699
627
|
|
|
700
|
-
|
|
701
628
|
return { buffer: fileData, binIbGib };
|
|
702
629
|
}
|
|
703
|
-
|
|
704
|
-
private async getChildItemsMap({
|
|
705
|
-
folderItem,
|
|
706
|
-
space,
|
|
707
|
-
readCache_graph,
|
|
708
|
-
}: {
|
|
709
|
-
folderItem?: B2tFSItemIbGib_V1;
|
|
710
|
-
space: IbGibSpaceAny;
|
|
711
|
-
readCache_graph?: FlatIbGibGraph;
|
|
712
|
-
}): Promise<Map<string, B2tFSItemIbGib_V1>> {
|
|
713
|
-
const map = new Map<string, B2tFSItemIbGib_V1>();
|
|
714
|
-
if (!folderItem || !folderItem.rel8ns) { return map; }
|
|
715
|
-
const childAddrs = folderItem.rel8ns[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
|
|
716
|
-
for (const addr of childAddrs) {
|
|
717
|
-
const childNode = await this.fetchIbGib({ addr, space, readCache_graph }) as B2tFSItemIbGib_V1;
|
|
718
|
-
if (childNode && childNode.data?.name) {
|
|
719
|
-
map.set(childNode.data.name, childNode);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
return map;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
private async mergeTreeNodes({
|
|
726
|
-
lcaItem,
|
|
727
|
-
baseItem,
|
|
728
|
-
orphanItem,
|
|
729
|
-
space,
|
|
730
|
-
readCache_graph,
|
|
731
|
-
newGraftDnaIbGibs,
|
|
732
|
-
newGraftedIntermediateIbGibs_ordered,
|
|
733
|
-
}: {
|
|
734
|
-
lcaItem?: B2tFSItemIbGib_V1;
|
|
735
|
-
baseItem?: B2tFSItemIbGib_V1;
|
|
736
|
-
orphanItem?: B2tFSItemIbGib_V1;
|
|
737
|
-
space: IbGibSpaceAny;
|
|
738
|
-
readCache_graph?: FlatIbGibGraph;
|
|
739
|
-
newGraftDnaIbGibs: IbGib_V1[];
|
|
740
|
-
newGraftedIntermediateIbGibs_ordered: IbGib_V1[];
|
|
741
|
-
}): Promise<B2tFSItemIbGib_V1 | undefined> {
|
|
742
|
-
const lc = `${lcFile}[${this.mergeTreeNodes.name}]`;
|
|
743
|
-
|
|
744
|
-
const baseAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
|
|
745
|
-
const orphanAddr = orphanItem ? getIbGibAddr({ ibGib: orphanItem }) : undefined;
|
|
746
|
-
|
|
747
|
-
const lcaAddr = lcaItem ? getIbGibAddr({ ibGib: lcaItem }) : undefined;
|
|
748
|
-
|
|
749
|
-
if (baseAddr && orphanAddr && baseAddr === orphanAddr) {
|
|
750
|
-
return baseItem;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
if (lcaAddr && baseAddr && baseAddr === lcaAddr && orphanItem) {
|
|
754
|
-
return orphanItem;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
if (lcaAddr && orphanAddr && orphanAddr === lcaAddr && baseItem) {
|
|
758
|
-
return baseItem;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (!baseItem && !orphanItem) {
|
|
762
|
-
return undefined;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
if (baseItem && !orphanItem) {
|
|
766
|
-
if (lcaAddr && baseAddr === lcaAddr) {
|
|
767
|
-
return undefined;
|
|
768
|
-
}
|
|
769
|
-
return baseItem;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (orphanItem && !baseItem) {
|
|
773
|
-
if (lcaAddr && orphanAddr === lcaAddr) {
|
|
774
|
-
return undefined;
|
|
775
|
-
}
|
|
776
|
-
return orphanItem;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (!baseItem || !orphanItem) {
|
|
780
|
-
throw new Error(`(UNEXPECTED) baseItem or orphanItem missing in 3-way merge branch (E: 5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a)`);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
const fsType = baseItem.data?.fsType || orphanItem.data?.fsType;
|
|
784
|
-
|
|
785
|
-
if (fsType === 'file') {
|
|
786
|
-
} else if (fsType === 'folder') {
|
|
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;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
return baseItem;
|
|
849
|
-
}
|
|
850
630
|
}
|
|
851
|
-
|
|
852
|
-
export const B2tFSItem3WayMergeStrategy = B2tFS3WayGraftStrategy;
|