remote-helper: Run sync on `git-fetch`
Changes the behavior of `git fetch` by running a radicle network-level fetch (ie. `rad sync --fetch`) before fetching refs from storage. This avoids having to run `rad sync` before `git fetch`; and tries to make sure that refs are always fresh.
This commit is contained in:
parent
7e32f91ea2
commit
b482ae85f0
|
|
@ -13,6 +13,7 @@ f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 refs/heads/master
|
||||||
|
|
||||||
``` (stderr)
|
``` (stderr)
|
||||||
$ git fetch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
$ git fetch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|
✓ Synced with 1 peer(s)
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
* [new branch] alice/1 -> alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/alice/1
|
* [new branch] alice/1 -> alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/alice/1
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,6 @@ As Alice, we fetch that code, but commit on top of our own master, which is no
|
||||||
longer canonical, since Bob pushed a more recent commit, and the threshold is 1:
|
longer canonical, since Bob pushed a more recent commit, and the threshold is 1:
|
||||||
|
|
||||||
``` ~alice
|
``` ~alice
|
||||||
$ rad sync --fetch
|
|
||||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
|
||||||
✓ Fetched repository from 1 seed(s)
|
|
||||||
$ git fetch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
$ git fetch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
$ git branch -arv
|
$ git branch -arv
|
||||||
bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master 319a7dc Third commit
|
bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master 319a7dc Third commit
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ remote of the project.
|
||||||
|
|
||||||
For the remote-tracking branch to work, we fetch bob:
|
For the remote-tracking branch to work, we fetch bob:
|
||||||
|
|
||||||
``` (stderr)
|
``` RAD_SOCKET=/dev/null (stderr)
|
||||||
$ git fetch bob
|
$ git fetch bob
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
* [new branch] master -> bob/master
|
* [new branch] master -> bob/master
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
Back to being the project maintainer.
|
Back to being the project maintainer.
|
||||||
|
|
||||||
Changes have been proposed by another person (or peer) via a radicle patch. To follow changes by another, we must 'track' them.
|
Changes have been proposed by another person (or peer) via a radicle patch. To
|
||||||
|
follow changes by another, we must 'track' them.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad track did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias bob
|
$ rad track did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias bob
|
||||||
✓ Tracking policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob)
|
✓ Tracking policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob)
|
||||||
$ rad sync --fetch
|
|
||||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
|
||||||
✓ Fetched repository from 1 seed(s)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Additionally, we need to add a new 'git remote' to our working copy for the
|
Additionally, we need to add a new 'git remote' to our working copy for the
|
||||||
|
|
@ -21,6 +19,7 @@ $ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob
|
||||||
|
|
||||||
``` (stderr)
|
``` (stderr)
|
||||||
$ git fetch bob
|
$ git fetch bob
|
||||||
|
✓ Synced with 1 peer(s)
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
* [new branch] master -> bob/master
|
* [new branch] master -> bob/master
|
||||||
* [new branch] patches/69e881c606639691330051d7d8f013854f32fb87 -> bob/patches/69e881c606639691330051d7d8f013854f32fb87
|
* [new branch] patches/69e881c606639691330051d7d8f013854f32fb87 -> bob/patches/69e881c606639691330051d7d8f013854f32fb87
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Now let's checkout `master` and pull the maintainer's changes:
|
||||||
$ git checkout master
|
$ git checkout master
|
||||||
Your branch is up to date with 'rad/master'.
|
Your branch is up to date with 'rad/master'.
|
||||||
```
|
```
|
||||||
``` (stderr)
|
``` (stderr) RAD_SOCKET=/dev/null
|
||||||
$ git pull --all --ff
|
$ git pull --all --ff
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
||||||
f2de534..f567f69 master -> rad/master
|
f2de534..f567f69 master -> rad/master
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,18 @@ mod fetch;
|
||||||
mod list;
|
mod list;
|
||||||
mod push;
|
mod push;
|
||||||
|
|
||||||
|
use std::io::IsTerminal as _;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::time;
|
||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
|
use radicle::node::FetchResults;
|
||||||
|
use radicle::node::Handle as _;
|
||||||
|
use radicle::prelude::Id;
|
||||||
use radicle::storage::git::transport::local::{Url, UrlError};
|
use radicle::storage::git::transport::local::{Url, UrlError};
|
||||||
use radicle::storage::{ReadRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, WriteStorage};
|
||||||
use radicle_cli::terminal as cli;
|
use radicle_cli::terminal as cli;
|
||||||
|
|
@ -100,6 +105,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let mut opts = Options::default();
|
let mut opts = Options::default();
|
||||||
|
let mut sync = SyncState::new(url.repo);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let tokens = read_line(&stdin, &mut line)?;
|
let tokens = read_line(&stdin, &mut line)?;
|
||||||
|
|
@ -158,6 +164,8 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
|
||||||
let oid = git::Oid::from_str(oid)?;
|
let oid = git::Oid::from_str(oid)?;
|
||||||
let refstr = git::RefString::try_from(*refstr)?;
|
let refstr = git::RefString::try_from(*refstr)?;
|
||||||
|
|
||||||
|
sync.run(&opts, &profile).ok();
|
||||||
|
|
||||||
return fetch::run(vec![(oid, refstr)], &working, url, stored, &stdin)
|
return fetch::run(vec![(oid, refstr)], &working, url, stored, &stdin)
|
||||||
.map_err(Error::from);
|
.map_err(Error::from);
|
||||||
}
|
}
|
||||||
|
|
@ -174,6 +182,8 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
|
||||||
.map_err(Error::from);
|
.map_err(Error::from);
|
||||||
}
|
}
|
||||||
["list"] => {
|
["list"] => {
|
||||||
|
sync.run(&opts, &profile).ok();
|
||||||
|
|
||||||
list::for_fetch(&url, &stored)?;
|
list::for_fetch(&url, &stored)?;
|
||||||
}
|
}
|
||||||
["list", "for-push"] => {
|
["list", "for-push"] => {
|
||||||
|
|
@ -202,3 +212,77 @@ pub(crate) fn read_line<'a>(stdin: &io::Stdin, line: &'a mut String) -> io::Resu
|
||||||
|
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keeps track of sync state.
|
||||||
|
struct SyncState {
|
||||||
|
/// Whether we tried to fetch already.
|
||||||
|
fetched: bool,
|
||||||
|
/// The repo id.
|
||||||
|
rid: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyncState {
|
||||||
|
fn new(rid: Id) -> Self {
|
||||||
|
Self {
|
||||||
|
fetched: false,
|
||||||
|
rid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Connect to local node and try to fetch refs from the network.
|
||||||
|
/// If our node is not running, or the "no-sync" option is enabled,
|
||||||
|
/// we simply do nothing.
|
||||||
|
fn run(
|
||||||
|
&mut self,
|
||||||
|
opts: &Options,
|
||||||
|
profile: &radicle::Profile,
|
||||||
|
) -> Result<(), radicle::node::Error> {
|
||||||
|
if opts.no_sync || self.fetched {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut node = radicle::Node::new(profile.socket());
|
||||||
|
if !node.is_running() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = 3;
|
||||||
|
let timeout = time::Duration::from_secs(6);
|
||||||
|
let seeds = node.seeds(self.rid)?;
|
||||||
|
let connected = seeds.connected().map(|s| s.nid).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if connected.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let message = format!("Syncing with {} node(s)..", connected.len().min(target));
|
||||||
|
let mut spinner = if io::stderr().is_terminal() {
|
||||||
|
cli::spinner_to(message, io::stderr(), io::stderr())
|
||||||
|
} else {
|
||||||
|
cli::spinner_to(message, io::stderr(), io::sink())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch from connected seeds.
|
||||||
|
let mut results = FetchResults::default();
|
||||||
|
for seed in connected.into_iter() {
|
||||||
|
spinner.message(format!("Syncing with {seed}.."));
|
||||||
|
|
||||||
|
let result = node.fetch(self.rid, seed, timeout)?;
|
||||||
|
results.push(seed, result);
|
||||||
|
|
||||||
|
if results.success().count() >= target {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let success = results.success().count();
|
||||||
|
if success > 0 {
|
||||||
|
spinner.message(format!("Synced with {success} peer(s)"));
|
||||||
|
spinner.finish();
|
||||||
|
} else {
|
||||||
|
spinner.failed();
|
||||||
|
}
|
||||||
|
// Make sure we don't try to fetch again while this program is running.
|
||||||
|
self.fetched = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue