Skip to content

Commit 0c77e40

Browse files
committed
refactor (#16)
1 parent 78e05bd commit 0c77e40

File tree

3 files changed

+161
-157
lines changed

3 files changed

+161
-157
lines changed

src/index.rs renamed to src/index/diff.rs

Lines changed: 19 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,12 @@
1-
use super::{Change, CrateVersion};
2-
use std::path::Path;
1+
use crate::{Change, CrateVersion, Index};
32

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";
133
static EMPTY_TREE_HASH: &str = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
144
static LINE_ADDED_INDICATOR: char = '+';
155

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-
1476
/// Find changes without modifying the underling repository
1487
impl Index {
1498
/// 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> {
15110
self.peek_changes_with_options(None)
15211
}
15312

@@ -169,15 +28,15 @@ impl Index {
16928
pub fn peek_changes_with_options(
17029
&self,
17130
options: Option<&mut git2::FetchOptions<'_>>,
172-
) -> Result<(Vec<Change>, git2::Oid), GitError> {
31+
) -> Result<(Vec<Change>, git2::Oid), git2::Error> {
17332
let from = self
17433
.last_seen_reference()
17534
.and_then(|r| {
17635
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")
17837
})
17938
})
180-
.or_else(|_| Oid::from_str(EMPTY_TREE_HASH))?;
39+
.or_else(|_| git2::Oid::from_str(EMPTY_TREE_HASH))?;
18140
let to = {
18241
self.repo.find_remote("origin").and_then(|mut r| {
18342
r.fetch(
@@ -202,12 +61,15 @@ impl Index {
20261
/// to either `Commit`s or `Tree`s.
20362
pub fn changes_from_objects(
20463
&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> {
20971
repo.find_tree(match obj.kind() {
210-
Some(ObjectType::Commit) => obj
72+
Some(git2::ObjectType::Commit) => obj
21173
.as_commit()
21274
.expect("object of kind commit yields commit")
21375
.tree_id(),
@@ -227,7 +89,7 @@ impl Index {
22789
let mut deletes: Vec<String> = Vec::new();
22890
diff.foreach(
22991
&mut |delta, _| {
230-
if delta.status() == Delta::Deleted {
92+
if delta.status() == git2::Delta::Deleted {
23193
if let Some(path) = delta.new_file().path() {
23294
if let Some(file_name) = path.file_name() {
23395
deletes.push(file_name.to_string_lossy().to_string());
@@ -242,7 +104,7 @@ impl Index {
242104
if diffline.origin() != LINE_ADDED_INDICATOR {
243105
return true;
244106
}
245-
if !matches!(delta.status(), Delta::Added | Delta::Modified) {
107+
if !matches!(delta.status(), git2::Delta::Added | git2::Delta::Modified) {
246108
return true;
247109
}
248110

@@ -267,7 +129,7 @@ impl Index {
267129
/// Find changes while changing the underlying repository in one way or another.
268130
impl Index {
269131
/// 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> {
271133
self.fetch_changes_with_options(None)
272134
}
273135

@@ -287,14 +149,14 @@ impl Index {
287149
pub fn fetch_changes_with_options(
288150
&self,
289151
options: Option<&mut git2::FetchOptions<'_>>,
290-
) -> Result<Vec<Change>, GitError> {
152+
) -> Result<Vec<Change>, git2::Error> {
291153
let (changes, to) = self.peek_changes_with_options(options)?;
292154
self.set_last_seen_reference(to)?;
293155
Ok(changes)
294156
}
295157

296158
/// 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> {
298160
self.last_seen_reference()
299161
.and_then(|mut seen_ref| {
300162
seen_ref.set_target(to, "updating seen-ref head to latest fetched commit")
@@ -319,7 +181,7 @@ impl Index {
319181
&self,
320182
from: impl AsRef<str>,
321183
to: impl AsRef<str>,
322-
) -> Result<Vec<Change>, GitError> {
184+
) -> Result<Vec<Change>, git2::Error> {
323185
self.changes_from_objects(
324186
&self.repo.revparse_single(from.as_ref())?,
325187
&self.repo.revparse_single(to.as_ref())?,

src/index/init.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use crate::index::{CloneOptions, LAST_SEEN_REFNAME};
2+
use crate::Index;
3+
use std::path::Path;
4+
5+
/// Initialization
6+
impl Index {
7+
/// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
8+
/// clone of the `crates.io` index.
9+
/// If the directory does not contain the repository or does not exist, it will be cloned from
10+
/// the official location automatically (with complete history).
11+
///
12+
/// An error will occour if the repository exists and the remote URL does not match the given repository URL.
13+
///
14+
/// # Examples
15+
///
16+
/// ```no_run
17+
/// use crates_index_diff::{Index, index};
18+
///
19+
/// # let path = tempdir::TempDir::new("index").unwrap();
20+
/// let mut options = index::CloneOptions {
21+
/// repository_url: "https://github.com/rust-lang/staging.crates.io-index".into(),
22+
/// ..Default::default()
23+
/// };
24+
///
25+
///
26+
/// let index = Index::from_path_or_cloned_with_options(path, options)?;
27+
/// # Ok::<(), git2::Error>(())
28+
/// ```
29+
/// Or to access a private repository, use fetch options.
30+
///
31+
/// ```no_run
32+
/// use crates_index_diff::{index, Index};
33+
/// let fo = {
34+
/// let mut fo = git2::FetchOptions::new();
35+
/// fo.remote_callbacks({
36+
/// let mut callbacks = git2::RemoteCallbacks::new();
37+
/// callbacks.credentials(|_url, username_from_url, _allowed_types| {
38+
/// git2::Cred::ssh_key_from_memory(
39+
/// username_from_url.unwrap(),
40+
/// None,
41+
/// &std::env::var("PRIVATE_KEY").unwrap(),
42+
/// None,
43+
/// )
44+
/// });
45+
/// callbacks
46+
/// });
47+
/// fo
48+
/// };
49+
/// Index::from_path_or_cloned_with_options(
50+
/// "index",
51+
/// index::CloneOptions {
52+
/// repository_url: "[email protected]:private-index/goes-here.git".into(),
53+
/// fetch_options: Some(fo),
54+
/// },
55+
/// ).unwrap();
56+
/// ```
57+
pub fn from_path_or_cloned_with_options(
58+
path: impl AsRef<Path>,
59+
CloneOptions {
60+
repository_url,
61+
fetch_options,
62+
}: CloneOptions<'_>,
63+
) -> Result<Index, git2::Error> {
64+
let mut repo_did_exist = true;
65+
let repo = git2::Repository::open(path.as_ref()).or_else(|err| {
66+
if err.class() == git2::ErrorClass::Repository {
67+
repo_did_exist = false;
68+
let mut builder = git2::build::RepoBuilder::new();
69+
if let Some(fo) = fetch_options {
70+
builder.fetch_options(fo);
71+
}
72+
builder.bare(true).clone(&repository_url, path.as_ref())
73+
} else {
74+
Err(err)
75+
}
76+
})?;
77+
78+
if repo_did_exist {
79+
let remote = repo.find_remote("origin")?;
80+
let actual_remote_url = remote.url().ok_or_else(|| {
81+
git2::Error::from_str("did not obtain URL of remote named 'origin'")
82+
})?;
83+
if actual_remote_url != repository_url {
84+
return Err(git2::Error::from_str(&format!(
85+
"Actual 'origin' remote url {:#?} did not match desired one at {:#?}",
86+
actual_remote_url, repository_url
87+
)));
88+
}
89+
}
90+
91+
Ok(Index {
92+
repo,
93+
seen_ref_name: LAST_SEEN_REFNAME,
94+
})
95+
}
96+
97+
/// Return a new `Index` instance from the given `path`, which should contain a bare or non-bare
98+
/// clone of the `crates.io` index.
99+
/// If the directory does not contain the repository or does not exist, it will be cloned from
100+
/// the official location automatically (with complete history).
101+
pub fn from_path_or_cloned(path: impl AsRef<Path>) -> Result<Index, git2::Error> {
102+
Index::from_path_or_cloned_with_options(path, CloneOptions::default())
103+
}
104+
}

src/index/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::Index;
2+
use std::str;
3+
4+
static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";
5+
static LAST_SEEN_REFNAME: &str = "refs/heads/crates-index-diff_last-seen";
6+
7+
/// Options for use in `Index::from_path_or_cloned_with_options`
8+
pub struct CloneOptions<'a> {
9+
/// The url from which the repository should be cloned.
10+
pub repository_url: String,
11+
/// Git2 fetch options to control exactly how to clone.
12+
pub fetch_options: Option<git2::FetchOptions<'a>>,
13+
}
14+
15+
impl<'a> Default for CloneOptions<'a> {
16+
fn default() -> Self {
17+
CloneOptions {
18+
repository_url: INDEX_GIT_URL.into(),
19+
fetch_options: None,
20+
}
21+
}
22+
}
23+
24+
/// Access
25+
impl Index {
26+
/// Return the crates.io repository.
27+
pub fn repository(&self) -> &git2::Repository {
28+
&self.repo
29+
}
30+
31+
/// Return the reference pointing to the state we have seen after calling `fetch_changes()`.
32+
pub fn last_seen_reference(&self) -> Result<git2::Reference<'_>, git2::Error> {
33+
self.repo.find_reference(self.seen_ref_name)
34+
}
35+
}
36+
37+
mod diff;
38+
mod init;

0 commit comments

Comments
 (0)