1
1
use anyhow:: { Context , bail} ;
2
- use but_core:: RefMetadata ;
2
+ use but_core:: { RefMetadata , ref_metadata } ;
3
3
use gix:: {
4
4
hashtable:: hash_map:: Entry ,
5
5
prelude:: { ObjectIdExt , ReferenceExt } ,
@@ -13,12 +13,22 @@ mod walk;
13
13
use walk:: * ;
14
14
15
15
pub ( crate ) mod types;
16
+ use crate :: init:: overlay:: { OverlayMetadata , OverlayRepo } ;
16
17
use types:: { Goals , Instruction , Limit , Queue } ;
17
18
18
19
mod remotes;
19
20
21
+ mod overlay;
20
22
mod post;
21
23
24
+ /// A way to define information to be served from memory, instead of from the underlying data source, when
25
+ /// [initializing](Graph::from_commit_traversal()) the graph.
26
+ #[ derive( Debug , Default ) ]
27
+ pub struct Overlay {
28
+ references : Vec < gix:: refs:: Reference > ,
29
+ meta_branches : Vec < ( gix:: refs:: FullName , ref_metadata:: Branch ) > ,
30
+ }
31
+
22
32
pub ( super ) type PetGraph = petgraph:: stable_graph:: StableGraph < Segment , Edge > ;
23
33
24
34
/// Options for use in [`Graph::from_head()`] and [`Graph::from_commit_traversal()`].
@@ -123,9 +133,12 @@ impl Graph {
123
133
let ( tip, maybe_name) = match head. kind {
124
134
gix:: head:: Kind :: Unborn ( ref_name) => {
125
135
let mut graph = Graph :: default ( ) ;
136
+ // It's OK to default-initialise this here as overlays are only used when redoing
137
+ // the traversal.
138
+ let ( _repo, meta) = Overlay :: default ( ) . into_parts ( repo, meta) ;
126
139
graph. insert_root ( branch_segment_from_name_and_meta (
127
140
Some ( ( ref_name, None ) ) ,
128
- meta,
141
+ & meta,
129
142
None ,
130
143
) ?) ;
131
144
return Ok ( graph) ;
@@ -208,6 +221,19 @@ impl Graph {
208
221
ref_name : impl Into < Option < gix:: refs:: FullName > > ,
209
222
meta : & impl RefMetadata ,
210
223
options : Options ,
224
+ ) -> anyhow:: Result < Self > {
225
+ let ( repo, meta) = Overlay :: default ( ) . into_parts ( tip. repo , meta) ;
226
+ // TODO: use repo
227
+ Graph :: from_commit_traversal_inner ( tip. detach ( ) , tip. repo , ref_name, & meta, options)
228
+ }
229
+
230
+ fn from_commit_traversal_inner < T : RefMetadata > (
231
+ tip : gix:: ObjectId ,
232
+ // repo: &OverlayRepo<'_>,
233
+ repo : & gix:: Repository ,
234
+ ref_name : impl Into < Option < gix:: refs:: FullName > > ,
235
+ meta : & OverlayMetadata < ' _ , T > ,
236
+ options : Options ,
211
237
) -> anyhow:: Result < Self > {
212
238
let mut graph = Graph {
213
239
options : options. clone ( ) ,
@@ -221,7 +247,6 @@ impl Graph {
221
247
hard_limit,
222
248
} = options;
223
249
224
- let repo = tip. repo ;
225
250
let max_limit = Limit :: new ( limit) ;
226
251
// TODO: also traverse (outside)-branches that ought to be in the workspace. That way we have the desired ones
227
252
// automatically and just have to find a way to prune the undesired ones.
@@ -255,7 +280,7 @@ impl Graph {
255
280
// The tip transports itself.
256
281
let tip_flags = CommitFlags :: NotInRemote
257
282
| goals
258
- . flag_for ( tip. detach ( ) )
283
+ . flag_for ( tip)
259
284
. expect ( "we more than one bitflags for this" ) ;
260
285
261
286
let target_symbolic_remote_names = {
@@ -288,10 +313,10 @@ impl Graph {
288
313
let current = graph. insert_root ( branch_segment_from_name_and_meta (
289
314
ref_name. clone ( ) . map ( |rn| ( rn, None ) ) ,
290
315
meta,
291
- Some ( ( & ctx. refs_by_id , tip. detach ( ) ) ) ,
316
+ Some ( ( & ctx. refs_by_id , tip) ) ,
292
317
) ?) ;
293
318
_ = next. push_back_exhausted ( (
294
- tip. detach ( ) ,
319
+ tip,
295
320
tip_flags,
296
321
Instruction :: CollectCommit { into : current } ,
297
322
max_limit,
@@ -331,7 +356,7 @@ impl Graph {
331
356
} else {
332
357
(
333
358
CommitFlags :: empty ( ) ,
334
- max_limit. with_indirect_goal ( tip. detach ( ) , & mut goals) ,
359
+ max_limit. with_indirect_goal ( tip, & mut goals) ,
335
360
)
336
361
} ;
337
362
let mut ws_segment =
@@ -374,10 +399,10 @@ impl Graph {
374
399
CommitFlags :: NotInRemote | goal,
375
400
Instruction :: CollectCommit { into : local_sidx } ,
376
401
max_limit
377
- . with_indirect_goal ( tip. detach ( ) , & mut goals)
402
+ . with_indirect_goal ( tip, & mut goals)
378
403
. without_allowance ( ) ,
379
404
) ) ;
380
- next. add_goal_to ( tip. detach ( ) , goal) ;
405
+ next. add_goal_to ( tip, goal) ;
381
406
( Some ( local_sidx) , goal)
382
407
} else {
383
408
( None , CommitFlags :: empty ( ) )
@@ -391,7 +416,7 @@ impl Graph {
391
416
// Once the goal was found, be done immediately,
392
417
// we are not interested in these.
393
418
max_limit
394
- . with_indirect_goal ( tip. detach ( ) , & mut goals)
419
+ . with_indirect_goal ( tip, & mut goals)
395
420
. additional_goal ( local_goal)
396
421
. without_allowance ( ) ,
397
422
) ) ;
@@ -421,7 +446,7 @@ impl Graph {
421
446
into : extra_target_sidx,
422
447
} ,
423
448
max_limit
424
- . with_indirect_goal ( tip. detach ( ) , & mut goals)
449
+ . with_indirect_goal ( tip, & mut goals)
425
450
. without_allowance ( ) ,
426
451
) ) ;
427
452
extra_target_sidx
@@ -571,7 +596,7 @@ impl Graph {
571
596
limit,
572
597
) ;
573
598
if hard_limit_hit {
574
- return graph. post_processed ( meta, tip. detach ( ) , ctx. with_hard_limit ( ) ) ;
599
+ return graph. post_processed ( meta, tip, ctx. with_hard_limit ( ) ) ;
575
600
}
576
601
577
602
segment. commits . push (
@@ -592,14 +617,36 @@ impl Graph {
592
617
593
618
for item in remote_items {
594
619
if next. push_back_exhausted ( item) {
595
- return graph. post_processed ( meta, tip. detach ( ) , ctx. with_hard_limit ( ) ) ;
620
+ return graph. post_processed ( meta, tip, ctx. with_hard_limit ( ) ) ;
596
621
}
597
622
}
598
623
599
624
prune_integrated_tips ( & mut graph, & mut next) ;
600
625
}
601
626
602
- graph. post_processed ( meta, tip. detach ( ) , ctx)
627
+ graph. post_processed ( meta, tip, ctx)
628
+ }
629
+
630
+ /// Repeat the traversal that generated this graph using `repo` and `meta`, but allow to set an in-memory
631
+ /// `overlay` to amend the data available from `repo` and `meta`.
632
+ /// This way, one can see this graph as it will be in the future once the changes to `repo` and `meta` are actually made.
633
+ pub fn redo_traversal_with_overlay (
634
+ & self ,
635
+ repo : & gix:: Repository ,
636
+ meta : & impl RefMetadata ,
637
+ overlay : Overlay ,
638
+ ) -> anyhow:: Result < Self > {
639
+ let ( _repo, meta) = overlay. into_parts ( repo, meta) ;
640
+ let tip_sidx = self
641
+ . entrypoint
642
+ . context ( "BUG: entrypoint must always be set" ) ?
643
+ . 0 ;
644
+ let tip = self
645
+ . tip_skip_empty ( tip_sidx)
646
+ . context ( "BUG: entrypoint must eventually point to a commit" ) ?
647
+ . id ;
648
+ let ref_name = self [ tip_sidx] . ref_name . clone ( ) ;
649
+ Graph :: from_commit_traversal_inner ( tip, repo, ref_name, & meta, self . options . clone ( ) )
603
650
}
604
651
}
605
652
0 commit comments