Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
Use humantime to parse timeouts
Matthias Beyer committed 1 month ago
commit 99d92421225767a3c17eb0bd0f040cae01e87673
parent 52e5581
15 files changed +53 -33
modified CHANGELOG.md
@@ -66,6 +66,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `TypeName` strings defined in `radicle-cob` are restricted to reflect the
  size limits on domain names as specified in
  [RFC-1035](https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4).
+
- The `--timeout` flag, which is available on a number of CLI subcommands, now
+
  takes a human-readable duration as parameter, E.G. "9s" or "1min" instead of
+
  "9" or "60".

## 1.6.1

modified Cargo.lock
@@ -1855,6 +1855,12 @@ dependencies = [
]

[[package]]
+
name = "humantime"
+
version = "2.3.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
+

+
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2939,6 +2945,7 @@ dependencies = [
 "clap_complete",
 "dunce",
 "human-panic",
+
 "humantime",
 "itertools",
 "log",
 "nonempty",
modified Cargo.toml
@@ -33,6 +33,7 @@ git2 = { version = "0.20.4", default-features = false, features = ["vendored-lib
gix-hash = { version = "0.22.1", default-features = false, features = ["sha1"] }
gix-packetline = { version = "0.21.1", default-features = false }
human-panic = "2.0.6"
+
humantime = "2.3"
itertools = "0.14"
lexopt = "0.3.0"
libc = "0.2.137"
modified crates/radicle-cli/Cargo.toml
@@ -20,6 +20,7 @@ clap = { version = "4.5.44", features = ["derive"] }
clap_complete = "4.5"
dunce = { workspace = true }
human-panic.workspace = true
+
humantime.workspace = true
itertools.workspace = true
log = { workspace = true, features = ["std"] }
nonempty = { workspace = true }
modified crates/radicle-cli/examples/rad-clone-partial-fail.md
@@ -15,7 +15,7 @@ When she tries to clone, one of those will fail to fetch. But the clone command
still returns successfully.

```
-
$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --timeout 3
+
$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --timeout 3s
✓ Seeding policy updated for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'followed'
Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 3 potential seed(s).
✓ Target met: 1 seed(s)
modified crates/radicle-cli/examples/rad-id-collaboration.md
@@ -156,7 +156,7 @@ At this point, when Alice runs `rad sync`, she will fetch Eve's fork
since she has become a delegate:

``` ~alice
-
$ rad sync --timeout 3
+
$ rad sync --timeout 3s
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MkvVv…Z1Ct4tD@[..]..
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MkuPZ…xEuaPUp@[..]..
✓ Fetched repository from 2 seed(s)
modified crates/radicle-cli/examples/rad-id-multi-delegate.md
@@ -4,7 +4,7 @@ $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Bob" --des
```

``` ~bob
-
$ rad watch --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --node z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z -r 'refs/rad/sigrefs' -t c9a828fc2fb01f893d6e6e9e17b9092dea2b3aba -i 500 --timeout 5000
+
$ rad watch --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --node z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z -r 'refs/rad/sigrefs' -t c9a828fc2fb01f893d6e6e9e17b9092dea2b3aba -i 500 --timeout 5000ms
$ rad sync --fetch rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji
Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found 1 potential seed(s).
✓ Target met: 1 seed(s)
modified crates/radicle-cli/examples/rad-init-private-clone-seed.md
@@ -29,7 +29,7 @@ $ rad inspect --identity

``` ~bob
$ rad ls --all --private
-
$ rad clone rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --seed z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1
+
$ rad clone rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --seed z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1s
✓ Seeding policy updated for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu with scope 'followed'
Fetching rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu from the network, found 1 potential seed(s).
✓ Target met: 1 preferred seed(s).
@@ -48,7 +48,7 @@ Run `cd ./heartwood` to go to the repository directory.
We can also use `rad seed` to seed and fetch without creating a checkout.

``` ~bob
-
$ rad seed rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --from z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1
+
$ rad seed rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --from z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1s
✓ Seeding policy exists for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu with scope 'followed'
Fetching rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu from the network, found 1 potential seed(s).
✓ Target met: 1 seed(s)
modified crates/radicle-cli/examples/rad-init-private-clone.md
@@ -5,7 +5,7 @@ Bob tries to fetch it, and even though he's connected to Alice, it fails.
$ rad ls
```
``` ~bob (fail)
-
$ rad clone rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --seed z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1
+
$ rad clone rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --seed z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi --timeout 1s
✓ Seeding policy updated for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu with scope 'followed'
Fetching rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu from the network, found 1 potential seed(s).
✗ Target not met: could not fetch from [z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi], and required 1 more seed(s)
@@ -20,7 +20,7 @@ the refs.
``` ~alice
$ rad id update --title "Allow Bob" --description "" --allow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk -q
...
-
$ rad sync --announce --timeout 3
+
$ rad sync --announce --timeout 3s
✓ Synced with 1 seed(s)
```

modified crates/radicle-cli/src/commands/clone/args.rs
@@ -1,5 +1,4 @@
use std::path::PathBuf;
-
use std::time;

use clap::Parser;

@@ -31,15 +30,17 @@ pub(super) struct SyncArgs {
    #[arg(short, long = "seed", value_name = "NID", action = clap::ArgAction::Append)]
    seeds: Vec<NodeId>,

-
    /// Timeout for fetching repository in seconds
-
    #[arg(long, default_value_t = 9, value_name = "SECS")]
-
    timeout: usize,
+
    /// Timeout for fetching repository
+
    ///
+
    /// Valid arguments are for example "10s", "5min" or "2h 37min"
+
    #[arg(long, value_parser = humantime::parse_duration, default_value = "9s")]
+
    timeout: std::time::Duration,
}

impl From<SyncArgs> for SyncSettings {
    fn from(args: SyncArgs) -> Self {
        SyncSettings {
-
            timeout: time::Duration::from_secs(args.timeout as u64),
+
            timeout: args.timeout,
            seeds: args.seeds.into_iter().collect(),
            ..SyncSettings::default()
        }
modified crates/radicle-cli/src/commands/node.rs
@@ -29,9 +29,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {

    match command {
        Command::Connect { addr, timeout } => {
-
            let timeout = timeout
-
                .map(time::Duration::from_secs)
-
                .unwrap_or(time::Duration::MAX);
+
            let timeout = timeout.unwrap_or(time::Duration::MAX);
            match addr {
                Addr::Peer(addr) => control::connect(&mut node, addr.id, addr.addr, timeout)?,
                Addr::Node(nid) => {
@@ -70,9 +68,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
        }
        Command::Events { timeout, count } => {
            let count = count.unwrap_or(usize::MAX);
-
            let timeout = timeout
-
                .map(time::Duration::from_secs)
-
                .unwrap_or(time::Duration::MAX);
+
            let timeout = timeout.unwrap_or(time::Duration::MAX);

            events::run(node, count, timeout)?;
        }
modified crates/radicle-cli/src/commands/node/args.rs
@@ -105,8 +105,10 @@ pub(super) enum Command {
        addr: Addr,

        /// How long to wait for the connection to be established
-
        #[arg(long, value_name = "SECS")]
-
        timeout: Option<u64>,
+
        ///
+
        /// Valid arguments are for example "10s", "5min" or "2h 37min"
+
        #[arg(long, value_parser = humantime::parse_duration)]
+
        timeout: Option<std::time::Duration>,
    },

    /// Show the config
@@ -128,8 +130,10 @@ pub(super) enum Command {
    /// If no timeout or count is specified, it will run indefinitely.
    Events {
        /// How long to wait to receive an event before giving up
-
        #[arg(long, value_name = "SECS")]
-
        timeout: Option<u64>,
+
        ///
+
        /// Valid arguments are for example "10s", "5min" or "2h 37min"
+
        #[arg(long, value_parser = humantime::parse_duration)]
+
        timeout: Option<std::time::Duration>,

        /// Exit after <COUNT> events
        #[arg(long, short = 'n')]
modified crates/radicle-cli/src/commands/seed/args.rs
@@ -43,8 +43,10 @@ pub struct Args {
    pub(super) from: Vec<NodeId>,

    /// Fetch timeout in seconds
-
    #[arg(long, short, value_name = "SECS", default_value_t = 9)]
-
    timeout: u64,
+
    ///
+
    /// Valid arguments are for example "10s", "5min" or "2h 37min"
+
    #[arg(long, short, value_parser = humantime::parse_duration, default_value = "9s")]
+
    timeout: std::time::Duration,

    /// Peer follow scope for this repository
    #[arg(long, value_parser = terminal::args::ScopeParser)]
@@ -86,7 +88,7 @@ impl From<Args> for Operation {

impl Args {
    fn timeout(&self) -> time::Duration {
-
        time::Duration::from_secs(self.timeout)
+
        self.timeout
    }

    fn should_fetch(&self) -> bool {
modified crates/radicle-cli/src/commands/sync/args.rs
@@ -89,15 +89,17 @@ pub(super) struct SyncArgs {
    )]
    seeds: Vec<NodeId>,

-
    /// How many seconds to wait while synchronizing
+
    /// How long to wait while synchronizing
+
    ///
+
    /// Valid arguments are for example "10s", "5min" or "2h 37min"
    #[arg(
        long,
        short,
-
        default_value_t = 9,
-
        value_name = "SECS",
+
        default_value = "9s",
+
        value_parser = humantime::parse_duration,
        conflicts_with = "inventory"
    )]
-
    timeout: u64,
+
    timeout: std::time::Duration,

    /// The repository to perform the synchronizing for [default: cwd]
    rid: Option<RepoId>,
@@ -146,7 +148,7 @@ impl SyncArgs {
    }

    fn timeout(&self) -> time::Duration {
-
        time::Duration::from_secs(self.timeout)
+
        self.timeout
    }

    fn replication(&self) -> sync::ReplicationFactor {
modified crates/radicle-cli/src/commands/watch/args.rs
@@ -43,8 +43,10 @@ pub struct Args {
    interval: u64,

    /// Timeout, in milliseconds
-
    #[arg(long, value_name = "MILLIS")]
-
    timeout: Option<u64>,
+
    ///
+
    /// Valid arguments are for example "10s", "5min" or "2h 37min"
+
    #[arg(long, value_parser = humantime::parse_duration)]
+
    timeout: Option<std::time::Duration>,
}

impl Args {
@@ -55,7 +57,8 @@ impl Args {

    /// Provide the timeout duration in milliseconds.
    pub(super) fn timeout(&self) -> time::Duration {
-
        time::Duration::from_millis(self.timeout.unwrap_or(u64::MAX))
+
        self.timeout
+
            .unwrap_or_else(|| time::Duration::from_millis(u64::MAX))
    }
}