@lix-js/sdk 0.6.0-preview.4 → 0.6.0
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/README.md +76 -4
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +19 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +3 -3
- package/dist/native.d.ts +1 -0
- package/dist/native.js +47 -0
- package/dist/open-lix.d.ts +39 -201
- package/dist/open-lix.js +59 -284
- package/dist/result.d.ts +18 -0
- package/dist/result.js +48 -0
- package/dist/types.d.ts +114 -1
- package/dist/value.d.ts +28 -0
- package/dist/value.js +245 -0
- package/package.json +20 -50
- package/SKILL.md +0 -506
- package/dist/builtin-schemas.d.ts +0 -1
- package/dist/builtin-schemas.js +0 -1
- package/dist/engine-wasm/index.d.ts +0 -87
- package/dist/engine-wasm/index.js +0 -339
- package/dist/engine-wasm/wasm/lix_engine.d.ts +0 -79
- package/dist/engine-wasm/wasm/lix_engine.js +0 -821
- package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
- package/dist/engine-wasm/wasm/lix_engine.wasm.d.ts +0 -26
- package/dist/generated/builtin-schemas.d.ts +0 -427
- package/dist/generated/builtin-schemas.js +0 -643
- package/dist/sqlite/index.d.ts +0 -12
- package/dist/sqlite/index.js +0 -303
- package/dist-engine-src/README.md +0 -18
- package/dist-engine-src/src/backend/kv.rs +0 -358
- package/dist-engine-src/src/backend/mod.rs +0 -12
- package/dist-engine-src/src/backend/testing.rs +0 -658
- package/dist-engine-src/src/backend/types.rs +0 -96
- package/dist-engine-src/src/binary_cas/chunking.rs +0 -31
- package/dist-engine-src/src/binary_cas/codec.rs +0 -346
- package/dist-engine-src/src/binary_cas/context.rs +0 -139
- package/dist-engine-src/src/binary_cas/kv.rs +0 -1063
- package/dist-engine-src/src/binary_cas/mod.rs +0 -11
- package/dist-engine-src/src/binary_cas/types.rs +0 -121
- package/dist-engine-src/src/catalog/context.rs +0 -412
- package/dist-engine-src/src/catalog/mod.rs +0 -10
- package/dist-engine-src/src/catalog/schema.rs +0 -4
- package/dist-engine-src/src/catalog/snapshot.rs +0 -1114
- package/dist-engine-src/src/cel/context.rs +0 -86
- package/dist-engine-src/src/cel/error.rs +0 -19
- package/dist-engine-src/src/cel/mod.rs +0 -8
- package/dist-engine-src/src/cel/provider.rs +0 -9
- package/dist-engine-src/src/cel/runtime.rs +0 -167
- package/dist-engine-src/src/cel/value.rs +0 -50
- package/dist-engine-src/src/commit_graph/context.rs +0 -901
- package/dist-engine-src/src/commit_graph/mod.rs +0 -11
- package/dist-engine-src/src/commit_graph/types.rs +0 -109
- package/dist-engine-src/src/commit_graph/walker.rs +0 -756
- package/dist-engine-src/src/commit_store/codec.rs +0 -887
- package/dist-engine-src/src/commit_store/context.rs +0 -944
- package/dist-engine-src/src/commit_store/materialization.rs +0 -84
- package/dist-engine-src/src/commit_store/mod.rs +0 -16
- package/dist-engine-src/src/commit_store/storage.rs +0 -600
- package/dist-engine-src/src/commit_store/types.rs +0 -215
- package/dist-engine-src/src/common/error.rs +0 -313
- package/dist-engine-src/src/common/fingerprint.rs +0 -3
- package/dist-engine-src/src/common/fs_path.rs +0 -1336
- package/dist-engine-src/src/common/identity.rs +0 -145
- package/dist-engine-src/src/common/json_pointer.rs +0 -67
- package/dist-engine-src/src/common/metadata.rs +0 -40
- package/dist-engine-src/src/common/mod.rs +0 -23
- package/dist-engine-src/src/common/types.rs +0 -105
- package/dist-engine-src/src/common/wire.rs +0 -222
- package/dist-engine-src/src/domain.rs +0 -324
- package/dist-engine-src/src/engine.rs +0 -225
- package/dist-engine-src/src/entity_identity.rs +0 -405
- package/dist-engine-src/src/functions/context.rs +0 -292
- package/dist-engine-src/src/functions/deterministic.rs +0 -113
- package/dist-engine-src/src/functions/mod.rs +0 -18
- package/dist-engine-src/src/functions/provider.rs +0 -130
- package/dist-engine-src/src/functions/state.rs +0 -336
- package/dist-engine-src/src/functions/types.rs +0 -37
- package/dist-engine-src/src/init.rs +0 -558
- package/dist-engine-src/src/json_store/compression.rs +0 -77
- package/dist-engine-src/src/json_store/context.rs +0 -423
- package/dist-engine-src/src/json_store/encoded.rs +0 -15
- package/dist-engine-src/src/json_store/mod.rs +0 -12
- package/dist-engine-src/src/json_store/store.rs +0 -1109
- package/dist-engine-src/src/json_store/types.rs +0 -217
- package/dist-engine-src/src/lib.rs +0 -62
- package/dist-engine-src/src/live_state/context.rs +0 -2019
- package/dist-engine-src/src/live_state/mod.rs +0 -15
- package/dist-engine-src/src/live_state/overlay.rs +0 -75
- package/dist-engine-src/src/live_state/reader.rs +0 -23
- package/dist-engine-src/src/live_state/types.rs +0 -222
- package/dist-engine-src/src/live_state/visibility.rs +0 -223
- package/dist-engine-src/src/plugin/archive.rs +0 -438
- package/dist-engine-src/src/plugin/component.rs +0 -183
- package/dist-engine-src/src/plugin/install.rs +0 -619
- package/dist-engine-src/src/plugin/manifest.rs +0 -516
- package/dist-engine-src/src/plugin/materializer.rs +0 -477
- package/dist-engine-src/src/plugin/mod.rs +0 -33
- package/dist-engine-src/src/plugin/plugin_manifest.json +0 -118
- package/dist-engine-src/src/plugin/storage.rs +0 -74
- package/dist-engine-src/src/schema/annotations/defaults.rs +0 -275
- package/dist-engine-src/src/schema/annotations/mod.rs +0 -1
- package/dist-engine-src/src/schema/builtin/lix_account.json +0 -21
- package/dist-engine-src/src/schema/builtin/lix_active_account.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_change.json +0 -63
- package/dist-engine-src/src/schema/builtin/lix_change_author.json +0 -45
- package/dist-engine-src/src/schema/builtin/lix_commit.json +0 -24
- package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +0 -53
- package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +0 -52
- package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +0 -52
- package/dist-engine-src/src/schema/builtin/lix_key_value.json +0 -40
- package/dist-engine-src/src/schema/builtin/lix_label.json +0 -29
- package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +0 -74
- package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +0 -25
- package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -34
- package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -48
- package/dist-engine-src/src/schema/builtin/mod.rs +0 -222
- package/dist-engine-src/src/schema/compatibility.rs +0 -787
- package/dist-engine-src/src/schema/definition.json +0 -187
- package/dist-engine-src/src/schema/definition.rs +0 -742
- package/dist-engine-src/src/schema/key.rs +0 -138
- package/dist-engine-src/src/schema/mod.rs +0 -20
- package/dist-engine-src/src/schema/seed.rs +0 -14
- package/dist-engine-src/src/schema/tests.rs +0 -780
- package/dist-engine-src/src/session/context.rs +0 -404
- package/dist-engine-src/src/session/create_version.rs +0 -88
- package/dist-engine-src/src/session/execute.rs +0 -541
- package/dist-engine-src/src/session/merge/analysis.rs +0 -102
- package/dist-engine-src/src/session/merge/apply.rs +0 -23
- package/dist-engine-src/src/session/merge/conflicts.rs +0 -63
- package/dist-engine-src/src/session/merge/mod.rs +0 -11
- package/dist-engine-src/src/session/merge/stats.rs +0 -65
- package/dist-engine-src/src/session/merge/version.rs +0 -427
- package/dist-engine-src/src/session/mod.rs +0 -27
- package/dist-engine-src/src/session/optimization9_sql2_bench.rs +0 -100
- package/dist-engine-src/src/session/switch_version.rs +0 -110
- package/dist-engine-src/src/session/transaction.rs +0 -76
- package/dist-engine-src/src/sql2/change_provider.rs +0 -331
- package/dist-engine-src/src/sql2/classify.rs +0 -174
- package/dist-engine-src/src/sql2/context.rs +0 -311
- package/dist-engine-src/src/sql2/directory_history_provider.rs +0 -631
- package/dist-engine-src/src/sql2/directory_provider.rs +0 -2453
- package/dist-engine-src/src/sql2/dml.rs +0 -148
- package/dist-engine-src/src/sql2/entity_history_provider.rs +0 -440
- package/dist-engine-src/src/sql2/entity_provider.rs +0 -3211
- package/dist-engine-src/src/sql2/error.rs +0 -215
- package/dist-engine-src/src/sql2/execute.rs +0 -3533
- package/dist-engine-src/src/sql2/file_history_provider.rs +0 -910
- package/dist-engine-src/src/sql2/file_provider.rs +0 -3679
- package/dist-engine-src/src/sql2/filesystem_planner.rs +0 -1490
- package/dist-engine-src/src/sql2/filesystem_predicates.rs +0 -159
- package/dist-engine-src/src/sql2/filesystem_visibility.rs +0 -383
- package/dist-engine-src/src/sql2/history_projection.rs +0 -56
- package/dist-engine-src/src/sql2/history_provider.rs +0 -412
- package/dist-engine-src/src/sql2/history_route.rs +0 -657
- package/dist-engine-src/src/sql2/lix_state_provider.rs +0 -2512
- package/dist-engine-src/src/sql2/mod.rs +0 -47
- package/dist-engine-src/src/sql2/predicate_typecheck.rs +0 -246
- package/dist-engine-src/src/sql2/public_bind/assignment.rs +0 -46
- package/dist-engine-src/src/sql2/public_bind/capability.rs +0 -41
- package/dist-engine-src/src/sql2/public_bind/dml.rs +0 -172
- package/dist-engine-src/src/sql2/public_bind/mod.rs +0 -26
- package/dist-engine-src/src/sql2/public_bind/table.rs +0 -168
- package/dist-engine-src/src/sql2/read_only.rs +0 -63
- package/dist-engine-src/src/sql2/record_batch.rs +0 -17
- package/dist-engine-src/src/sql2/result_metadata.rs +0 -29
- package/dist-engine-src/src/sql2/runtime.rs +0 -60
- package/dist-engine-src/src/sql2/session.rs +0 -132
- package/dist-engine-src/src/sql2/udfs/common.rs +0 -295
- package/dist-engine-src/src/sql2/udfs/lix_active_version_commit_id.rs +0 -53
- package/dist-engine-src/src/sql2/udfs/lix_empty_blob.rs +0 -47
- package/dist-engine-src/src/sql2/udfs/lix_json.rs +0 -100
- package/dist-engine-src/src/sql2/udfs/lix_json_get.rs +0 -99
- package/dist-engine-src/src/sql2/udfs/lix_json_get_text.rs +0 -99
- package/dist-engine-src/src/sql2/udfs/lix_text_decode.rs +0 -82
- package/dist-engine-src/src/sql2/udfs/lix_text_encode.rs +0 -85
- package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +0 -76
- package/dist-engine-src/src/sql2/udfs/lix_uuid_v7.rs +0 -76
- package/dist-engine-src/src/sql2/udfs/mod.rs +0 -89
- package/dist-engine-src/src/sql2/udfs/public_call.rs +0 -238
- package/dist-engine-src/src/sql2/version_provider.rs +0 -1202
- package/dist-engine-src/src/sql2/version_scope.rs +0 -394
- package/dist-engine-src/src/sql2/write_normalization.rs +0 -345
- package/dist-engine-src/src/storage/context.rs +0 -356
- package/dist-engine-src/src/storage/mod.rs +0 -14
- package/dist-engine-src/src/storage/read_scope.rs +0 -88
- package/dist-engine-src/src/storage/types.rs +0 -501
- package/dist-engine-src/src/storage_bench.rs +0 -4863
- package/dist-engine-src/src/test_support.rs +0 -228
- package/dist-engine-src/src/tracked_state/by_file_index.rs +0 -98
- package/dist-engine-src/src/tracked_state/codec.rs +0 -2085
- package/dist-engine-src/src/tracked_state/context.rs +0 -1867
- package/dist-engine-src/src/tracked_state/diff.rs +0 -686
- package/dist-engine-src/src/tracked_state/materialization.rs +0 -403
- package/dist-engine-src/src/tracked_state/materializer.rs +0 -488
- package/dist-engine-src/src/tracked_state/merge.rs +0 -492
- package/dist-engine-src/src/tracked_state/mod.rs +0 -32
- package/dist-engine-src/src/tracked_state/storage.rs +0 -375
- package/dist-engine-src/src/tracked_state/tree.rs +0 -3187
- package/dist-engine-src/src/tracked_state/types.rs +0 -231
- package/dist-engine-src/src/transaction/commit.rs +0 -1484
- package/dist-engine-src/src/transaction/context.rs +0 -1548
- package/dist-engine-src/src/transaction/live_state_overlay.rs +0 -35
- package/dist-engine-src/src/transaction/mod.rs +0 -13
- package/dist-engine-src/src/transaction/normalization.rs +0 -890
- package/dist-engine-src/src/transaction/prep.rs +0 -37
- package/dist-engine-src/src/transaction/schema_resolver.rs +0 -149
- package/dist-engine-src/src/transaction/staging.rs +0 -1731
- package/dist-engine-src/src/transaction/types.rs +0 -460
- package/dist-engine-src/src/transaction/validation.rs +0 -5830
- package/dist-engine-src/src/untracked_state/codec.rs +0 -307
- package/dist-engine-src/src/untracked_state/context.rs +0 -98
- package/dist-engine-src/src/untracked_state/materialization.rs +0 -63
- package/dist-engine-src/src/untracked_state/mod.rs +0 -15
- package/dist-engine-src/src/untracked_state/storage.rs +0 -396
- package/dist-engine-src/src/untracked_state/types.rs +0 -146
- package/dist-engine-src/src/version/context.rs +0 -40
- package/dist-engine-src/src/version/lifecycle.rs +0 -221
- package/dist-engine-src/src/version/mod.rs +0 -13
- package/dist-engine-src/src/version/refs.rs +0 -330
- package/dist-engine-src/src/version/stage_rows.rs +0 -67
- package/dist-engine-src/src/version/types.rs +0 -21
- package/dist-engine-src/src/wasm/mod.rs +0 -60
|
@@ -1,756 +0,0 @@
|
|
|
1
|
-
use std::collections::{BTreeMap, BTreeSet};
|
|
2
|
-
|
|
3
|
-
use crate::commit_graph::{CommitGraphCommit, CommitGraphStoreReader, ReachableCommitGraphCommit};
|
|
4
|
-
use crate::storage::StorageReader;
|
|
5
|
-
use crate::LixError;
|
|
6
|
-
|
|
7
|
-
/// Walks parent links from `head_commit_id` and returns reachable commits
|
|
8
|
-
/// nearest-first.
|
|
9
|
-
///
|
|
10
|
-
/// The walker is intentionally storage-free. It asks `CommitGraphReader` to
|
|
11
|
-
/// load parsed commit facts and owns only traversal concerns: caching, cycle
|
|
12
|
-
/// detection, and nearest-depth selection.
|
|
13
|
-
pub(crate) async fn walk_reachable_commits<S>(
|
|
14
|
-
reader: &mut CommitGraphStoreReader<S>,
|
|
15
|
-
head_commit_id: &str,
|
|
16
|
-
) -> Result<Vec<ReachableCommitGraphCommit>, LixError>
|
|
17
|
-
where
|
|
18
|
-
S: StorageReader,
|
|
19
|
-
{
|
|
20
|
-
let mut loader = CommitTraversalLoader::new(reader);
|
|
21
|
-
let mut visiting = BTreeSet::new();
|
|
22
|
-
let mut nearest_depths = BTreeMap::new();
|
|
23
|
-
loader
|
|
24
|
-
.walk_commit(head_commit_id, 0, &mut visiting, &mut nearest_depths)
|
|
25
|
-
.await?;
|
|
26
|
-
|
|
27
|
-
let mut commits = nearest_depths
|
|
28
|
-
.into_iter()
|
|
29
|
-
.map(|(commit_id, depth)| {
|
|
30
|
-
let commit = loader
|
|
31
|
-
.loaded
|
|
32
|
-
.remove(&commit_id)
|
|
33
|
-
.expect("visited commit should be cached");
|
|
34
|
-
ReachableCommitGraphCommit { commit, depth }
|
|
35
|
-
})
|
|
36
|
-
.collect::<Vec<_>>();
|
|
37
|
-
commits.sort_by(|left, right| {
|
|
38
|
-
left.depth
|
|
39
|
-
.cmp(&right.depth)
|
|
40
|
-
.then_with(|| left.commit.commit_id.cmp(&right.commit.commit_id))
|
|
41
|
-
});
|
|
42
|
-
Ok(commits)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/// Returns the best common ancestors shared by two commit heads.
|
|
46
|
-
///
|
|
47
|
-
/// This is graph math, not merge policy. A commit is "best" when it is a
|
|
48
|
-
/// common ancestor and no descendant of it is also a common ancestor.
|
|
49
|
-
///
|
|
50
|
-
/// Simple history has one best common ancestor:
|
|
51
|
-
///
|
|
52
|
-
/// ```text
|
|
53
|
-
/// A -- B -- C left
|
|
54
|
-
/// \
|
|
55
|
-
/// D right
|
|
56
|
-
/// ```
|
|
57
|
-
///
|
|
58
|
-
/// `best_common_ancestors(C, D)` returns `[B]`.
|
|
59
|
-
///
|
|
60
|
-
/// Commit history is a DAG, not a tree, so criss-cross histories can have
|
|
61
|
-
/// multiple equally good answers. Callers that need one merge base should wrap
|
|
62
|
-
/// this API with an explicit policy instead of pretending the graph always has
|
|
63
|
-
/// a single lowest common ancestor.
|
|
64
|
-
pub(crate) async fn best_common_ancestors<S>(
|
|
65
|
-
reader: &mut CommitGraphStoreReader<S>,
|
|
66
|
-
left_commit_id: &str,
|
|
67
|
-
right_commit_id: &str,
|
|
68
|
-
) -> Result<Vec<CommitGraphCommit>, LixError>
|
|
69
|
-
where
|
|
70
|
-
S: StorageReader,
|
|
71
|
-
{
|
|
72
|
-
let left_reachable = walk_reachable_commits(reader, left_commit_id).await?;
|
|
73
|
-
let right_reachable = walk_reachable_commits(reader, right_commit_id).await?;
|
|
74
|
-
let right_ids = right_reachable
|
|
75
|
-
.iter()
|
|
76
|
-
.map(|reachable| reachable.commit.commit_id.clone())
|
|
77
|
-
.collect::<BTreeSet<_>>();
|
|
78
|
-
let common_ids = left_reachable
|
|
79
|
-
.iter()
|
|
80
|
-
.filter(|reachable| right_ids.contains(&reachable.commit.commit_id))
|
|
81
|
-
.map(|reachable| reachable.commit.commit_id.clone())
|
|
82
|
-
.collect::<BTreeSet<_>>();
|
|
83
|
-
|
|
84
|
-
let mut best = Vec::new();
|
|
85
|
-
for reachable in left_reachable {
|
|
86
|
-
let commit_id = &reachable.commit.commit_id;
|
|
87
|
-
if !common_ids.contains(commit_id) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if has_descendant_in_set(reader, commit_id, &common_ids).await? {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
best.push(reachable.commit);
|
|
96
|
-
}
|
|
97
|
-
best.sort_by(|left, right| left.commit_id.cmp(&right.commit_id));
|
|
98
|
-
Ok(best)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async fn has_descendant_in_set<S>(
|
|
102
|
-
reader: &mut CommitGraphStoreReader<S>,
|
|
103
|
-
commit_id: &str,
|
|
104
|
-
candidate_descendant_ids: &BTreeSet<String>,
|
|
105
|
-
) -> Result<bool, LixError>
|
|
106
|
-
where
|
|
107
|
-
S: StorageReader,
|
|
108
|
-
{
|
|
109
|
-
for candidate_descendant_id in candidate_descendant_ids {
|
|
110
|
-
if candidate_descendant_id == commit_id {
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
let reachable = walk_reachable_commits(reader, candidate_descendant_id).await?;
|
|
114
|
-
if reachable
|
|
115
|
-
.iter()
|
|
116
|
-
.any(|reachable| reachable.commit.commit_id == commit_id)
|
|
117
|
-
{
|
|
118
|
-
return Ok(true);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
Ok(false)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
struct CommitTraversalLoader<'a, S>
|
|
125
|
-
where
|
|
126
|
-
S: StorageReader,
|
|
127
|
-
{
|
|
128
|
-
reader: &'a mut CommitGraphStoreReader<S>,
|
|
129
|
-
loaded: BTreeMap<String, CommitGraphCommit>,
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
impl<'a, S> CommitTraversalLoader<'a, S>
|
|
133
|
-
where
|
|
134
|
-
S: StorageReader,
|
|
135
|
-
{
|
|
136
|
-
fn new(reader: &'a mut CommitGraphStoreReader<S>) -> Self {
|
|
137
|
-
Self {
|
|
138
|
-
reader,
|
|
139
|
-
loaded: BTreeMap::new(),
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async fn walk_commit(
|
|
144
|
-
&mut self,
|
|
145
|
-
commit_id: &str,
|
|
146
|
-
depth: u32,
|
|
147
|
-
visiting: &mut BTreeSet<String>,
|
|
148
|
-
nearest_depths: &mut BTreeMap<String, u32>,
|
|
149
|
-
) -> Result<(), LixError> {
|
|
150
|
-
let mut stack = vec![TraversalFrame {
|
|
151
|
-
commit_id: commit_id.to_string(),
|
|
152
|
-
depth,
|
|
153
|
-
expanded: false,
|
|
154
|
-
}];
|
|
155
|
-
|
|
156
|
-
while let Some(frame) = stack.pop() {
|
|
157
|
-
if frame.expanded {
|
|
158
|
-
visiting.remove(&frame.commit_id);
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if visiting.contains(&frame.commit_id) {
|
|
163
|
-
return Err(LixError::new(
|
|
164
|
-
"LIX_ERROR_UNKNOWN",
|
|
165
|
-
format!(
|
|
166
|
-
"commit_graph cycle detected at commit '{}'",
|
|
167
|
-
frame.commit_id
|
|
168
|
-
),
|
|
169
|
-
));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if let Some(previous_depth) = nearest_depths.get(&frame.commit_id) {
|
|
173
|
-
if *previous_depth <= frame.depth {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
let commit = self.load_commit(&frame.commit_id).await?;
|
|
179
|
-
nearest_depths.insert(frame.commit_id.clone(), frame.depth);
|
|
180
|
-
|
|
181
|
-
visiting.insert(frame.commit_id.clone());
|
|
182
|
-
stack.push(TraversalFrame {
|
|
183
|
-
commit_id: frame.commit_id,
|
|
184
|
-
depth: frame.depth,
|
|
185
|
-
expanded: true,
|
|
186
|
-
});
|
|
187
|
-
for parent_commit_id in commit.parent_commit_ids.iter().rev() {
|
|
188
|
-
stack.push(TraversalFrame {
|
|
189
|
-
commit_id: parent_commit_id.clone(),
|
|
190
|
-
depth: frame.depth + 1,
|
|
191
|
-
expanded: false,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
Ok(())
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async fn load_commit(&mut self, commit_id: &str) -> Result<CommitGraphCommit, LixError> {
|
|
199
|
-
if let Some(commit) = self.loaded.get(commit_id) {
|
|
200
|
-
return Ok(commit.clone());
|
|
201
|
-
}
|
|
202
|
-
let Some(commit) = self.reader.load_commit(commit_id).await? else {
|
|
203
|
-
return Err(LixError::new(
|
|
204
|
-
"LIX_ERROR_UNKNOWN",
|
|
205
|
-
format!("commit_graph missing commit '{commit_id}'"),
|
|
206
|
-
));
|
|
207
|
-
};
|
|
208
|
-
self.loaded.insert(commit_id.to_string(), commit.clone());
|
|
209
|
-
Ok(commit)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
struct TraversalFrame {
|
|
214
|
-
commit_id: String,
|
|
215
|
-
depth: u32,
|
|
216
|
-
expanded: bool,
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
#[cfg(test)]
|
|
220
|
-
mod tests {
|
|
221
|
-
use std::sync::Arc;
|
|
222
|
-
|
|
223
|
-
use serde_json::json;
|
|
224
|
-
|
|
225
|
-
use crate::backend::testing::UnitTestBackend;
|
|
226
|
-
use crate::commit_graph::CommitGraphContext;
|
|
227
|
-
use crate::commit_store::{Change, CommitDraftRef, CommitStoreContext};
|
|
228
|
-
use crate::storage::{StorageContext, StorageWriteSet};
|
|
229
|
-
use crate::LixError;
|
|
230
|
-
|
|
231
|
-
#[tokio::test]
|
|
232
|
-
async fn reachable_commits_returns_commits_nearest_first() {
|
|
233
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
234
|
-
let storage = StorageContext::new(backend.clone());
|
|
235
|
-
append_changes(
|
|
236
|
-
storage.clone(),
|
|
237
|
-
&[
|
|
238
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
239
|
-
commit_change(
|
|
240
|
-
"commit-parent-change",
|
|
241
|
-
"commit-parent",
|
|
242
|
-
&[],
|
|
243
|
-
&["commit-root"],
|
|
244
|
-
),
|
|
245
|
-
commit_change("commit-head-change", "commit-head", &[], &["commit-parent"]),
|
|
246
|
-
],
|
|
247
|
-
)
|
|
248
|
-
.await;
|
|
249
|
-
|
|
250
|
-
let graph = CommitGraphContext::new();
|
|
251
|
-
let mut reader = graph.reader(storage);
|
|
252
|
-
let commits = reader
|
|
253
|
-
.reachable_commits("commit-head")
|
|
254
|
-
.await
|
|
255
|
-
.expect("reachable commits should load");
|
|
256
|
-
|
|
257
|
-
assert_eq!(
|
|
258
|
-
commits
|
|
259
|
-
.iter()
|
|
260
|
-
.map(|reachable| (reachable.commit.commit_id.as_str(), reachable.depth))
|
|
261
|
-
.collect::<Vec<_>>(),
|
|
262
|
-
vec![("commit-head", 0), ("commit-parent", 1), ("commit-root", 2)]
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
#[tokio::test]
|
|
267
|
-
async fn reachable_commits_errors_on_missing_parent_commit() {
|
|
268
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
269
|
-
let storage = StorageContext::new(backend.clone());
|
|
270
|
-
append_changes(
|
|
271
|
-
storage.clone(),
|
|
272
|
-
&[commit_change(
|
|
273
|
-
"commit-head-change",
|
|
274
|
-
"commit-head",
|
|
275
|
-
&[],
|
|
276
|
-
&["missing-parent"],
|
|
277
|
-
)],
|
|
278
|
-
)
|
|
279
|
-
.await;
|
|
280
|
-
|
|
281
|
-
let graph = CommitGraphContext::new();
|
|
282
|
-
let mut reader = graph.reader(storage);
|
|
283
|
-
let error = reader
|
|
284
|
-
.reachable_commits("commit-head")
|
|
285
|
-
.await
|
|
286
|
-
.expect_err("missing parent should fail");
|
|
287
|
-
|
|
288
|
-
assert!(error.message.contains("missing-parent"));
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
#[tokio::test]
|
|
292
|
-
async fn reachable_commits_errors_on_cycle() {
|
|
293
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
294
|
-
let storage = StorageContext::new(backend.clone());
|
|
295
|
-
append_changes(
|
|
296
|
-
storage.clone(),
|
|
297
|
-
&[
|
|
298
|
-
commit_change("commit-a-change", "commit-a", &[], &["commit-b"]),
|
|
299
|
-
commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
|
|
300
|
-
],
|
|
301
|
-
)
|
|
302
|
-
.await;
|
|
303
|
-
|
|
304
|
-
let graph = CommitGraphContext::new();
|
|
305
|
-
let mut reader = graph.reader(storage);
|
|
306
|
-
let error = reader
|
|
307
|
-
.reachable_commits("commit-a")
|
|
308
|
-
.await
|
|
309
|
-
.expect_err("cycle should fail");
|
|
310
|
-
|
|
311
|
-
assert!(error.message.contains("cycle"));
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
#[tokio::test]
|
|
315
|
-
async fn reachable_commits_dedupes_shared_ancestors_in_diamond() {
|
|
316
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
317
|
-
let storage = StorageContext::new(backend.clone());
|
|
318
|
-
append_changes(
|
|
319
|
-
storage.clone(),
|
|
320
|
-
&[
|
|
321
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
322
|
-
commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
|
|
323
|
-
commit_change("commit-right-change", "commit-right", &[], &["commit-root"]),
|
|
324
|
-
commit_change(
|
|
325
|
-
"commit-head-change",
|
|
326
|
-
"commit-head",
|
|
327
|
-
&[],
|
|
328
|
-
&["commit-left", "commit-right"],
|
|
329
|
-
),
|
|
330
|
-
],
|
|
331
|
-
)
|
|
332
|
-
.await;
|
|
333
|
-
|
|
334
|
-
let graph = CommitGraphContext::new();
|
|
335
|
-
let mut reader = graph.reader(storage);
|
|
336
|
-
let commits = reader
|
|
337
|
-
.reachable_commits("commit-head")
|
|
338
|
-
.await
|
|
339
|
-
.expect("reachable commits should load");
|
|
340
|
-
|
|
341
|
-
assert_eq!(
|
|
342
|
-
commits
|
|
343
|
-
.iter()
|
|
344
|
-
.map(|reachable| (reachable.commit.commit_id.as_str(), reachable.depth))
|
|
345
|
-
.collect::<Vec<_>>(),
|
|
346
|
-
vec![
|
|
347
|
-
("commit-head", 0),
|
|
348
|
-
("commit-left", 1),
|
|
349
|
-
("commit-right", 1),
|
|
350
|
-
("commit-root", 2),
|
|
351
|
-
]
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
#[tokio::test]
|
|
356
|
-
async fn reachable_commits_keeps_nearest_depth_for_multiple_paths() {
|
|
357
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
358
|
-
let storage = StorageContext::new(backend.clone());
|
|
359
|
-
append_changes(
|
|
360
|
-
storage.clone(),
|
|
361
|
-
&[
|
|
362
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
363
|
-
commit_change(
|
|
364
|
-
"commit-parent-change",
|
|
365
|
-
"commit-parent",
|
|
366
|
-
&[],
|
|
367
|
-
&["commit-root"],
|
|
368
|
-
),
|
|
369
|
-
commit_change(
|
|
370
|
-
"commit-head-change",
|
|
371
|
-
"commit-head",
|
|
372
|
-
&[],
|
|
373
|
-
&["commit-root", "commit-parent"],
|
|
374
|
-
),
|
|
375
|
-
],
|
|
376
|
-
)
|
|
377
|
-
.await;
|
|
378
|
-
|
|
379
|
-
let graph = CommitGraphContext::new();
|
|
380
|
-
let mut reader = graph.reader(storage);
|
|
381
|
-
let commits = reader
|
|
382
|
-
.reachable_commits("commit-head")
|
|
383
|
-
.await
|
|
384
|
-
.expect("reachable commits should load");
|
|
385
|
-
|
|
386
|
-
assert_eq!(
|
|
387
|
-
commits
|
|
388
|
-
.iter()
|
|
389
|
-
.map(|reachable| (reachable.commit.commit_id.as_str(), reachable.depth))
|
|
390
|
-
.collect::<Vec<_>>(),
|
|
391
|
-
vec![("commit-head", 0), ("commit-parent", 1), ("commit-root", 1)]
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
#[tokio::test]
|
|
396
|
-
async fn reachable_commits_orders_same_depth_commits_by_id() {
|
|
397
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
398
|
-
let storage = StorageContext::new(backend.clone());
|
|
399
|
-
append_changes(
|
|
400
|
-
storage.clone(),
|
|
401
|
-
&[
|
|
402
|
-
commit_change("commit-z-change", "commit-z", &[], &[]),
|
|
403
|
-
commit_change("commit-a-change", "commit-a", &[], &[]),
|
|
404
|
-
commit_change(
|
|
405
|
-
"commit-head-change",
|
|
406
|
-
"commit-head",
|
|
407
|
-
&[],
|
|
408
|
-
&["commit-z", "commit-a"],
|
|
409
|
-
),
|
|
410
|
-
],
|
|
411
|
-
)
|
|
412
|
-
.await;
|
|
413
|
-
|
|
414
|
-
let graph = CommitGraphContext::new();
|
|
415
|
-
let mut reader = graph.reader(storage);
|
|
416
|
-
let commits = reader
|
|
417
|
-
.reachable_commits("commit-head")
|
|
418
|
-
.await
|
|
419
|
-
.expect("reachable commits should load");
|
|
420
|
-
|
|
421
|
-
assert_eq!(
|
|
422
|
-
commits
|
|
423
|
-
.iter()
|
|
424
|
-
.map(|reachable| (reachable.commit.commit_id.as_str(), reachable.depth))
|
|
425
|
-
.collect::<Vec<_>>(),
|
|
426
|
-
vec![("commit-head", 0), ("commit-a", 1), ("commit-z", 1)]
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
#[tokio::test]
|
|
431
|
-
async fn reachable_commits_errors_on_missing_head_commit() {
|
|
432
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
433
|
-
let storage = StorageContext::new(backend.clone());
|
|
434
|
-
let graph = CommitGraphContext::new();
|
|
435
|
-
let mut reader = graph.reader(storage);
|
|
436
|
-
|
|
437
|
-
let error = reader
|
|
438
|
-
.reachable_commits("missing-head")
|
|
439
|
-
.await
|
|
440
|
-
.expect_err("missing head should fail");
|
|
441
|
-
|
|
442
|
-
assert!(error.message.contains("missing-head"));
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
#[tokio::test]
|
|
446
|
-
async fn best_common_ancestors_returns_nearest_common_commit_in_simple_graph() {
|
|
447
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
448
|
-
let storage = StorageContext::new(backend.clone());
|
|
449
|
-
append_changes(
|
|
450
|
-
storage.clone(),
|
|
451
|
-
&[
|
|
452
|
-
commit_change("commit-a-change", "commit-a", &[], &[]),
|
|
453
|
-
commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
|
|
454
|
-
commit_change("commit-c-change", "commit-c", &[], &["commit-b"]),
|
|
455
|
-
commit_change("commit-d-change", "commit-d", &[], &["commit-b"]),
|
|
456
|
-
],
|
|
457
|
-
)
|
|
458
|
-
.await;
|
|
459
|
-
|
|
460
|
-
let graph = CommitGraphContext::new();
|
|
461
|
-
let mut reader = graph.reader(storage);
|
|
462
|
-
let ancestors = reader
|
|
463
|
-
.best_common_ancestors("commit-c", "commit-d")
|
|
464
|
-
.await
|
|
465
|
-
.expect("best common ancestors should load");
|
|
466
|
-
|
|
467
|
-
assert_eq!(
|
|
468
|
-
ancestors
|
|
469
|
-
.iter()
|
|
470
|
-
.map(|commit| commit.commit_id.as_str())
|
|
471
|
-
.collect::<Vec<_>>(),
|
|
472
|
-
vec!["commit-b"]
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
#[tokio::test]
|
|
477
|
-
async fn best_common_ancestors_returns_shared_fork_in_diamond_graph() {
|
|
478
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
479
|
-
let storage = StorageContext::new(backend.clone());
|
|
480
|
-
append_changes(
|
|
481
|
-
storage.clone(),
|
|
482
|
-
&[
|
|
483
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
484
|
-
commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
|
|
485
|
-
commit_change("commit-right-change", "commit-right", &[], &["commit-root"]),
|
|
486
|
-
commit_change(
|
|
487
|
-
"commit-left-head-change",
|
|
488
|
-
"commit-left-head",
|
|
489
|
-
&[],
|
|
490
|
-
&["commit-left"],
|
|
491
|
-
),
|
|
492
|
-
commit_change(
|
|
493
|
-
"commit-right-head-change",
|
|
494
|
-
"commit-right-head",
|
|
495
|
-
&[],
|
|
496
|
-
&["commit-right"],
|
|
497
|
-
),
|
|
498
|
-
],
|
|
499
|
-
)
|
|
500
|
-
.await;
|
|
501
|
-
|
|
502
|
-
let graph = CommitGraphContext::new();
|
|
503
|
-
let mut reader = graph.reader(storage);
|
|
504
|
-
let ancestors = reader
|
|
505
|
-
.best_common_ancestors("commit-left-head", "commit-right-head")
|
|
506
|
-
.await
|
|
507
|
-
.expect("best common ancestors should load");
|
|
508
|
-
|
|
509
|
-
assert_eq!(
|
|
510
|
-
ancestors
|
|
511
|
-
.iter()
|
|
512
|
-
.map(|commit| commit.commit_id.as_str())
|
|
513
|
-
.collect::<Vec<_>>(),
|
|
514
|
-
vec!["commit-root"]
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
#[tokio::test]
|
|
519
|
-
async fn best_common_ancestors_returns_parent_when_one_side_is_ancestor() {
|
|
520
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
521
|
-
let storage = StorageContext::new(backend.clone());
|
|
522
|
-
append_changes(
|
|
523
|
-
storage.clone(),
|
|
524
|
-
&[
|
|
525
|
-
commit_change("commit-a-change", "commit-a", &[], &[]),
|
|
526
|
-
commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
|
|
527
|
-
commit_change("commit-c-change", "commit-c", &[], &["commit-b"]),
|
|
528
|
-
],
|
|
529
|
-
)
|
|
530
|
-
.await;
|
|
531
|
-
|
|
532
|
-
let graph = CommitGraphContext::new();
|
|
533
|
-
let mut reader = graph.reader(storage);
|
|
534
|
-
let ancestors = reader
|
|
535
|
-
.best_common_ancestors("commit-b", "commit-c")
|
|
536
|
-
.await
|
|
537
|
-
.expect("best common ancestors should load");
|
|
538
|
-
|
|
539
|
-
assert_eq!(
|
|
540
|
-
ancestors
|
|
541
|
-
.iter()
|
|
542
|
-
.map(|commit| commit.commit_id.as_str())
|
|
543
|
-
.collect::<Vec<_>>(),
|
|
544
|
-
vec!["commit-b"]
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
#[tokio::test]
|
|
549
|
-
async fn best_common_ancestors_returns_multiple_bases_for_criss_cross_graph() {
|
|
550
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
551
|
-
let storage = StorageContext::new(backend.clone());
|
|
552
|
-
append_changes(
|
|
553
|
-
storage.clone(),
|
|
554
|
-
&[
|
|
555
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
556
|
-
commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
|
|
557
|
-
commit_change("commit-right-change", "commit-right", &[], &["commit-root"]),
|
|
558
|
-
commit_change(
|
|
559
|
-
"commit-head-left-change",
|
|
560
|
-
"commit-head-left",
|
|
561
|
-
&[],
|
|
562
|
-
&["commit-left", "commit-right"],
|
|
563
|
-
),
|
|
564
|
-
commit_change(
|
|
565
|
-
"commit-head-right-change",
|
|
566
|
-
"commit-head-right",
|
|
567
|
-
&[],
|
|
568
|
-
&["commit-right", "commit-left"],
|
|
569
|
-
),
|
|
570
|
-
],
|
|
571
|
-
)
|
|
572
|
-
.await;
|
|
573
|
-
|
|
574
|
-
let graph = CommitGraphContext::new();
|
|
575
|
-
let mut reader = graph.reader(storage);
|
|
576
|
-
let ancestors = reader
|
|
577
|
-
.best_common_ancestors("commit-head-left", "commit-head-right")
|
|
578
|
-
.await
|
|
579
|
-
.expect("best common ancestors should load");
|
|
580
|
-
|
|
581
|
-
assert_eq!(
|
|
582
|
-
ancestors
|
|
583
|
-
.iter()
|
|
584
|
-
.map(|commit| commit.commit_id.as_str())
|
|
585
|
-
.collect::<Vec<_>>(),
|
|
586
|
-
vec!["commit-left", "commit-right"]
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
#[tokio::test]
|
|
591
|
-
async fn merge_base_returns_single_best_common_ancestor() {
|
|
592
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
593
|
-
let storage = StorageContext::new(backend.clone());
|
|
594
|
-
append_changes(
|
|
595
|
-
storage.clone(),
|
|
596
|
-
&[
|
|
597
|
-
commit_change("commit-a-change", "commit-a", &[], &[]),
|
|
598
|
-
commit_change("commit-b-change", "commit-b", &[], &["commit-a"]),
|
|
599
|
-
commit_change("commit-c-change", "commit-c", &[], &["commit-b"]),
|
|
600
|
-
commit_change("commit-d-change", "commit-d", &[], &["commit-b"]),
|
|
601
|
-
],
|
|
602
|
-
)
|
|
603
|
-
.await;
|
|
604
|
-
|
|
605
|
-
let graph = CommitGraphContext::new();
|
|
606
|
-
let mut reader = graph.reader(storage);
|
|
607
|
-
let base = reader
|
|
608
|
-
.merge_base("commit-c", "commit-d")
|
|
609
|
-
.await
|
|
610
|
-
.expect("single merge base should resolve");
|
|
611
|
-
|
|
612
|
-
assert_eq!(base.commit_id, "commit-b");
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
#[tokio::test]
|
|
616
|
-
async fn merge_base_errors_when_histories_have_no_common_commit() {
|
|
617
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
618
|
-
let storage = StorageContext::new(backend.clone());
|
|
619
|
-
append_changes(
|
|
620
|
-
storage.clone(),
|
|
621
|
-
&[
|
|
622
|
-
commit_change("commit-left-change", "commit-left", &[], &[]),
|
|
623
|
-
commit_change("commit-right-change", "commit-right", &[], &[]),
|
|
624
|
-
],
|
|
625
|
-
)
|
|
626
|
-
.await;
|
|
627
|
-
|
|
628
|
-
let graph = CommitGraphContext::new();
|
|
629
|
-
let mut reader = graph.reader(storage);
|
|
630
|
-
let error = reader
|
|
631
|
-
.merge_base("commit-left", "commit-right")
|
|
632
|
-
.await
|
|
633
|
-
.expect_err("unrelated histories should not have a merge base");
|
|
634
|
-
|
|
635
|
-
assert!(error.message.contains("no common history"));
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
#[tokio::test]
|
|
639
|
-
async fn merge_base_errors_when_best_common_ancestor_is_ambiguous() {
|
|
640
|
-
let backend = Arc::new(UnitTestBackend::new());
|
|
641
|
-
let storage = StorageContext::new(backend.clone());
|
|
642
|
-
append_changes(
|
|
643
|
-
storage.clone(),
|
|
644
|
-
&[
|
|
645
|
-
commit_change("commit-root-change", "commit-root", &[], &[]),
|
|
646
|
-
commit_change("commit-left-change", "commit-left", &[], &["commit-root"]),
|
|
647
|
-
commit_change("commit-right-change", "commit-right", &[], &["commit-root"]),
|
|
648
|
-
commit_change(
|
|
649
|
-
"commit-head-left-change",
|
|
650
|
-
"commit-head-left",
|
|
651
|
-
&[],
|
|
652
|
-
&["commit-left", "commit-right"],
|
|
653
|
-
),
|
|
654
|
-
commit_change(
|
|
655
|
-
"commit-head-right-change",
|
|
656
|
-
"commit-head-right",
|
|
657
|
-
&[],
|
|
658
|
-
&["commit-right", "commit-left"],
|
|
659
|
-
),
|
|
660
|
-
],
|
|
661
|
-
)
|
|
662
|
-
.await;
|
|
663
|
-
|
|
664
|
-
let graph = CommitGraphContext::new();
|
|
665
|
-
let mut reader = graph.reader(storage);
|
|
666
|
-
let error = reader
|
|
667
|
-
.merge_base("commit-head-left", "commit-head-right")
|
|
668
|
-
.await
|
|
669
|
-
.expect_err("ambiguous best common ancestors should fail");
|
|
670
|
-
|
|
671
|
-
assert_eq!(error.code, LixError::CODE_AMBIGUOUS_MERGE_BASE);
|
|
672
|
-
assert_eq!(
|
|
673
|
-
error
|
|
674
|
-
.details
|
|
675
|
-
.as_ref()
|
|
676
|
-
.and_then(|details| details.get("left_commit_id")),
|
|
677
|
-
Some(&json!("commit-head-left"))
|
|
678
|
-
);
|
|
679
|
-
assert_eq!(
|
|
680
|
-
error
|
|
681
|
-
.details
|
|
682
|
-
.as_ref()
|
|
683
|
-
.and_then(|details| details.get("right_commit_id")),
|
|
684
|
-
Some(&json!("commit-head-right"))
|
|
685
|
-
);
|
|
686
|
-
assert_eq!(
|
|
687
|
-
error
|
|
688
|
-
.details
|
|
689
|
-
.as_ref()
|
|
690
|
-
.and_then(|details| details.get("candidates")),
|
|
691
|
-
Some(&json!(["commit-left", "commit-right"]))
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
#[derive(Clone)]
|
|
696
|
-
struct TestCommitChange {
|
|
697
|
-
change: Change,
|
|
698
|
-
parent_commit_ids: Vec<String>,
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
async fn append_changes(storage: StorageContext, changes: &[TestCommitChange]) {
|
|
702
|
-
let mut tx = storage
|
|
703
|
-
.begin_write_transaction()
|
|
704
|
-
.await
|
|
705
|
-
.expect("transaction should open");
|
|
706
|
-
let mut writes = StorageWriteSet::new();
|
|
707
|
-
let commit_store = CommitStoreContext::new();
|
|
708
|
-
for change in changes {
|
|
709
|
-
let commit_id = change
|
|
710
|
-
.change
|
|
711
|
-
.entity_id
|
|
712
|
-
.as_single_string()
|
|
713
|
-
.expect("commit fixture should have single id")
|
|
714
|
-
.to_string();
|
|
715
|
-
let author_account_ids = Vec::new();
|
|
716
|
-
let commit = CommitDraftRef {
|
|
717
|
-
id: &commit_id,
|
|
718
|
-
change_id: &change.change.id,
|
|
719
|
-
parent_ids: &change.parent_commit_ids,
|
|
720
|
-
author_account_ids: &author_account_ids,
|
|
721
|
-
created_at: &change.change.created_at,
|
|
722
|
-
};
|
|
723
|
-
commit_store
|
|
724
|
-
.writer(tx.as_mut(), &mut writes)
|
|
725
|
-
.stage_commit_draft(commit, Vec::new(), Vec::new())
|
|
726
|
-
.await
|
|
727
|
-
.expect("commit-store fixture should append");
|
|
728
|
-
}
|
|
729
|
-
writes
|
|
730
|
-
.apply(&mut tx.as_mut())
|
|
731
|
-
.await
|
|
732
|
-
.expect("writes should apply");
|
|
733
|
-
tx.commit().await.expect("commit should succeed");
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
fn commit_change(
|
|
737
|
-
change_id: &str,
|
|
738
|
-
commit_id: &str,
|
|
739
|
-
change_ids: &[&str],
|
|
740
|
-
parent_commit_ids: &[&str],
|
|
741
|
-
) -> TestCommitChange {
|
|
742
|
-
let _ = change_ids;
|
|
743
|
-
TestCommitChange {
|
|
744
|
-
change: Change {
|
|
745
|
-
id: change_id.to_string(),
|
|
746
|
-
entity_id: crate::entity_identity::EntityIdentity::single(commit_id),
|
|
747
|
-
schema_key: "lix_commit".to_string(),
|
|
748
|
-
file_id: None,
|
|
749
|
-
snapshot_ref: None,
|
|
750
|
-
metadata_ref: None,
|
|
751
|
-
created_at: "2026-01-01T00:00:00Z".to_string(),
|
|
752
|
-
},
|
|
753
|
-
parent_commit_ids: parent_commit_ids.iter().map(|id| id.to_string()).collect(),
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|