@@ -2,8 +2,9 @@ use crate::init::walk::RefsById;
2
2
use crate :: init:: { Entrypoint , Overlay } ;
3
3
use but_core:: { RefMetadata , ref_metadata} ;
4
4
use gix:: prelude:: ReferenceExt ;
5
+ use gix:: refs:: Target ;
5
6
use std:: borrow:: Cow ;
6
- use std:: collections:: BTreeSet ;
7
+ use std:: collections:: { BTreeMap , BTreeSet } ;
7
8
8
9
impl Overlay {
9
10
/// Serve the given `refs` from memory, as if they would exist.
@@ -16,13 +17,27 @@ impl Overlay {
16
17
self
17
18
}
18
19
20
+ /// Serve the given `refs` from memory, which is like creating the reference or as if its value was set,
21
+ /// completely overriding the value in the repository.
22
+ pub fn with_references ( mut self , refs : impl IntoIterator < Item = gix:: refs:: Reference > ) -> Self {
23
+ self . overriding_references . extend ( refs) ;
24
+ self
25
+ }
26
+
19
27
/// Override the starting position of the traversal by setting it to `id`,
20
28
/// and optionally, by providing the `ref_name` that points to `id`.
21
29
pub fn with_entrypoint (
22
30
mut self ,
23
31
id : gix:: ObjectId ,
24
32
ref_name : Option < gix:: refs:: FullName > ,
25
33
) -> Self {
34
+ if let Some ( ref_name) = & ref_name {
35
+ self . overriding_references . push ( gix:: refs:: Reference {
36
+ name : ref_name. to_owned ( ) ,
37
+ target : Target :: Object ( id) ,
38
+ peeled : Some ( id) ,
39
+ } )
40
+ }
26
41
self . entrypoint = Some ( ( id, ref_name) ) ;
27
42
self
28
43
}
@@ -59,13 +74,21 @@ impl Overlay {
59
74
{
60
75
let Overlay {
61
76
nonoverriding_references,
77
+ overriding_references,
62
78
meta_branches,
63
79
workspace,
64
80
entrypoint,
65
81
} = self ;
66
82
(
67
83
OverlayRepo {
68
- nonoverriding_references,
84
+ nonoverriding_references : nonoverriding_references
85
+ . into_iter ( )
86
+ . map ( |r| ( r. name . clone ( ) , r) )
87
+ . collect ( ) ,
88
+ overriding_references : overriding_references
89
+ . into_iter ( )
90
+ . map ( |r| ( r. name . clone ( ) , r) )
91
+ . collect ( ) ,
69
92
inner : repo,
70
93
} ,
71
94
OverlayMetadata {
@@ -80,7 +103,8 @@ impl Overlay {
80
103
81
104
pub ( crate ) struct OverlayRepo < ' repo > {
82
105
inner : & ' repo gix:: Repository ,
83
- nonoverriding_references : Vec < gix:: refs:: Reference > ,
106
+ nonoverriding_references : BTreeMap < gix:: refs:: FullName , gix:: refs:: Reference > ,
107
+ overriding_references : BTreeMap < gix:: refs:: FullName , gix:: refs:: Reference > ,
84
108
}
85
109
86
110
/// Note that functions with `'repo` in their return value technically leak the bare repo, and it's
@@ -94,13 +118,11 @@ impl<'repo> OverlayRepo<'repo> {
94
118
& self ,
95
119
ref_name : & gix:: refs:: FullNameRef ,
96
120
) -> anyhow:: Result < Option < gix:: Reference < ' repo > > > {
97
- if let Some ( rn) = self . inner . try_find_reference ( ref_name) ? {
121
+ if let Some ( r) = self . overriding_references . get ( ref_name) {
122
+ Ok ( Some ( r. clone ( ) . attach ( self . inner ) ) )
123
+ } else if let Some ( rn) = self . inner . try_find_reference ( ref_name) ? {
98
124
Ok ( Some ( rn) )
99
- } else if let Some ( r) = self
100
- . nonoverriding_references
101
- . iter ( )
102
- . find ( |r| r. name . as_ref ( ) == ref_name)
103
- {
125
+ } else if let Some ( r) = self . nonoverriding_references . get ( ref_name) {
104
126
Ok ( Some ( r. clone ( ) . attach ( self . inner ) ) )
105
127
} else {
106
128
Ok ( None )
@@ -111,17 +133,16 @@ impl<'repo> OverlayRepo<'repo> {
111
133
& self ,
112
134
ref_name : & gix:: refs:: FullNameRef ,
113
135
) -> anyhow:: Result < gix:: Reference < ' repo > > {
136
+ if let Some ( r) = self . overriding_references . get ( ref_name) {
137
+ return Ok ( r. clone ( ) . attach ( self . inner ) ) ;
138
+ }
114
139
Ok ( self
115
140
. inner
116
141
. find_reference ( ref_name)
117
142
. or_else ( |err| match err {
118
143
gix:: reference:: find:: existing:: Error :: Find ( _) => Err ( err) ,
119
144
gix:: reference:: find:: existing:: Error :: NotFound { .. } => {
120
- if let Some ( r) = self
121
- . nonoverriding_references
122
- . iter ( )
123
- . find ( |r| r. name . as_ref ( ) == ref_name)
124
- {
145
+ if let Some ( r) = self . nonoverriding_references . get ( ref_name) {
125
146
Ok ( r. clone ( ) . attach ( self . inner ) )
126
147
} else {
127
148
Err ( err)
@@ -202,6 +223,18 @@ impl<'repo> OverlayRepo<'repo> {
202
223
} ;
203
224
let mut all_refs_by_id = gix:: hashtable:: HashMap :: < _ , Vec < _ > > :: default ( ) ;
204
225
for prefix in prefixes {
226
+ // apply overrides - they are seen first and take the spot of everything.
227
+ for ( commit_id, git_reference) in self
228
+ . overriding_references
229
+ . values ( )
230
+ . filter ( |rn| rn. name . as_bstr ( ) . starts_with ( prefix. as_bytes ( ) ) )
231
+ . filter_map ( |rn| ref_filter ( rn. clone ( ) . attach ( self . inner ) ) )
232
+ {
233
+ all_refs_by_id
234
+ . entry ( commit_id)
235
+ . or_default ( )
236
+ . push ( git_reference) ;
237
+ }
205
238
for ( commit_id, git_reference) in self
206
239
. inner
207
240
. references ( ) ?
@@ -214,10 +247,10 @@ impl<'repo> OverlayRepo<'repo> {
214
247
. or_default ( )
215
248
. push ( git_reference) ;
216
249
}
217
- // apply overrides
250
+ // apply overrides (new only)
218
251
for ( commit_id, git_reference) in self
219
252
. nonoverriding_references
220
- . iter ( )
253
+ . values ( )
221
254
. filter ( |rn| rn. name . as_bstr ( ) . starts_with ( prefix. as_bytes ( ) ) )
222
255
. filter_map ( |rn| ref_filter ( rn. clone ( ) . attach ( self . inner ) ) )
223
256
{
0 commit comments