1
- use super :: { Change , CrateVersion } ;
2
- use std:: path:: Path ;
1
+ use crate :: { Change , CrateVersion , Index } ;
3
2
4
- use crate :: Index ;
5
- use git2:: {
6
- build:: RepoBuilder , Delta , Error as GitError , ErrorClass , Object , ObjectType , Oid , Reference ,
7
- Repository , Tree ,
8
- } ;
9
- use std:: str;
10
-
11
- static INDEX_GIT_URL : & str = "https://github.com/rust-lang/crates.io-index" ;
12
- static LAST_SEEN_REFNAME : & str = "refs/heads/crates-index-diff_last-seen" ;
13
3
static EMPTY_TREE_HASH : & str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" ;
14
4
static LINE_ADDED_INDICATOR : char = '+' ;
15
5
16
- /// Options for use in `Index::from_path_or_cloned_with_options`
17
- pub struct CloneOptions < ' a > {
18
- /// The url from which the repository should be cloned.
19
- pub repository_url : String ,
20
- /// Git2 fetch options to control exactly how to clone.
21
- pub fetch_options : Option < git2:: FetchOptions < ' a > > ,
22
- }
23
-
24
- impl < ' a > Default for CloneOptions < ' a > {
25
- fn default ( ) -> Self {
26
- CloneOptions {
27
- repository_url : INDEX_GIT_URL . into ( ) ,
28
- fetch_options : None ,
29
- }
30
- }
31
- }
32
-
33
- /// Access
34
- impl Index {
35
- /// Return the crates.io repository.
36
- pub fn repository ( & self ) -> & Repository {
37
- & self . repo
38
- }
39
-
40
- /// Return the reference pointing to the state we have seen after calling `fetch_changes()`.
41
- pub fn last_seen_reference ( & self ) -> Result < Reference < ' _ > , GitError > {
42
- self . repo . find_reference ( self . seen_ref_name )
43
- }
44
- }
45
-
46
- /// Initialization
47
- impl Index {
48
- /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
49
- /// clone of the `crates.io` index.
50
- /// If the directory does not contain the repository or does not exist, it will be cloned from
51
- /// the official location automatically (with complete history).
52
- ///
53
- /// An error will occour if the repository exists and the remote URL does not match the given repository URL.
54
- ///
55
- /// # Examples
56
- ///
57
- /// ```no_run
58
- /// use crates_index_diff::{Index, index};
59
- ///
60
- /// # let path = tempdir::TempDir::new("index").unwrap();
61
- /// let mut options = index::CloneOptions {
62
- /// repository_url: "https://github.com/rust-lang/staging.crates.io-index".into(),
63
- /// ..Default::default()
64
- /// };
65
- ///
66
- ///
67
- /// let index = Index::from_path_or_cloned_with_options(path, options)?;
68
- /// # Ok::<(), git2::Error>(())
69
- /// ```
70
- /// Or to access a private repository, use fetch options.
71
- ///
72
- /// ```no_run
73
- /// use crates_index_diff::{index, Index};
74
- /// let fo = {
75
- /// let mut fo = git2::FetchOptions::new();
76
- /// fo.remote_callbacks({
77
- /// let mut callbacks = git2::RemoteCallbacks::new();
78
- /// callbacks.credentials(|_url, username_from_url, _allowed_types| {
79
- /// git2::Cred::ssh_key_from_memory(
80
- /// username_from_url.unwrap(),
81
- /// None,
82
- /// &std::env::var("PRIVATE_KEY").unwrap(),
83
- /// None,
84
- /// )
85
- /// });
86
- /// callbacks
87
- /// });
88
- /// fo
89
- /// };
90
- /// Index::from_path_or_cloned_with_options(
91
- /// "index",
92
- /// index::CloneOptions {
93
- /// repository_url: "[email protected] :private-index/goes-here.git".into(),
94
- /// fetch_options: Some(fo),
95
- /// },
96
- /// ).unwrap();
97
- /// ```
98
- pub fn from_path_or_cloned_with_options (
99
- path : impl AsRef < Path > ,
100
- CloneOptions {
101
- repository_url,
102
- fetch_options,
103
- } : CloneOptions < ' _ > ,
104
- ) -> Result < Index , GitError > {
105
- let mut repo_did_exist = true ;
106
- let repo = Repository :: open ( path. as_ref ( ) ) . or_else ( |err| {
107
- if err. class ( ) == ErrorClass :: Repository {
108
- repo_did_exist = false ;
109
- let mut builder = RepoBuilder :: new ( ) ;
110
- if let Some ( fo) = fetch_options {
111
- builder. fetch_options ( fo) ;
112
- }
113
- builder. bare ( true ) . clone ( & repository_url, path. as_ref ( ) )
114
- } else {
115
- Err ( err)
116
- }
117
- } ) ?;
118
-
119
- if repo_did_exist {
120
- let remote = repo. find_remote ( "origin" ) ?;
121
- let actual_remote_url = remote
122
- . url ( )
123
- . ok_or_else ( || GitError :: from_str ( "did not obtain URL of remote named 'origin'" ) ) ?;
124
- if actual_remote_url != repository_url {
125
- return Err ( GitError :: from_str ( & format ! (
126
- "Actual 'origin' remote url {:#?} did not match desired one at {:#?}" ,
127
- actual_remote_url, repository_url
128
- ) ) ) ;
129
- }
130
- }
131
-
132
- Ok ( Index {
133
- repo,
134
- seen_ref_name : LAST_SEEN_REFNAME ,
135
- } )
136
- }
137
-
138
- /// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
139
- /// clone of the `crates.io` index.
140
- /// If the directory does not contain the repository or does not exist, it will be cloned from
141
- /// the official location automatically (with complete history).
142
- pub fn from_path_or_cloned ( path : impl AsRef < Path > ) -> Result < Index , GitError > {
143
- Index :: from_path_or_cloned_with_options ( path, CloneOptions :: default ( ) )
144
- }
145
- }
146
-
147
6
/// Find changes without modifying the underling repository
148
7
impl Index {
149
8
/// As `peek_changes_with_options`, but without the options.
150
- pub fn peek_changes ( & self ) -> Result < ( Vec < Change > , git2:: Oid ) , GitError > {
9
+ pub fn peek_changes ( & self ) -> Result < ( Vec < Change > , git2:: Oid ) , git2 :: Error > {
151
10
self . peek_changes_with_options ( None )
152
11
}
153
12
@@ -169,15 +28,15 @@ impl Index {
169
28
pub fn peek_changes_with_options (
170
29
& self ,
171
30
options : Option < & mut git2:: FetchOptions < ' _ > > ,
172
- ) -> Result < ( Vec < Change > , git2:: Oid ) , GitError > {
31
+ ) -> Result < ( Vec < Change > , git2:: Oid ) , git2 :: Error > {
173
32
let from = self
174
33
. last_seen_reference ( )
175
34
. and_then ( |r| {
176
35
r. target ( ) . ok_or_else ( || {
177
- GitError :: from_str ( "last-seen reference did not have a valid target" )
36
+ git2 :: Error :: from_str ( "last-seen reference did not have a valid target" )
178
37
} )
179
38
} )
180
- . or_else ( |_| Oid :: from_str ( EMPTY_TREE_HASH ) ) ?;
39
+ . or_else ( |_| git2 :: Oid :: from_str ( EMPTY_TREE_HASH ) ) ?;
181
40
let to = {
182
41
self . repo . find_remote ( "origin" ) . and_then ( |mut r| {
183
42
r. fetch (
@@ -202,12 +61,15 @@ impl Index {
202
61
/// to either `Commit`s or `Tree`s.
203
62
pub fn changes_from_objects (
204
63
& self ,
205
- from : & Object < ' _ > ,
206
- to : & Object < ' _ > ,
207
- ) -> Result < Vec < Change > , GitError > {
208
- fn into_tree < ' a > ( repo : & ' a Repository , obj : & Object < ' _ > ) -> Result < Tree < ' a > , GitError > {
64
+ from : & git2:: Object < ' _ > ,
65
+ to : & git2:: Object < ' _ > ,
66
+ ) -> Result < Vec < Change > , git2:: Error > {
67
+ fn into_tree < ' a > (
68
+ repo : & ' a git2:: Repository ,
69
+ obj : & git2:: Object < ' _ > ,
70
+ ) -> Result < git2:: Tree < ' a > , git2:: Error > {
209
71
repo. find_tree ( match obj. kind ( ) {
210
- Some ( ObjectType :: Commit ) => obj
72
+ Some ( git2 :: ObjectType :: Commit ) => obj
211
73
. as_commit ( )
212
74
. expect ( "object of kind commit yields commit" )
213
75
. tree_id ( ) ,
@@ -227,7 +89,7 @@ impl Index {
227
89
let mut deletes: Vec < String > = Vec :: new ( ) ;
228
90
diff. foreach (
229
91
& mut |delta, _| {
230
- if delta. status ( ) == Delta :: Deleted {
92
+ if delta. status ( ) == git2 :: Delta :: Deleted {
231
93
if let Some ( path) = delta. new_file ( ) . path ( ) {
232
94
if let Some ( file_name) = path. file_name ( ) {
233
95
deletes. push ( file_name. to_string_lossy ( ) . to_string ( ) ) ;
@@ -242,7 +104,7 @@ impl Index {
242
104
if diffline. origin ( ) != LINE_ADDED_INDICATOR {
243
105
return true ;
244
106
}
245
- if !matches ! ( delta. status( ) , Delta :: Added | Delta :: Modified ) {
107
+ if !matches ! ( delta. status( ) , git2 :: Delta :: Added | git2 :: Delta :: Modified ) {
246
108
return true ;
247
109
}
248
110
@@ -267,7 +129,7 @@ impl Index {
267
129
/// Find changes while changing the underlying repository in one way or another.
268
130
impl Index {
269
131
/// As `fetch_changes_with_options`, but without the options.
270
- pub fn fetch_changes ( & self ) -> Result < Vec < Change > , GitError > {
132
+ pub fn fetch_changes ( & self ) -> Result < Vec < Change > , git2 :: Error > {
271
133
self . fetch_changes_with_options ( None )
272
134
}
273
135
@@ -287,14 +149,14 @@ impl Index {
287
149
pub fn fetch_changes_with_options (
288
150
& self ,
289
151
options : Option < & mut git2:: FetchOptions < ' _ > > ,
290
- ) -> Result < Vec < Change > , GitError > {
152
+ ) -> Result < Vec < Change > , git2 :: Error > {
291
153
let ( changes, to) = self . peek_changes_with_options ( options) ?;
292
154
self . set_last_seen_reference ( to) ?;
293
155
Ok ( changes)
294
156
}
295
157
296
158
/// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
297
- pub fn set_last_seen_reference ( & self , to : Oid ) -> Result < ( ) , GitError > {
159
+ pub fn set_last_seen_reference ( & self , to : git2 :: Oid ) -> Result < ( ) , git2 :: Error > {
298
160
self . last_seen_reference ( )
299
161
. and_then ( |mut seen_ref| {
300
162
seen_ref. set_target ( to, "updating seen-ref head to latest fetched commit" )
@@ -319,7 +181,7 @@ impl Index {
319
181
& self ,
320
182
from : impl AsRef < str > ,
321
183
to : impl AsRef < str > ,
322
- ) -> Result < Vec < Change > , GitError > {
184
+ ) -> Result < Vec < Change > , git2 :: Error > {
323
185
self . changes_from_objects (
324
186
& self . repo . revparse_single ( from. as_ref ( ) ) ?,
325
187
& self . repo . revparse_single ( to. as_ref ( ) ) ?,
0 commit comments