cli: Improve `rad remote add`
By default, this command now: * Follows the peer if not already followed * Syncs refs of the peer, if it wasn't followed before * Fetches refs into working copy This functionality can be disabled via `--no-sync` and `--no-fetch`.
This commit is contained in:
parent
3a3820b06d
commit
e4f06e9c9d
|
|
@ -7,9 +7,6 @@ First we add a second delegate, Bob, to our repo:
|
||||||
``` ~alice
|
``` ~alice
|
||||||
$ rad id update --title "Add Bob" --description "" --delegate did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji -q
|
$ rad id update --title "Add Bob" --description "" --delegate did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji -q
|
||||||
c036c0d89ce26aef3ad7da402157dba16b5163b4
|
c036c0d89ce26aef3ad7da402157dba16b5163b4
|
||||||
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
|
||||||
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
|
||||||
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, as Bob, we commit some code on top of the canonical head:
|
Then, as Bob, we commit some code on top of the canonical head:
|
||||||
|
|
@ -32,7 +29,9 @@ 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
|
||||||
$ git fetch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --fetch --no-sync
|
||||||
|
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
||||||
|
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
||||||
$ git branch -arv
|
$ git branch -arv
|
||||||
bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master 319a7dc Third commit
|
bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master 319a7dc Third commit
|
||||||
rad/master f2de534 Second commit
|
rad/master f2de534 Second commit
|
||||||
|
|
|
||||||
|
|
@ -48,18 +48,9 @@ z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
We can then setup a git remote for `bob`:
|
We can then setup a git remote for `bob`:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob
|
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob --no-sync --fetch
|
||||||
✓ Remote bob added
|
✓ Remote bob added
|
||||||
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
||||||
```
|
|
||||||
|
|
||||||
And fetch his refs:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ git fetch --all
|
|
||||||
Fetching rad
|
|
||||||
Fetching alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
|
||||||
Fetching bob
|
|
||||||
$ git branch --remotes
|
$ git branch --remotes
|
||||||
alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master
|
alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master
|
||||||
bob/master
|
bob/master
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,6 @@ $ git push -o patch.message="Changes" rad HEAD:refs/patches
|
||||||
```
|
```
|
||||||
|
|
||||||
``` ~alice
|
``` ~alice
|
||||||
$ rad sync -f
|
|
||||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
|
||||||
✓ Fetched repository from 1 seed(s)
|
|
||||||
$ git checkout -b alice/1 -q
|
$ git checkout -b alice/1 -q
|
||||||
$ git rev-parse HEAD
|
$ git rev-parse HEAD
|
||||||
f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354
|
||||||
|
|
@ -19,13 +16,12 @@ $ rad patch checkout 0fd67a0
|
||||||
✓ Switched to branch patch/0fd67a0
|
✓ Switched to branch patch/0fd67a0
|
||||||
✓ Branch patch/0fd67a0 setup to track rad/patches/0fd67a0364af1f79ed8770a35ed09d85571d4c21
|
✓ Branch patch/0fd67a0 setup to track rad/patches/0fd67a0364af1f79ed8770a35ed09d85571d4c21
|
||||||
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
||||||
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
||||||
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
||||||
$ git checkout master -q
|
$ git checkout master -q
|
||||||
$ git fetch --all -q
|
|
||||||
$ cat .git/FETCH_HEAD
|
$ cat .git/FETCH_HEAD
|
||||||
f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 branch 'master' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
|
||||||
8d5f1bae4b69d8e3f6cbfc6f4bd675ed19990afc not-for-merge branch 'patches/0fd67a0364af1f79ed8770a35ed09d85571d4c21' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
|
||||||
f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 not-for-merge branch 'master' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 not-for-merge branch 'master' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
8d5f1bae4b69d8e3f6cbfc6f4bd675ed19990afc not-for-merge branch 'patches/0fd67a0364af1f79ed8770a35ed09d85571d4c21' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
8d5f1bae4b69d8e3f6cbfc6f4bd675ed19990afc not-for-merge branch 'patches/0fd67a0364af1f79ed8770a35ed09d85571d4c21' of rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
$ git rev-parse master
|
$ git rev-parse master
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
Now, let's add a bob as a new remote:
|
Now, let's add a bob as a new remote:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob
|
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob --no-sync
|
||||||
✓ Remote bob added
|
✓ Remote bob added
|
||||||
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
||||||
```
|
```
|
||||||
|
|
@ -18,14 +18,6 @@ rad z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push)
|
||||||
You can see both `bob` and `rad` as remotes. The `rad` remote is our personal
|
You can see both `bob` and `rad` as remotes. The `rad` remote is our personal
|
||||||
remote of the project.
|
remote of the project.
|
||||||
|
|
||||||
For the remote-tracking branch to work, we fetch bob:
|
|
||||||
|
|
||||||
``` RAD_SOCKET=/dev/null (stderr)
|
|
||||||
$ git fetch bob
|
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
|
||||||
* [new branch] master -> bob/master
|
|
||||||
```
|
|
||||||
|
|
||||||
We can now see the remote-tracking branch that was setup:
|
We can now see the remote-tracking branch that was setup:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -47,7 +39,7 @@ Now, add another time `bob` but without specify the `name`, so we should be
|
||||||
able to fetch the node alias from our db!
|
able to fetch the node alias from our db!
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
$ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --no-sync
|
||||||
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
✓ Remote bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk added
|
||||||
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
✓ Remote-tracking branch bob@z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk/master created for z6Mkt67…v4N1tRk
|
||||||
```
|
```
|
||||||
|
|
@ -76,7 +68,7 @@ As we can see, we have also have another remote namespace `eve`, so
|
||||||
let's add them to our set of working copy remotes:
|
let's add them to our set of working copy remotes:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad remote add did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z --name eve
|
$ rad remote add did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z --name eve --no-sync
|
||||||
✓ Remote eve added
|
✓ Remote eve added
|
||||||
✓ Remote-tracking branch eve/master created for z6Mkux1…nVhib7Z
|
✓ Remote-tracking branch eve/master created for z6Mkux1…nVhib7Z
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,16 @@
|
||||||
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
|
Changes have been proposed by another peer via a radicle patch. To track
|
||||||
follow changes by another, we must 'follow' them.
|
changes from another peer, we must first follow them, and then create
|
||||||
|
a tracking branch in our working copy. The `rad remote add` command does all
|
||||||
|
of this.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad follow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias bob
|
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob --sync --fetch
|
||||||
✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob)
|
✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob)
|
||||||
```
|
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
||||||
|
|
||||||
Additionally, we need to add a new 'git remote' to our working copy for the
|
|
||||||
peer. Upcoming versions of radicle will not require this step.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ rad remote add z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --name bob
|
|
||||||
✓ Remote bob added
|
✓ Remote bob added
|
||||||
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
✓ Remote-tracking branch bob/master created for z6Mkt67…v4N1tRk
|
||||||
$ rad sync -f
|
|
||||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk..
|
|
||||||
✓ Fetched repository from 1 seed(s)
|
|
||||||
```
|
|
||||||
|
|
||||||
``` (stderr)
|
|
||||||
$ git fetch bob
|
|
||||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
|
||||||
* [new branch] patches/3581e83ad18f5cdd806ab50fa11cfd5dd4e8ae1c -> bob/patches/3581e83ad18f5cdd806ab50fa11cfd5dd4e8ae1c
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The contributor's changes are now visible to us.
|
The contributor's changes are now visible to us.
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ pub fn setup_remote(
|
||||||
remote_id: &NodeId,
|
remote_id: &NodeId,
|
||||||
remote_name: Option<git::RefString>,
|
remote_name: Option<git::RefString>,
|
||||||
aliases: &impl AliasStore,
|
aliases: &impl AliasStore,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<git::RefString> {
|
||||||
let remote_name = if let Some(name) = remote_name {
|
let remote_name = if let Some(name) = remote_name {
|
||||||
name
|
name
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -168,7 +168,7 @@ pub fn setup_remote(
|
||||||
git::RefString::try_from(name.as_str())
|
git::RefString::try_from(name.as_str())
|
||||||
.map_err(|_| anyhow!("invalid remote name: '{name}'"))?
|
.map_err(|_| anyhow!("invalid remote name: '{name}'"))?
|
||||||
};
|
};
|
||||||
let (remote, branch) = setup.run(remote_name, *remote_id)?;
|
let (remote, branch) = setup.run(&remote_name, *remote_id)?;
|
||||||
|
|
||||||
term::success!("Remote {} added", term::format::tertiary(remote.name));
|
term::success!("Remote {} added", term::format::tertiary(remote.name));
|
||||||
|
|
||||||
|
|
@ -179,5 +179,5 @@ pub fn setup_remote(
|
||||||
term::format::tertiary(term::format::node(remote_id))
|
term::format::tertiary(term::format::node(remote_id))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(remote_name)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -528,7 +528,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
||||||
if announce {
|
if announce {
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket());
|
||||||
node::sync(rid, &mut node)?;
|
node::announce(rid, &mut node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
if refs.is_none() && !options.all {
|
if refs.is_none() && !options.all {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let seeded = policy.is_repo_seeded(&rid)?;
|
let seeded = policy.is_seeded(&rid)?;
|
||||||
|
|
||||||
if !seeded && !options.all {
|
if !seeded && !options.all {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -794,7 +794,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
||||||
if announce {
|
if announce {
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket());
|
||||||
node::sync(id, &mut node)?;
|
node::announce(id, &mut node)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ List options
|
||||||
Add options
|
Add options
|
||||||
|
|
||||||
--name Override the name of the remote that by default is set to the node alias
|
--name Override the name of the remote that by default is set to the node alias
|
||||||
|
--[no-]fetch Fetch the remote from local storage (default: fetch)
|
||||||
|
--[no-]sync Sync the remote refs from the network (default: sync)
|
||||||
|
|
||||||
Options
|
Options
|
||||||
|
|
||||||
|
|
@ -56,9 +58,18 @@ pub enum OperationName {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Operation {
|
pub enum Operation {
|
||||||
Add { id: NodeId, name: Option<RefString> },
|
Add {
|
||||||
Rm { name: RefString },
|
id: NodeId,
|
||||||
List { option: ListOption },
|
name: Option<RefString>,
|
||||||
|
fetch: bool,
|
||||||
|
sync: bool,
|
||||||
|
},
|
||||||
|
Rm {
|
||||||
|
name: RefString,
|
||||||
|
},
|
||||||
|
List {
|
||||||
|
option: ListOption,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|
@ -83,6 +94,8 @@ impl Args for Options {
|
||||||
let mut id: Option<NodeId> = None;
|
let mut id: Option<NodeId> = None;
|
||||||
let mut name: Option<RefString> = None;
|
let mut name: Option<RefString> = None;
|
||||||
let mut list_op: ListOption = ListOption::default();
|
let mut list_op: ListOption = ListOption::default();
|
||||||
|
let mut fetch = true;
|
||||||
|
let mut sync = true;
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
match arg {
|
match arg {
|
||||||
|
|
@ -114,6 +127,18 @@ impl Args for Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add options
|
// Add options
|
||||||
|
Long("sync") if op == Some(OperationName::Add) => {
|
||||||
|
sync = true;
|
||||||
|
}
|
||||||
|
Long("no-sync") if op == Some(OperationName::Add) => {
|
||||||
|
sync = false;
|
||||||
|
}
|
||||||
|
Long("fetch") if op == Some(OperationName::Add) => {
|
||||||
|
fetch = true;
|
||||||
|
}
|
||||||
|
Long("no-fetch") if op == Some(OperationName::Add) => {
|
||||||
|
fetch = false;
|
||||||
|
}
|
||||||
Value(val) if op == Some(OperationName::Add) && id.is_none() => {
|
Value(val) if op == Some(OperationName::Add) && id.is_none() => {
|
||||||
let nid = args::pubkey(&val)?;
|
let nid = args::pubkey(&val)?;
|
||||||
id = Some(nid);
|
id = Some(nid);
|
||||||
|
|
@ -137,6 +162,8 @@ impl Args for Options {
|
||||||
"`DID` required, try running `rad remote add <did>`"
|
"`DID` required, try running `rad remote add <did>`"
|
||||||
))?,
|
))?,
|
||||||
name,
|
name,
|
||||||
|
fetch,
|
||||||
|
sync,
|
||||||
},
|
},
|
||||||
OperationName::List => Operation::List { option: list_op },
|
OperationName::List => Operation::List { option: list_op },
|
||||||
OperationName::Rm => Operation::Rm {
|
OperationName::Rm => Operation::Rm {
|
||||||
|
|
@ -154,11 +181,25 @@ pub fn run(options: Options, ctx: impl Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
|
|
||||||
match options.op {
|
match options.op {
|
||||||
Operation::Add { ref id, name } => {
|
Operation::Add {
|
||||||
|
ref id,
|
||||||
|
name,
|
||||||
|
fetch,
|
||||||
|
sync,
|
||||||
|
} => {
|
||||||
let proj = profile.storage.repository(rid)?.project()?;
|
let proj = profile.storage.repository(rid)?.project()?;
|
||||||
let branch = proj.default_branch();
|
let branch = proj.default_branch();
|
||||||
|
|
||||||
self::add::run(rid, id, name, Some(branch.clone()), &profile, &working)?
|
self::add::run(
|
||||||
|
rid,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
Some(branch.clone()),
|
||||||
|
&profile,
|
||||||
|
&working,
|
||||||
|
fetch,
|
||||||
|
sync,
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
Operation::Rm { ref name } => self::rm::run(name, &working)?,
|
Operation::Rm { ref name } => self::rm::run(name, &working)?,
|
||||||
Operation::List { option } => match option {
|
Operation::List { option } => match option {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
use radicle::git;
|
||||||
use radicle::git::RefString;
|
use radicle::git::RefString;
|
||||||
use radicle::prelude::*;
|
use radicle::prelude::*;
|
||||||
use radicle::Profile;
|
use radicle::Profile;
|
||||||
use radicle_crypto::PublicKey;
|
use radicle_crypto::PublicKey;
|
||||||
|
|
||||||
use crate::commands::rad_checkout as checkout;
|
use crate::commands::rad_checkout as checkout;
|
||||||
use crate::git;
|
use crate::commands::rad_follow as follow;
|
||||||
|
use crate::commands::rad_sync as sync;
|
||||||
use crate::project::SetupRemote;
|
use crate::project::SetupRemote;
|
||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
|
|
@ -13,14 +18,33 @@ pub fn run(
|
||||||
name: Option<RefString>,
|
name: Option<RefString>,
|
||||||
tracking: Option<BranchName>,
|
tracking: Option<BranchName>,
|
||||||
profile: &Profile,
|
profile: &Profile,
|
||||||
repo: &git::Repository,
|
repo: &git::raw::Repository,
|
||||||
|
fetch: bool,
|
||||||
|
sync: bool,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if sync {
|
||||||
|
let mut node = radicle::Node::new(profile.socket());
|
||||||
|
|
||||||
|
if !profile.policies()?.is_followed(nid)? {
|
||||||
|
let alias = name.as_ref().and_then(|n| Alias::from_str(n.as_str()).ok());
|
||||||
|
|
||||||
|
follow::follow(*nid, alias, &mut node, profile)?;
|
||||||
|
sync::fetch(
|
||||||
|
rid,
|
||||||
|
sync::RepoSync::default(),
|
||||||
|
time::Duration::from_secs(9),
|
||||||
|
&mut node,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
let aliases = profile.aliases();
|
let aliases = profile.aliases();
|
||||||
let setup = SetupRemote {
|
let setup = SetupRemote {
|
||||||
rid,
|
rid,
|
||||||
tracking,
|
tracking,
|
||||||
fetch: false,
|
fetch,
|
||||||
repo,
|
repo,
|
||||||
};
|
};
|
||||||
checkout::setup_remote(&setup, nid, name, &aliases)
|
checkout::setup_remote(&setup, nid, name, &aliases)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
Operation::Synchronize(SyncMode::Repo { mode, direction }) => {
|
Operation::Synchronize(SyncMode::Repo { mode, direction }) => {
|
||||||
if [SyncDirection::Fetch, SyncDirection::Both].contains(&direction) {
|
if [SyncDirection::Fetch, SyncDirection::Both].contains(&direction) {
|
||||||
if !profile.policies()?.is_repo_seeded(&rid)? {
|
if !profile.policies()?.is_seeded(&rid)? {
|
||||||
anyhow::bail!("repository {rid} is not seeded");
|
anyhow::bail!("repository {rid} is not seeded");
|
||||||
}
|
}
|
||||||
let results = fetch(rid, mode.clone(), options.timeout, &mut node)?;
|
let results = fetch(rid, mode.clone(), options.timeout, &mut node)?;
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ use radicle::Node;
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
|
||||||
pub fn sync(rid: Id, node: &mut Node) -> anyhow::Result<()> {
|
/// Announce changes to the network.
|
||||||
match sync_(rid, node) {
|
pub fn announce(rid: Id, node: &mut Node) -> anyhow::Result<()> {
|
||||||
|
match announce_(rid, node) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(e) if e.is_connection_err() => {
|
Err(e) if e.is_connection_err() => {
|
||||||
term::hint("Node is stopped. To announce changes to the network, start it with `rad node start`.");
|
term::hint("Node is stopped. To announce changes to the network, start it with `rad node start`.");
|
||||||
|
|
@ -18,8 +19,7 @@ pub fn sync(rid: Id, node: &mut Node) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sync with the network.
|
fn announce_(rid: Id, node: &mut Node) -> Result<(), radicle::node::Error> {
|
||||||
fn sync_(rid: Id, node: &mut Node) -> Result<(), radicle::node::Error> {
|
|
||||||
let seeds = node.seeds(rid)?;
|
let seeds = node.seeds(rid)?;
|
||||||
let connected = seeds.connected().map(|s| s.nid).collect::<Vec<_>>();
|
let connected = seeds.connected().map(|s| s.nid).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ impl Store<Write> {
|
||||||
/// `Config<Write>` can access these functions as well.
|
/// `Config<Write>` can access these functions as well.
|
||||||
impl<T> Store<T> {
|
impl<T> Store<T> {
|
||||||
/// Check if a node is followed.
|
/// Check if a node is followed.
|
||||||
pub fn is_node_followed(&self, id: &NodeId) -> Result<bool, Error> {
|
pub fn is_followed(&self, id: &NodeId) -> Result<bool, Error> {
|
||||||
Ok(matches!(
|
Ok(matches!(
|
||||||
self.follow_policy(id)?,
|
self.follow_policy(id)?,
|
||||||
Some(Node {
|
Some(Node {
|
||||||
|
|
@ -215,7 +215,7 @@ impl<T> Store<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a repository is seeded.
|
/// Check if a repository is seeded.
|
||||||
pub fn is_repo_seeded(&self, id: &Id) -> Result<bool, Error> {
|
pub fn is_seeded(&self, id: &Id) -> Result<bool, Error> {
|
||||||
Ok(matches!(
|
Ok(matches!(
|
||||||
self.seed_policy(id)?,
|
self.seed_policy(id)?,
|
||||||
Some(Repo {
|
Some(Repo {
|
||||||
|
|
@ -335,10 +335,10 @@ mod test {
|
||||||
let mut db = Store::open(":memory:").unwrap();
|
let mut db = Store::open(":memory:").unwrap();
|
||||||
|
|
||||||
assert!(db.follow(&id, Some("eve")).unwrap());
|
assert!(db.follow(&id, Some("eve")).unwrap());
|
||||||
assert!(db.is_node_followed(&id).unwrap());
|
assert!(db.is_followed(&id).unwrap());
|
||||||
assert!(!db.follow(&id, Some("eve")).unwrap());
|
assert!(!db.follow(&id, Some("eve")).unwrap());
|
||||||
assert!(db.unfollow(&id).unwrap());
|
assert!(db.unfollow(&id).unwrap());
|
||||||
assert!(!db.is_node_followed(&id).unwrap());
|
assert!(!db.is_followed(&id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -347,10 +347,10 @@ mod test {
|
||||||
let mut db = Store::open(":memory:").unwrap();
|
let mut db = Store::open(":memory:").unwrap();
|
||||||
|
|
||||||
assert!(db.seed(&id, Scope::All).unwrap());
|
assert!(db.seed(&id, Scope::All).unwrap());
|
||||||
assert!(db.is_repo_seeded(&id).unwrap());
|
assert!(db.is_seeded(&id).unwrap());
|
||||||
assert!(!db.seed(&id, Scope::All).unwrap());
|
assert!(!db.seed(&id, Scope::All).unwrap());
|
||||||
assert!(db.unseed(&id).unwrap());
|
assert!(db.unseed(&id).unwrap());
|
||||||
assert!(!db.is_repo_seeded(&id).unwrap());
|
assert!(!db.is_seeded(&id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use thiserror::Error;
|
||||||
use crate::crypto::ssh::agent::Agent;
|
use crate::crypto::ssh::agent::Agent;
|
||||||
use crate::crypto::ssh::{keystore, Keystore, Passphrase};
|
use crate::crypto::ssh::{keystore, Keystore, Passphrase};
|
||||||
use crate::crypto::{PublicKey, Signer};
|
use crate::crypto::{PublicKey, Signer};
|
||||||
|
use crate::node::policy::config::store::Read;
|
||||||
use crate::node::{policy, Alias, AliasStore};
|
use crate::node::{policy, Alias, AliasStore};
|
||||||
use crate::prelude::Did;
|
use crate::prelude::Did;
|
||||||
use crate::prelude::{Id, NodeId};
|
use crate::prelude::{Id, NodeId};
|
||||||
|
|
@ -346,6 +347,17 @@ impl Profile {
|
||||||
&self.home
|
&self.home
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a read-only handle to the policies of the node.
|
||||||
|
pub fn policies(&self) -> Result<policy::config::Config<Read>, policy::store::Error> {
|
||||||
|
let path = self.node().join(node::POLICIES_DB_FILE);
|
||||||
|
let config = policy::config::Config::new(
|
||||||
|
self.config.node.policy,
|
||||||
|
self.config.node.scope,
|
||||||
|
policy::store::Store::reader(path)?,
|
||||||
|
);
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a multi-source store for aliases.
|
/// Return a multi-source store for aliases.
|
||||||
pub fn aliases(&self) -> Aliases {
|
pub fn aliases(&self) -> Aliases {
|
||||||
let policies = self.home.policies().ok();
|
let policies = self.home.policies().ok();
|
||||||
|
|
@ -471,15 +483,7 @@ impl Home {
|
||||||
.unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
|
.unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a read-only handle to the policies of the node.
|
/// Return a read-write handle to the policies store of the node.
|
||||||
pub fn policies(&self) -> Result<policy::store::StoreReader, policy::store::Error> {
|
|
||||||
let path = self.node().join(node::POLICIES_DB_FILE);
|
|
||||||
let config = policy::store::Store::reader(path)?;
|
|
||||||
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a read-write handle to the policies of the node.
|
|
||||||
pub fn policies_mut(&self) -> Result<policy::store::StoreWriter, policy::store::Error> {
|
pub fn policies_mut(&self) -> Result<policy::store::StoreWriter, policy::store::Error> {
|
||||||
let path = self.node().join(node::POLICIES_DB_FILE);
|
let path = self.node().join(node::POLICIES_DB_FILE);
|
||||||
let config = policy::store::Store::open(path)?;
|
let config = policy::store::Store::open(path)?;
|
||||||
|
|
@ -504,6 +508,17 @@ impl Home {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Private methods.
|
||||||
|
impl Home {
|
||||||
|
/// Return a read-only handle to the policies store of the node.
|
||||||
|
fn policies(&self) -> Result<policy::store::StoreReader, policy::store::Error> {
|
||||||
|
let path = self.node().join(node::POLICIES_DB_FILE);
|
||||||
|
let config = policy::store::Store::reader(path)?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue