Skip to content

Commit a43e2b4

Browse files
committed
sketch a new peek method that uses gitoxide to fetch things
1 parent ad2f6d9 commit a43e2b4

File tree

5 files changed

+129
-8
lines changed

5 files changed

+129
-8
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ include = ["src/**/*", "LICENSE.md", "README.md", "CHANGELOG.md"]
1515
test = false
1616

1717
[dependencies]
18-
git-repository = { version = "0.24.0", default-features = false, features = ["max-performance-safe"] }
18+
git-repository = { version = "0.24.0", default-features = false, features = ["max-performance-safe", "blocking-network-client", "blocking-http-transport"], git = "https://github.com/byron/gitoxide" }
1919
similar = { version = "2.2.0", features = ["bytes"] }
2020
serde = { version = "1", features = ["std", "derive"] }
2121
serde_json = "1"

src/index/diff/mod.rs

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use git_repository as git;
33
use git_repository::prelude::ObjectIdExt;
44
use git_repository::refs::transaction::PreviousValue;
55
use std::convert::TryFrom;
6+
use std::sync::atomic::AtomicBool;
67

78
mod delegate;
89
use delegate::Delegate;
@@ -12,7 +13,7 @@ use delegate::Delegate;
1213
#[allow(missing_docs)]
1314
pub enum Error {
1415
#[error("Failed to fetch crates.io index repository")]
15-
Fetch(#[from] git2::Error),
16+
FetchGit2(#[from] git2::Error),
1617
#[error("Couldn't update marker reference")]
1718
ReferenceEdit(#[from] git::reference::edit::Error),
1819
#[error("Failed to parse rev-spec to determine which revisions to diff")]
@@ -29,6 +30,18 @@ pub enum Error {
2930
file_name: bstr::BString,
3031
line: bstr::BString,
3132
},
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),
3245
}
3346

3447
/// Find changes without modifying the underling repository
@@ -63,13 +76,16 @@ impl Index {
6376
.ok()
6477
.and_then(|r| r.try_id().map(|id| id.detach()))
6578
.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");
6682
let to = {
6783
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| {
6985
r.fetch(
7086
&[format!(
7187
"+refs/heads/{branch}:refs/remotes/{remote}/{branch}",
72-
remote = self.remote_name,
88+
remote = remote_name,
7389
branch = self.branch_name,
7490
)],
7591
options,
@@ -79,7 +95,7 @@ impl Index {
7995
git::hash::ObjectId::try_from(
8096
repo.refname_to_id(&format!(
8197
"refs/remotes/{}/{}",
82-
self.remote_name, self.branch_name
98+
remote_name, self.branch_name
8399
))?
84100
.as_bytes(),
85101
)
@@ -89,6 +105,110 @@ impl Index {
89105
Ok((self.changes_between_commits(from, to)?, to))
90106
}
91107

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+
92212
/// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
93213
/// to either `Commit`s or `Tree`s.
94214
pub fn changes_between_commits(

src/index/init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl Index {
8888
repo.object_cache_size_if_unset(4 * 1024 * 1024);
8989
Ok(Index {
9090
repo,
91-
remote_name: "origin",
91+
remote_name: Some("origin"),
9292
branch_name: "master",
9393
seen_ref_name: LAST_SEEN_REFNAME,
9494
})

src/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ pub struct Index {
1212
/// The name of the branch to fetch. This value also affects the tracking branch.
1313
pub branch_name: &'static str,
1414
/// The name of the symbolic name of the remote to fetch from.
15-
pub remote_name: &'static str,
15+
/// If `None`, obtain the remote name from the configuration of the currently checked-out branch.
16+
pub remote_name: Option<&'static str>,
1617
/// The git repository to use for diffing
1718
pub(crate) repo: git::Repository,
1819
}

tests/index/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn changes_since_last_fetch() -> crate::Result {
9393

9494
// now the remote has squashed their history, we should still be able to get the correct changes.
9595
git2::Repository::open(repo.git_dir())?.remote("local", repo.git_dir().to_str().unwrap())?;
96-
index.remote_name = "local";
96+
index.remote_name = Some("local");
9797
index
9898
.repository()
9999
.find_reference("refs/heads/main")?

0 commit comments

Comments
 (0)