@@ -3,6 +3,7 @@ use git_repository as git;
3
3
use git_repository:: prelude:: ObjectIdExt ;
4
4
use git_repository:: refs:: transaction:: PreviousValue ;
5
5
use std:: convert:: TryFrom ;
6
+ use std:: sync:: atomic:: AtomicBool ;
6
7
7
8
mod delegate;
8
9
use delegate:: Delegate ;
@@ -12,7 +13,7 @@ use delegate::Delegate;
12
13
#[ allow( missing_docs) ]
13
14
pub enum Error {
14
15
#[ error( "Failed to fetch crates.io index repository" ) ]
15
- Fetch ( #[ from] git2:: Error ) ,
16
+ FetchGit2 ( #[ from] git2:: Error ) ,
16
17
#[ error( "Couldn't update marker reference" ) ]
17
18
ReferenceEdit ( #[ from] git:: reference:: edit:: Error ) ,
18
19
#[ error( "Failed to parse rev-spec to determine which revisions to diff" ) ]
@@ -29,6 +30,18 @@ pub enum Error {
29
30
file_name : bstr:: BString ,
30
31
line : bstr:: BString ,
31
32
} ,
33
+ #[ error( transparent) ]
34
+ FindRemote ( #[ from] git:: remote:: find:: existing:: Error ) ,
35
+ #[ error( transparent) ]
36
+ FindReference ( #[ from] git:: reference:: find:: existing:: Error ) ,
37
+ #[ error( transparent) ]
38
+ Connect ( #[ from] git:: remote:: connect:: Error ) ,
39
+ #[ error( transparent) ]
40
+ PrepareFetch ( #[ from] git:: remote:: fetch:: prepare:: Error ) ,
41
+ #[ error( transparent) ]
42
+ Fetch ( #[ from] git:: remote:: fetch:: Error ) ,
43
+ #[ error( transparent) ]
44
+ InitAnonymousRemote ( #[ from] git:: remote:: init:: Error ) ,
32
45
}
33
46
34
47
/// Find changes without modifying the underling repository
@@ -63,13 +76,16 @@ impl Index {
63
76
. ok ( )
64
77
. and_then ( |r| r. try_id ( ) . map ( |id| id. detach ( ) ) )
65
78
. unwrap_or_else ( || git:: hash:: ObjectId :: empty_tree ( repo. object_hash ( ) ) ) ;
79
+ let remote_name = self
80
+ . remote_name
81
+ . expect ( "always set for this old portion of the code" ) ;
66
82
let to = {
67
83
let repo = git2:: Repository :: open ( repo. git_dir ( ) ) ?;
68
- repo. find_remote ( self . remote_name ) . and_then ( |mut r| {
84
+ repo. find_remote ( remote_name) . and_then ( |mut r| {
69
85
r. fetch (
70
86
& [ format ! (
71
87
"+refs/heads/{branch}:refs/remotes/{remote}/{branch}" ,
72
- remote = self . remote_name,
88
+ remote = remote_name,
73
89
branch = self . branch_name,
74
90
) ] ,
75
91
options,
@@ -79,7 +95,7 @@ impl Index {
79
95
git:: hash:: ObjectId :: try_from (
80
96
repo. refname_to_id ( & format ! (
81
97
"refs/remotes/{}/{}" ,
82
- self . remote_name, self . branch_name
98
+ remote_name, self . branch_name
83
99
) ) ?
84
100
. as_bytes ( ) ,
85
101
)
@@ -89,6 +105,110 @@ impl Index {
89
105
Ok ( ( self . changes_between_commits ( from, to) ?, to) )
90
106
}
91
107
108
+ /// Return all `Change`s that are observed between the last time `peek_changes*(…)` was called
109
+ /// and the latest state of the `crates.io` index repository, which is obtained by fetching
110
+ /// the remote called `origin` or whatever is configured for the current `HEAD` branch.
111
+ /// The `last_seen_reference()` will not be created or updated.
112
+ /// The second field in the returned tuple is the commit object to which the changes were provided.
113
+ /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
114
+ /// as if `fetch_changes(…)` had been called.
115
+ ///
116
+ /// # Resource Usage
117
+ ///
118
+ /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
119
+ /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
120
+ /// of the maximum number of open file handles as configured with `ulimit`.
121
+ ///
122
+ /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
123
+ // TODO: update this once it's clear how auto-gc works in `gitoxide`.
124
+ pub fn peek_changes_with_options2 (
125
+ & self ,
126
+ progress : impl git:: Progress ,
127
+ should_interrupt : & AtomicBool ,
128
+ ) -> Result < ( Vec < Change > , git:: hash:: ObjectId ) , Error > {
129
+ let repo = & self . repo ;
130
+ let from = repo
131
+ . find_reference ( self . seen_ref_name )
132
+ . ok ( )
133
+ . and_then ( |r| r. try_id ( ) . map ( |id| id. detach ( ) ) )
134
+ . unwrap_or_else ( || git:: hash:: ObjectId :: empty_tree ( repo. object_hash ( ) ) ) ;
135
+ let to = {
136
+ let remote = self
137
+ . remote_name
138
+ . and_then ( |name| {
139
+ self . repo . find_remote ( name) . ok ( ) . or_else ( || {
140
+ self . repo
141
+ . head ( )
142
+ . ok ( )
143
+ . and_then ( |head| {
144
+ head. into_remote ( git:: remote:: Direction :: Fetch )
145
+ . map ( |r| r. ok ( ) )
146
+ . flatten ( )
147
+ } )
148
+ . or_else ( || {
149
+ self . repo
150
+ . find_default_remote ( git:: remote:: Direction :: Fetch )
151
+ . map ( |r| r. ok ( ) )
152
+ . flatten ( )
153
+ } )
154
+ } )
155
+ } )
156
+ . map ( Ok )
157
+ . unwrap_or_else ( || {
158
+ self . repo
159
+ . head ( ) ?
160
+ . into_remote ( git:: remote:: Direction :: Fetch )
161
+ . map ( |r| r. map_err ( Error :: from) )
162
+ . or_else ( || {
163
+ self . repo
164
+ . find_default_remote ( git:: remote:: Direction :: Fetch )
165
+ . map ( |r| r. map_err ( Error :: from) )
166
+ } )
167
+ . unwrap_or_else ( || {
168
+ let spec = format ! (
169
+ "+refs/heads/{branch}:refs/remotes/{remote}/{branch}" ,
170
+ remote = self . remote_name. unwrap_or( "origin" ) ,
171
+ branch = self . branch_name,
172
+ ) ;
173
+ self . repo
174
+ . remote_at ( "https://github.com/rust-lang/crates.io-index" )
175
+ . map_err ( Into :: into)
176
+ . map ( |r| {
177
+ r. with_refspec ( spec. as_str ( ) , git:: remote:: Direction :: Fetch )
178
+ . expect ( "valid refspec" )
179
+ } )
180
+ } )
181
+ } ) ?;
182
+ let res: git:: remote:: fetch:: Outcome < ' _ > = remote
183
+ . connect ( git:: remote:: Direction :: Fetch , progress) ?
184
+ . prepare_fetch ( Default :: default ( ) ) ?
185
+ . receive ( should_interrupt) ?;
186
+ // let repo = git2::Repository::open(repo.git_dir())?;
187
+ // repo.find_remote(self.remote_name).and_then(|mut r| {
188
+ // r.fetch(
189
+ // &[format!(
190
+ // "+refs/heads/{branch}:refs/remotes/{remote}/{branch}",
191
+ // remote = self.remote_name,
192
+ // branch = self.branch_name,
193
+ // )],
194
+ // options,
195
+ // None,
196
+ // )
197
+ todo ! ( )
198
+ } ;
199
+ // git::hash::ObjectId::try_from(
200
+ // repo.refname_to_id(&format!(
201
+ // "refs/remotes/{}/{}",
202
+ // self.remote_name, self.branch_name
203
+ // ))?
204
+ // .as_bytes(),
205
+ // )
206
+ // .expect("valid oid")
207
+ // };
208
+
209
+ Ok ( ( self . changes_between_commits ( from, to) ?, to) )
210
+ }
211
+
92
212
/// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
93
213
/// to either `Commit`s or `Tree`s.
94
214
pub fn changes_between_commits (
0 commit comments