Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
remote-helper: Run sync on `git-fetch`
cloudhead committed 2 years ago
commit b482ae85f0233e6a597bb98d17bf222612c32920
parent 7e32f91ea29a79ea8571809dd494459640a0b052
6 files changed +90 -9
modified radicle-cli/examples/git/git-pull.md
@@ -13,6 +13,7 @@ f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 refs/heads/master

``` (stderr)
$ git fetch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
✓ Synced with 1 peer(s)
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
 * [new branch]      alice/1    -> alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/alice/1
```
modified radicle-cli/examples/git/git-push-diverge.md
@@ -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:

``` ~alice
-
$ rad sync --fetch
-
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
-
✓ Fetched repository from 1 seed(s)
$ git fetch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
$ git branch -arv
  bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master 319a7dc Third commit
modified radicle-cli/examples/rad-remote.md
@@ -20,7 +20,7 @@ remote of the project.

For the remote-tracking branch to work, we fetch bob:

-
``` (stderr)
+
``` RAD_SOCKET=/dev/null (stderr)
$ git fetch bob
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
 * [new branch]      master     -> bob/master
modified radicle-cli/examples/workflow/5-patching-maintainer.md
@@ -1,13 +1,11 @@
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
✓ 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
@@ -21,6 +19,7 @@ $ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob

``` (stderr)
$ git fetch bob
+
✓ Synced with 1 peer(s)
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
 * [new branch]      master     -> bob/master
 * [new branch]      patches/69e881c606639691330051d7d8f013854f32fb87 -> bob/patches/69e881c606639691330051d7d8f013854f32fb87
modified radicle-cli/examples/workflow/6-pulling-contributor.md
@@ -19,7 +19,7 @@ Now let's checkout `master` and pull the maintainer's changes:
$ git checkout master
Your branch is up to date with 'rad/master'.
```
-
``` (stderr)
+
``` (stderr) RAD_SOCKET=/dev/null
$ git pull --all --ff
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
   f2de534..f567f69  master     -> rad/master
modified radicle-remote-helper/src/lib.rs
@@ -7,13 +7,18 @@ mod fetch;
mod list;
mod push;

+
use std::io::IsTerminal as _;
use std::path::PathBuf;
use std::str::FromStr;
+
use std::time;
use std::{env, io};

use thiserror::Error;

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::{ReadRepository, WriteStorage};
use radicle_cli::terminal as cli;
@@ -100,6 +105,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
    let stdin = io::stdin();
    let mut line = String::new();
    let mut opts = Options::default();
+
    let mut sync = SyncState::new(url.repo);

    loop {
        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 refstr = git::RefString::try_from(*refstr)?;

+
                sync.run(&opts, &profile).ok();
+

                return fetch::run(vec![(oid, refstr)], &working, url, stored, &stdin)
                    .map_err(Error::from);
            }
@@ -174,6 +182,8 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
                .map_err(Error::from);
            }
            ["list"] => {
+
                sync.run(&opts, &profile).ok();
+

                list::for_fetch(&url, &stored)?;
            }
            ["list", "for-push"] => {
@@ -202,3 +212,77 @@ pub(crate) fn read_line<'a>(stdin: &io::Stdin, line: &'a mut String) -> io::Resu

    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(())
+
    }
+
}