1
- use std:: fmt:: { self , Debug , Formatter } ;
2
-
3
- use log:: trace;
4
- use url:: Url ;
5
-
6
1
use crate :: core:: source:: { MaybePackage , Source , SourceId } ;
7
2
use crate :: core:: GitReference ;
8
3
use crate :: core:: { Dependency , Package , PackageId , Summary } ;
9
- use crate :: sources:: git:: utils:: { GitRemote , GitRevision } ;
4
+ use crate :: sources:: git:: utils:: GitRemote ;
10
5
use crate :: sources:: PathSource ;
11
6
use crate :: util:: errors:: CargoResult ;
12
7
use crate :: util:: hex:: short_hash;
13
8
use crate :: util:: Config ;
9
+ use anyhow:: Context ;
10
+ use log:: trace;
11
+ use std:: fmt:: { self , Debug , Formatter } ;
12
+ use url:: Url ;
14
13
15
14
pub struct GitSource < ' cfg > {
16
15
remote : GitRemote ,
17
- reference : GitReference ,
16
+ manifest_reference : GitReference ,
17
+ locked_rev : Option < git2:: Oid > ,
18
18
source_id : SourceId ,
19
19
path_source : Option < PathSource < ' cfg > > ,
20
- rev : Option < GitRevision > ,
21
20
ident : String ,
22
21
config : & ' cfg Config ,
23
22
}
@@ -29,17 +28,17 @@ impl<'cfg> GitSource<'cfg> {
29
28
let remote = GitRemote :: new ( source_id. url ( ) ) ;
30
29
let ident = ident ( & source_id) ;
31
30
32
- let reference = match source_id. precise ( ) {
33
- Some ( s) => GitReference :: Rev ( s. to_string ( ) ) ,
34
- None => source_id. git_reference ( ) . unwrap ( ) . clone ( ) ,
35
- } ;
36
-
37
31
let source = GitSource {
38
32
remote,
39
- reference,
33
+ manifest_reference : source_id. git_reference ( ) . unwrap ( ) . clone ( ) ,
34
+ locked_rev : match source_id. precise ( ) {
35
+ Some ( s) => Some ( git2:: Oid :: from_str ( s) . with_context ( || {
36
+ format ! ( "precise value for git is not a git revision: {}" , s)
37
+ } ) ?) ,
38
+ None => None ,
39
+ } ,
40
40
source_id,
41
41
path_source : None ,
42
- rev : None ,
43
42
ident,
44
43
config,
45
44
} ;
@@ -76,7 +75,7 @@ impl<'cfg> Debug for GitSource<'cfg> {
76
75
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
77
76
write ! ( f, "git repo at {}" , self . remote. url( ) ) ?;
78
77
79
- match self . reference . pretty_ref ( ) {
78
+ match self . manifest_reference . pretty_ref ( ) {
80
79
Some ( s) => write ! ( f, " ({})" , s) ,
81
80
None => Ok ( ( ) ) ,
82
81
}
@@ -117,52 +116,70 @@ impl<'cfg> Source for GitSource<'cfg> {
117
116
let git_path = self . config . assert_package_cache_locked ( & git_path) ;
118
117
let db_path = git_path. join ( "db" ) . join ( & self . ident ) ;
119
118
120
- if self . config . offline ( ) && !db_path. exists ( ) {
121
- anyhow:: bail!(
122
- "can't checkout from '{}': you are in the offline mode (--offline)" ,
123
- self . remote. url( )
124
- ) ;
125
- }
126
-
127
- // Resolve our reference to an actual revision, and check if the
128
- // database already has that revision. If it does, we just load a
129
- // database pinned at that revision, and if we don't we issue an update
130
- // to try to find the revision.
131
- let actual_rev = self . remote . rev_for ( & db_path, & self . reference ) ;
132
- let should_update = actual_rev. is_err ( ) || self . source_id . precise ( ) . is_none ( ) ;
133
-
134
- let ( db, actual_rev) = if should_update && !self . config . offline ( ) {
135
- self . config . shell ( ) . status (
136
- "Updating" ,
137
- format ! ( "git repository `{}`" , self . remote. url( ) ) ,
138
- ) ?;
139
-
140
- trace ! ( "updating git source `{:?}`" , self . remote) ;
141
-
142
- self . remote
143
- . checkout ( & db_path, & self . reference , self . config ) ?
144
- } else {
145
- ( self . remote . db_at ( & db_path) ?, actual_rev. unwrap ( ) )
119
+ let db = self . remote . db_at ( & db_path) . ok ( ) ;
120
+ let ( db, actual_rev) = match ( self . locked_rev , db) {
121
+ // If we have a locked revision, and we have a preexisting database
122
+ // which has that revision, then no update needs to happen.
123
+ ( Some ( rev) , Some ( db) ) if db. contains ( rev) => ( db, rev) ,
124
+
125
+ // If we're in offline mode, we're not locked, and we have a
126
+ // database, then try to resolve our reference with the preexisting
127
+ // repository.
128
+ ( None , Some ( db) ) if self . config . offline ( ) => {
129
+ let rev = db. resolve ( & self . manifest_reference ) . with_context ( || {
130
+ "failed to lookup reference in preexisting repository, and \
131
+ can't check for updates in offline mode (--offline)"
132
+ } ) ?;
133
+ ( db, rev)
134
+ }
135
+
136
+ // ... otherwise we use this state to update the git database. Note
137
+ // that we still check for being offline here, for example in the
138
+ // situation that we have a locked revision but the database
139
+ // doesn't have it.
140
+ ( locked_rev, db) => {
141
+ if self . config . offline ( ) {
142
+ anyhow:: bail!(
143
+ "can't checkout from '{}': you are in the offline mode (--offline)" ,
144
+ self . remote. url( )
145
+ ) ;
146
+ }
147
+ self . config . shell ( ) . status (
148
+ "Updating" ,
149
+ format ! ( "git repository `{}`" , self . remote. url( ) ) ,
150
+ ) ?;
151
+
152
+ trace ! ( "updating git source `{:?}`" , self . remote) ;
153
+
154
+ self . remote . checkout (
155
+ & db_path,
156
+ db,
157
+ & self . manifest_reference ,
158
+ locked_rev,
159
+ self . config ,
160
+ ) ?
161
+ }
146
162
} ;
147
163
148
164
// Don’t use the full hash, in order to contribute less to reaching the
149
165
// path length limit on Windows. See
150
166
// <https://github.com/servo/servo/pull/14397>.
151
- let short_id = db. to_short_id ( & actual_rev) . unwrap ( ) ;
167
+ let short_id = db. to_short_id ( actual_rev) ? ;
152
168
169
+ // Check out `actual_rev` from the database to a scoped location on the
170
+ // filesystem. This will use hard links and such to ideally make the
171
+ // checkout operation here pretty fast.
153
172
let checkout_path = git_path
154
173
. join ( "checkouts" )
155
174
. join ( & self . ident )
156
175
. join ( short_id. as_str ( ) ) ;
157
-
158
- // Copy the database to the checkout location.
159
176
db. copy_to ( actual_rev. clone ( ) , & checkout_path, self . config ) ?;
160
177
161
178
let source_id = self . source_id . with_precise ( Some ( actual_rev. to_string ( ) ) ) ;
162
179
let path_source = PathSource :: new_recursive ( & checkout_path, source_id, self . config ) ;
163
180
164
181
self . path_source = Some ( path_source) ;
165
- self . rev = Some ( actual_rev) ;
182
+ self . locked_rev = Some ( actual_rev) ;
166
183
self . path_source . as_mut ( ) . unwrap ( ) . update ( )
167
184
}
168
185
@@ -183,7 +200,7 @@ impl<'cfg> Source for GitSource<'cfg> {
183
200
}
184
201
185
202
fn fingerprint ( & self , _pkg : & Package ) -> CargoResult < String > {
186
- Ok ( self . rev . as_ref ( ) . unwrap ( ) . to_string ( ) )
203
+ Ok ( self . locked_rev . as_ref ( ) . unwrap ( ) . to_string ( ) )
187
204
}
188
205
189
206
fn describe ( & self ) -> String {
0 commit comments