1
1
use std:: collections:: BTreeSet ;
2
2
3
- use gix_hash:: ObjectId ;
4
-
5
3
use crate :: {
6
4
packed, peel,
7
5
raw:: Reference ,
8
6
store_impl:: { file, file:: log} ,
9
7
Target ,
10
8
} ;
9
+ use gix_hash:: ObjectId ;
11
10
12
11
pub trait Sealed { }
13
12
impl Sealed for crate :: Reference { }
@@ -22,16 +21,17 @@ pub trait ReferenceExt: Sealed {
22
21
23
22
/// Follow all symbolic targets this reference might point to and peel the underlying object
24
23
/// to the end of the tag-chain, returning the first non-tag object the annotated tag points to,
25
- /// using `objects` to access them.
24
+ /// using `objects` to access them and `store` to lookup symbolic references .
26
25
///
27
- /// This is useful to learn where this reference is ultimately pointing to.
26
+ /// This is useful to learn where this reference is ultimately pointing to after following all symbolic
27
+ /// refs and all annotated tags to the first non-tag object.
28
28
fn peel_to_id_in_place (
29
29
& mut self ,
30
30
store : & file:: Store ,
31
31
objects : & dyn gix_object:: Find ,
32
32
) -> Result < ObjectId , peel:: to_id:: Error > ;
33
33
34
- /// Like [`ReferenceExt::peel_to_id_in_place()`], but with support for a known stable packed buffer
34
+ /// Like [`ReferenceExt::peel_to_id_in_place()`], but with support for a known stable ` packed` buffer
35
35
/// to use for resolving symbolic links.
36
36
fn peel_to_id_in_place_packed (
37
37
& mut self ,
@@ -40,6 +40,14 @@ pub trait ReferenceExt: Sealed {
40
40
packed : Option < & packed:: Buffer > ,
41
41
) -> Result < ObjectId , peel:: to_id:: Error > ;
42
42
43
+ /// Like [`ReferenceExt::follow()`], but follows all symbolic references while gracefully handling loops,
44
+ /// altering this instance in place.
45
+ fn follow_to_object_in_place_packed (
46
+ & mut self ,
47
+ store : & file:: Store ,
48
+ packed : Option < & packed:: Buffer > ,
49
+ ) -> Result < ObjectId , peel:: to_object:: Error > ;
50
+
43
51
/// Follow this symbolic reference one level and return the ref it refers to.
44
52
///
45
53
/// Returns `None` if this is not a symbolic reference, hence the leaf of the chain.
@@ -77,7 +85,9 @@ impl ReferenceExt for Reference {
77
85
objects : & dyn gix_object:: Find ,
78
86
) -> Result < ObjectId , peel:: to_id:: Error > {
79
87
let packed = store. assure_packed_refs_uptodate ( ) . map_err ( |err| {
80
- peel:: to_id:: Error :: Follow ( file:: find:: existing:: Error :: Find ( file:: find:: Error :: PackedOpen ( err) ) )
88
+ peel:: to_id:: Error :: FollowToObject ( peel:: to_object:: Error :: Follow ( file:: find:: existing:: Error :: Find (
89
+ file:: find:: Error :: PackedOpen ( err) ,
90
+ ) ) )
81
91
} ) ?;
82
92
self . peel_to_id_in_place_packed ( store, objects, packed. as_ref ( ) . map ( |b| & * * * b) )
83
93
}
@@ -94,28 +104,8 @@ impl ReferenceExt for Reference {
94
104
Ok ( peeled)
95
105
}
96
106
None => {
97
- if self . target . kind ( ) == crate :: Kind :: Symbolic {
98
- let mut seen = BTreeSet :: new ( ) ;
99
- let cursor = & mut * self ;
100
- while let Some ( next) = cursor. follow_packed ( store, packed) {
101
- let next = next?;
102
- if seen. contains ( & next. name ) {
103
- return Err ( peel:: to_id:: Error :: Cycle {
104
- start_absolute : store. reference_path ( cursor. name . as_ref ( ) ) ,
105
- } ) ;
106
- }
107
- * cursor = next;
108
- seen. insert ( cursor. name . clone ( ) ) ;
109
- const MAX_REF_DEPTH : usize = 5 ;
110
- if seen. len ( ) == MAX_REF_DEPTH {
111
- return Err ( peel:: to_id:: Error :: DepthLimitExceeded {
112
- max_depth : MAX_REF_DEPTH ,
113
- } ) ;
114
- }
115
- }
116
- } ;
107
+ let mut oid = self . follow_to_object_in_place_packed ( store, packed) ?;
117
108
let mut buf = Vec :: new ( ) ;
118
- let mut oid = self . target . try_id ( ) . expect ( "peeled ref" ) . to_owned ( ) ;
119
109
let peeled_id = loop {
120
110
let gix_object:: Data { kind, data } =
121
111
objects
@@ -143,6 +133,38 @@ impl ReferenceExt for Reference {
143
133
}
144
134
}
145
135
136
+ fn follow_to_object_in_place_packed (
137
+ & mut self ,
138
+ store : & file:: Store ,
139
+ packed : Option < & packed:: Buffer > ,
140
+ ) -> Result < ObjectId , peel:: to_object:: Error > {
141
+ match self . target {
142
+ Target :: Object ( id) => Ok ( id) ,
143
+ Target :: Symbolic ( _) => {
144
+ let mut seen = BTreeSet :: new ( ) ;
145
+ let cursor = & mut * self ;
146
+ while let Some ( next) = cursor. follow_packed ( store, packed) {
147
+ let next = next?;
148
+ if seen. contains ( & next. name ) {
149
+ return Err ( peel:: to_object:: Error :: Cycle {
150
+ start_absolute : store. reference_path ( cursor. name . as_ref ( ) ) ,
151
+ } ) ;
152
+ }
153
+ * cursor = next;
154
+ seen. insert ( cursor. name . clone ( ) ) ;
155
+ const MAX_REF_DEPTH : usize = 5 ;
156
+ if seen. len ( ) == MAX_REF_DEPTH {
157
+ return Err ( peel:: to_object:: Error :: DepthLimitExceeded {
158
+ max_depth : MAX_REF_DEPTH ,
159
+ } ) ;
160
+ }
161
+ }
162
+ let oid = self . target . try_id ( ) . expect ( "peeled ref" ) . to_owned ( ) ;
163
+ Ok ( oid)
164
+ }
165
+ }
166
+ }
167
+
146
168
fn follow ( & self , store : & file:: Store ) -> Option < Result < Reference , file:: find:: existing:: Error > > {
147
169
let packed = match store
148
170
. assure_packed_refs_uptodate ( )
@@ -159,21 +181,14 @@ impl ReferenceExt for Reference {
159
181
store : & file:: Store ,
160
182
packed : Option < & packed:: Buffer > ,
161
183
) -> Option < Result < Reference , file:: find:: existing:: Error > > {
162
- match self . peeled {
163
- Some ( peeled) => Some ( Ok ( Reference {
164
- name : self . name . clone ( ) ,
165
- target : Target :: Object ( peeled) ,
166
- peeled : None ,
167
- } ) ) ,
168
- None => match & self . target {
169
- Target :: Object ( _) => None ,
170
- Target :: Symbolic ( full_name) => match store. try_find_packed ( full_name. as_ref ( ) , packed) {
171
- Ok ( Some ( next) ) => Some ( Ok ( next) ) ,
172
- Ok ( None ) => Some ( Err ( file:: find:: existing:: Error :: NotFound {
173
- name : full_name. to_path ( ) . to_owned ( ) ,
174
- } ) ) ,
175
- Err ( err) => Some ( Err ( file:: find:: existing:: Error :: Find ( err) ) ) ,
176
- } ,
184
+ match & self . target {
185
+ Target :: Object ( _) => None ,
186
+ Target :: Symbolic ( full_name) => match store. try_find_packed ( full_name. as_ref ( ) , packed) {
187
+ Ok ( Some ( next) ) => Some ( Ok ( next) ) ,
188
+ Ok ( None ) => Some ( Err ( file:: find:: existing:: Error :: NotFound {
189
+ name : full_name. to_path ( ) . to_owned ( ) ,
190
+ } ) ) ,
191
+ Err ( err) => Some ( Err ( file:: find:: existing:: Error :: Find ( err) ) ) ,
177
192
} ,
178
193
}
179
194
}
0 commit comments