Skip to content

Commit 0cec6b5

Browse files
authored
Merge pull request #26 from keepsimple1/new-design
radicle-surf: refactoring the design - part 1
2 parents 93d92ed + cd9132c commit 0cec6b5

File tree

13 files changed

+414
-1387
lines changed

13 files changed

+414
-1387
lines changed

radicle-surf/benches/last_commit.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
1919
use radicle_surf::{
2020
file_system::{unsound, Path},
21-
vcs::git::{Branch, Browser, Repository},
21+
vcs::git::{Branch, Repository, Rev},
2222
};
2323

2424
fn last_commit_comparison(c: &mut Criterion) {
2525
let repo = Repository::new("./data/git-platinum")
2626
.expect("Could not retrieve ./data/git-platinum as git repository");
27-
let browser =
28-
Browser::new(&repo, Branch::local("master")).expect("Could not initialise Browser");
27+
let rev: Rev = Branch::local("master").into();
2928

3029
let mut group = c.benchmark_group("Last Commit");
3130
for path in [
@@ -36,7 +35,7 @@ fn last_commit_comparison(c: &mut Criterion) {
3635
.iter()
3736
{
3837
group.bench_with_input(BenchmarkId::new("", path), path, |b, path| {
39-
b.iter(|| browser.last_commit(path.clone()))
38+
b.iter(|| repo.as_ref().last_commit(path.clone(), &rev))
4039
});
4140
}
4241
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# An updated design for radicle-surf
2+
3+
Now we have ported the `radicle-surf` crate from its own github repo to be part of the `radicle-git` repo. We are taking this opportunity to refactor its design as well. Intuitively, `radicle-surf` provides an API so that one can use it to create a github-like UI for a git repo:
4+
5+
- Given a commit (or other types of ref), list the content: i.e. files and directories.
6+
- Generate a diff between two commits.
7+
- List the history of the commits.
8+
- List refs: Branches, Tags.
9+
10+
The main goals of the changes are:
11+
12+
- make API simpler whenever possible.
13+
- address open issues in the original `radicle-surf` repo as much as possible.
14+
- not to shy away from being `git` specific. (i.e. not to consider supporting other VCS systems)
15+
16+
## Make API simpler
17+
18+
The current API has quite a bit accidental complexity that is not inherent with the requirements, especially when we can be git specific and don't care about other VCS systems.
19+
20+
### Remove the `Browser`
21+
22+
The type `Browser` is awkward as of today:
23+
24+
- it is not a source of truth of any information. For example, `list_branches` method is just a wrapper of `Repository::list_branches`.
25+
- it takes in `History`, but really works at the `Snapshot` level.
26+
- it is mutable but its state does not help much.
27+
28+
Can we just remove `Browser` and implement its functionalities using other types?
29+
30+
- For iteratoring the history, use `History`.
31+
- For generating `Directory`, use `Repository` directly given a `Rev`.
32+
- For accessing `Branch`, `Tag` or `Commit`, use `Repository`.
33+
34+
## Remove the `Snapshot`
35+
36+
A `Snapshot` should be really just a tree (or `Directory`) of a `Commit` in git. Currently it is a function that returns a `Directory`. Because it is OK to be git specific, we don't need to have this generic function to create a snapshot across different VCS systems.
37+
38+
The only `snapshot` function defined currently:
39+
40+
```Rust
41+
let snapshot = Box::new(|repository: &RepositoryRef<'a>, history: &History| {
42+
let tree = Self::get_tree(repository.repo_ref, history.0.first())?;
43+
Ok(directory::Directory::from_hash_map(tree))
44+
});
45+
```
46+
47+
The above function can be easily implement as a method of `Repository`.

radicle-surf/examples/diff.rs

Lines changed: 8 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,20 @@ extern crate radicle_surf;
1919

2020
use std::{env::Args, str::FromStr, time::Instant};
2121

22-
use nonempty::NonEmpty;
23-
2422
use radicle_git_ext::Oid;
25-
use radicle_surf::{
26-
diff::Diff,
27-
file_system::Directory,
28-
vcs::{git, History},
29-
};
23+
use radicle_surf::{diff::Diff, vcs::git};
3024

3125
fn main() {
3226
let options = get_options_or_exit();
3327
let repo = init_repository_or_exit(&options.path_to_repo);
34-
let mut browser =
35-
git::Browser::new(&repo, git::Branch::local("master")).expect("failed to create browser:");
36-
37-
match options.head_revision {
38-
HeadRevision::Head => {
39-
reset_browser_to_head_or_exit(&mut browser);
40-
},
41-
HeadRevision::Commit(id) => {
42-
set_browser_history_or_exit(&mut browser, &id);
43-
},
44-
}
45-
let head_directory = get_directory_or_exit(&browser);
46-
47-
set_browser_history_or_exit(&mut browser, &options.base_revision);
48-
let base_directory = get_directory_or_exit(&browser);
49-
28+
let head_oid = match options.head_revision {
29+
HeadRevision::Head => repo.as_ref().head_oid().unwrap(),
30+
HeadRevision::Commit(id) => Oid::from_str(&id).unwrap(),
31+
};
32+
let base_oid = Oid::from_str(&options.base_revision).unwrap();
5033
let now = Instant::now();
5134
let elapsed_nanos = now.elapsed().as_nanos();
52-
let diff = Diff::diff(base_directory, head_directory);
35+
let diff = repo.as_ref().diff(base_oid, head_oid).unwrap();
5336
print_diff_summary(&diff, elapsed_nanos);
5437
}
5538

@@ -73,46 +56,6 @@ fn init_repository_or_exit(path_to_repo: &str) -> git::Repository {
7356
}
7457
}
7558

76-
fn reset_browser_to_head_or_exit(browser: &mut git::Browser) {
77-
if let Err(e) = browser.head() {
78-
println!("Failed to set browser to HEAD: {:?}", e);
79-
std::process::exit(1);
80-
}
81-
}
82-
83-
fn set_browser_history_or_exit(browser: &mut git::Browser, commit_id: &str) {
84-
// TODO: Might consider to not require resetting to HEAD when history is not at
85-
// HEAD
86-
reset_browser_to_head_or_exit(browser);
87-
if let Err(e) = set_browser_history(browser, commit_id) {
88-
println!("Failed to set browser history: {:?}", e);
89-
std::process::exit(1);
90-
}
91-
}
92-
93-
fn set_browser_history(browser: &mut git::Browser, commit_id: &str) -> Result<(), String> {
94-
let oid = match Oid::from_str(commit_id) {
95-
Ok(oid) => oid,
96-
Err(e) => return Err(format!("{}", e)),
97-
};
98-
let commit = match browser.get().find_in_history(&oid, |artifact| artifact.id) {
99-
Some(commit) => commit,
100-
None => return Err(format!("Git commit not found: {}", commit_id)),
101-
};
102-
browser.set(History(NonEmpty::new(commit)));
103-
Ok(())
104-
}
105-
106-
fn get_directory_or_exit(browser: &git::Browser) -> Directory {
107-
match browser.get_directory() {
108-
Ok(dir) => dir,
109-
Err(e) => {
110-
println!("Failed to get directory: {:?}", e);
111-
std::process::exit(1)
112-
},
113-
}
114-
}
115-
11659
fn print_diff_summary(diff: &Diff, elapsed_nanos: u128) {
11760
diff.created.iter().for_each(|created| {
11861
println!("+++ {}", created.path);
@@ -131,7 +74,7 @@ fn print_diff_summary(diff: &Diff, elapsed_nanos: u128) {
13174
diff.modified.len(),
13275
diff.created.len() + diff.deleted.len() + diff.modified.len()
13376
);
134-
println!("diff took {} micros ", elapsed_nanos / 1000);
77+
println!("diff took {} nanos ", elapsed_nanos);
13578
}
13679

13780
struct Options {

radicle-surf/src/commit.rs

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ use crate::{
3030
file_system,
3131
person::Person,
3232
revision::Revision,
33-
vcs::git::{self, BranchName, Browser, Rev},
33+
vcs::{
34+
git::{self, BranchName, RepositoryRef, Rev},
35+
Vcs,
36+
},
3437
};
3538

3639
use radicle_git_ext::Oid;
@@ -141,16 +144,12 @@ pub struct Commits {
141144
///
142145
/// Will return [`Error`] if the project doesn't exist or the surf interaction
143146
/// fails.
144-
pub fn commit(browser: &mut Browser<'_>, sha1: Oid) -> Result<Commit, Error> {
145-
browser.commit(sha1)?;
146-
147-
let history = browser.get();
148-
let commit = history.first();
149-
147+
pub fn commit(repo: &RepositoryRef, sha1: Oid) -> Result<Commit, Error> {
148+
let commit = repo.get_commit(sha1)?;
150149
let diff = if let Some(parent) = commit.parents.first() {
151-
browser.diff(*parent, sha1)?
150+
repo.diff(*parent, sha1)?
152151
} else {
153-
browser.initial_diff(sha1)?
152+
repo.initial_diff(sha1)?
154153
};
155154

156155
let mut deletions = 0;
@@ -194,14 +193,14 @@ pub fn commit(browser: &mut Browser<'_>, sha1: Oid) -> Result<Commit, Error> {
194193
}
195194
}
196195

197-
let branches = browser
198-
.revision_branches(sha1)?
196+
let branches = repo
197+
.revision_branches(&sha1)?
199198
.into_iter()
200199
.map(|b| b.name)
201200
.collect();
202201

203202
Ok(Commit {
204-
header: Header::from(commit),
203+
header: Header::from(&commit),
205204
stats: Stats {
206205
additions,
207206
deletions,
@@ -217,13 +216,9 @@ pub fn commit(browser: &mut Browser<'_>, sha1: Oid) -> Result<Commit, Error> {
217216
///
218217
/// Will return [`Error`] if the project doesn't exist or the surf interaction
219218
/// fails.
220-
pub fn header(browser: &mut Browser<'_>, sha1: Oid) -> Result<Header, Error> {
221-
browser.commit(sha1)?;
222-
223-
let history = browser.get();
224-
let commit = history.first();
225-
226-
Ok(Header::from(commit))
219+
pub fn header(repo: &RepositoryRef, sha1: Oid) -> Result<Header, Error> {
220+
let commit = repo.get_commit(sha1)?;
221+
Ok(Header::from(&commit))
227222
}
228223

229224
/// Retrieves the [`Commit`] history for the given `revision`.
@@ -233,20 +228,21 @@ pub fn header(browser: &mut Browser<'_>, sha1: Oid) -> Result<Header, Error> {
233228
/// Will return [`Error`] if the project doesn't exist or the surf interaction
234229
/// fails.
235230
pub fn commits<P>(
236-
browser: &mut Browser<'_>,
231+
repo: &RepositoryRef,
237232
maybe_revision: Option<Revision<P>>,
238233
) -> Result<Commits, Error>
239234
where
240235
P: ToString,
241236
{
242237
let maybe_revision = maybe_revision.map(Rev::try_from).transpose()?;
243238

244-
if let Some(revision) = maybe_revision {
245-
browser.rev(revision)?;
246-
}
239+
let rev: Rev = match maybe_revision {
240+
Some(revision) => revision,
241+
None => repo.head_oid()?.into(),
242+
};
247243

248-
let headers = browser.get().iter().map(Header::from).collect();
249-
let stats = browser.get_stats()?;
244+
let stats = repo.get_stats(&rev)?;
245+
let headers = repo.get_history(rev)?.iter().map(Header::from).collect();
250246

251247
Ok(Commits { headers, stats })
252248
}

radicle-surf/src/object.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use serde::{
2525
};
2626

2727
pub mod blob;
28-
pub use blob::{blob, Blob, BlobContent};
28+
pub use blob::{Blob, BlobContent};
2929

3030
pub mod tree;
3131
pub use tree::{tree, Tree, TreeEntry};

radicle-surf/src/object/blob.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ use serde::{
3232
use crate::{
3333
commit,
3434
file_system,
35+
git::RepositoryRef,
3536
object::{Error, Info, ObjectType},
3637
revision::Revision,
37-
vcs::git::{Browser, Rev},
38+
vcs::git::Rev,
3839
};
3940

4041
#[cfg(feature = "syntax")]
@@ -118,18 +119,18 @@ impl Serialize for BlobContent {
118119
/// Will return [`Error`] if the project doesn't exist or a surf interaction
119120
/// fails.
120121
pub fn blob<P>(
121-
browser: &mut Browser,
122+
repo: &RepositoryRef,
122123
maybe_revision: Option<Revision<P>>,
123124
path: &str,
124125
) -> Result<Blob, Error>
125126
where
126127
P: ToString,
127128
{
128-
make_blob(browser, maybe_revision, path, content)
129+
make_blob(repo, maybe_revision, path, content)
129130
}
130131

131132
fn make_blob<P, C>(
132-
browser: &mut Browser,
133+
repo: &RepositoryRef,
133134
maybe_revision: Option<Revision<P>>,
134135
path: &str,
135136
content: C,
@@ -139,11 +140,9 @@ where
139140
C: FnOnce(&[u8]) -> BlobContent,
140141
{
141142
let maybe_revision = maybe_revision.map(Rev::try_from).transpose()?;
142-
if let Some(revision) = maybe_revision {
143-
browser.rev(revision)?;
144-
}
143+
let revision = maybe_revision.unwrap();
145144

146-
let root = browser.get_directory()?;
145+
let root = repo.snapshot(&revision)?;
147146
let p = file_system::Path::from_str(path)?;
148147

149148
let file = root
@@ -153,8 +152,8 @@ where
153152
let mut commit_path = file_system::Path::root();
154153
commit_path.append(p.clone());
155154

156-
let last_commit = browser
157-
.last_commit(commit_path)?
155+
let last_commit = repo
156+
.last_commit(commit_path, &revision)?
158157
.map(|c| commit::Header::from(&c));
159158
let (_rest, last) = p.split_last();
160159

radicle-surf/src/object/tree.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ use serde::{
2929
use crate::{
3030
commit,
3131
file_system,
32+
git::RepositoryRef,
3233
object::{Error, Info, ObjectType},
3334
revision::Revision,
34-
vcs::git::{Browser, Rev},
35+
vcs::{
36+
git::{Branch, Rev},
37+
Vcs,
38+
},
3539
};
3640

3741
/// Result of a directory listing, carries other trees and blobs.
@@ -86,7 +90,7 @@ impl Serialize for TreeEntry {
8690
///
8791
/// Will return [`Error`] if any of the surf interactions fail.
8892
pub fn tree<P>(
89-
browser: &mut Browser<'_>,
93+
repo: &RepositoryRef,
9094
maybe_revision: Option<Revision<P>>,
9195
maybe_prefix: Option<String>,
9296
) -> Result<Tree, Error>
@@ -96,17 +100,18 @@ where
96100
let maybe_revision = maybe_revision.map(Rev::try_from).transpose()?;
97101
let prefix = maybe_prefix.unwrap_or_default();
98102

99-
if let Some(revision) = maybe_revision {
100-
browser.rev(revision)?;
101-
}
103+
let rev = match maybe_revision {
104+
Some(r) => r,
105+
None => Branch::local("main").into(),
106+
};
102107

103108
let path = if prefix == "/" || prefix.is_empty() {
104109
file_system::Path::root()
105110
} else {
106111
file_system::Path::from_str(&prefix)?
107112
};
108113

109-
let root_dir = browser.get_directory()?;
114+
let root_dir = repo.snapshot(&rev)?;
110115
let prefix_dir = if path.is_root() {
111116
root_dir
112117
} else {
@@ -155,7 +160,7 @@ where
155160
entries.sort_by(|a, b| a.info.object_type.cmp(&b.info.object_type));
156161

157162
let last_commit = if path.is_root() {
158-
Some(commit::Header::from(browser.get().first()))
163+
Some(commit::Header::from(repo.get_history(rev).unwrap().first()))
159164
} else {
160165
None
161166
};

0 commit comments

Comments
 (0)