Parsing of IPv6 addresses not enclosed in square brackets causes a
warning to be logged.
This is too strict, since the user can not influence IPv6 addresses
received over the network, but only those in their configuration.
Remove the warning from parsing, and instead carry a boolean to warn the
user later.
Move logging-related module `radicle::logging` into its own crate.
While at it, remove the "logger" feature flag from `radicle`.
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.dev>
`cargo check` fails because `human-panic` and `sysinfo` require at least
1.88.0.
+++ command cargo check --release --locked --all-targets
error: rustc 1.85.0 is not supported by the following packages:
human-panic@2.0.6 requires rustc 1.88
sysinfo@0.37.2 requires rustc 1.88
Bump MSRV to fix this.
1.88.0 introduced [let chains], which in turn has `clippy` warn about
nested if statements. All of these sites are fixed in this change.
1.87.0 introduced [`is_multiple_of`], which is a more readable version
of `x % y == 0`.
[let chains]: https://blog.rust-lang.org/2025/06/26/Rust-1.88.0/#let-chains
[`is_multiple_of`]: https://doc.rust-lang.org/std/primitive.usize.html#method.is_multiple_of
- Fixes a bug where the log level set in the config file was
ignored: `Logger` and `StderrLogger` captured the level in a
`self.level` field at construction time and checked it in
`Log::enabled`. After config was loaded, the global
`log::set_max_level` was updated but `self.level` was not,
so verbose messages were dropped by the per-instance filter
even when the global filter allowed them.
- Make `log::set_max_level` the single source of truth: remove
the `level` field and have `Log::enabled` defer to
`log::max_level()` so the two filters can no longer drift.
- Update call sites to construct loggers without a level.
- Disable the structured logger's internal filter (set to "trace") so
that it also falls back to `log::set_max_level`.
Canonical references can not be used to model symbolic references.
Relax this restriction by adding another member to the payload, named
"symbolic". Its key-value/name-target pairs then translate directly to
canonical symbolic references.
Care is taken to not allow circular references, and that there always
is a rule that could generate the target of a symbolic reference
(or a chain of symbolic references). Still, a symbolic reference may
dangle (for example when its target reference cannot be computed
because of divergence), but at least it can be prevented that a
symref *always* dangles, because there is no rule that would produce
its target.
Co-authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
Update the output of `rad_jj_colocated_patch` so that it passes with the current version of `jj` being used:
```
jj --version
jj 0.35.0
```
Mark `rad_jj_bare` as `ignore` since it currently cannot determine the
RID from the `rad` remote.
The name `print_inline` was used because, previously, the `print`
function name was taken.
This has now changed, allowing the rename of this function to happen.
The name `print` was used because, previously, the `println`
function name was taken.
This has now changed, allowing the rename of this function to happen.
Prevent `rad` from panicking when its stdout is a closed pipe, e.g.
when running `rad config | head`.
The broken pipes are handled at the output boundaries using three
layers of defence:
1. Inner: Route all stdout output through `term::print()` and
`term::print_inline()`, which use explicit `writeln!`/`write!` to
a locked stdout and silently ignore write errors. All `println!`
calls in `radicle-cli` and `radicle-term` are converted.
2. Middle: Catch `BrokenPipe` errors that propagate up via `anyhow`
from subcommands in `main::run()`, and exit cleanly with code 0.
3. Outer: Install a panic hook that intercepts `println!` panics
containing "Broken pipe" (from dependencies like clap) and exits
cleanly, chained in front of human_panic's hook.
To prevent regressions, `#![deny(clippy::print_stdout)]` is added to
`radicle-cli`, requiring all future stdout output to go through the
safe `term::` functions.
Note: `eprintln!` calls (stderr) are not handled, as broken stderr
pipes are extremely rare in practice.
Rust (since 1.62) ignores EPIPE by default (see [Rust #62569]),
causing writes to closed pipes to return `io::ErrorKind::BrokenPipe`
errors. The `println!` macro panics on these errors, producing a
confusing backtrace instead of the silent exit expected of Unix CLI
tools.
To avoid the use of `print!` and `println!`, the `radicle-term`
helper functions use `write!` and `writeln!`. This lays the groundwork
for the `rad` CLI to transition to using only `radicle-term`
functions.
There was a first attempt made, which is documented here. A
process-wide SIGPIPE reset (`SIG_DFL`) was ruled out because `rad`
manages child processes via libgit2 pipes and communicates with the
radicle node over Unix sockets. Resetting SIGPIPE globally caused
`rad` itself to be killed during internal pipe operations (e.g. during
`rad remote add --fetch`), producing flaky test failures.
[Rust #62569] https://github.com/rust-lang/rust/issues/62569
Add tests that verify the `rad` binary does not panic when its stdout
is a broken pipe (e.g., `rad config | head -1`).
Rust (since 1.62) ignores SIGPIPE by default (see [Rust #62569]),
causing `println!` to panic with "failed printing to stdout: Broken
pipe" instead of exiting silently. This is the standard Unix behaviour
expected of CLI tools.
These tests currently fail on `rad config` and `rad self`, and are set to `ignore`, to be enabled when fixed.
[Rust #62569]: https://github.com/rust-lang/rust/issues/62569
`fn sha1_zero` can be `const fn`, and since it does not take arguments,
it can just be a `const`. There is no good reason to not have a constant.
Justification for changing the order to first specify "zero" and then
"SHA1": In the future we will support multiple object formats. A
function that produces a zero OID would be parameterized by the object
format then. Imagine `fn zero(format: ObjectFormat)` which would be
called as `Oid::zero(ObjectForma::Sha1)`. In anticipation, we change the
ordering to match.
Two tests assumed that `refs/remotes/rad/HEAD` would automatically be
crated. It turns out, however, that this only the case if executed
with Git 2.48.0 or newer. Git versions older than 2.48.0 do not touch
'refs/remotes/<remote>/HEAD'.
Git 2.48.0 and newer will update `refs/remotes/<remote>/HEAD` by
default. This can be disabled by setting
`remote.<remote>.followRemoteHEAD` to "never". Thus, with these
versions, setting that configuration to "never" emulates the behaviour
of older versions.
Therefore, to ensure that test results are consistent across Git
versions before and after 2.48.0, the fixture of test repositories
now include setting 'remote.rad.followRemoteHEAD = never'.
The affected tests are adjusted accordingly.
This change can possibly be reverted once Radicle requires usage of Git
2.48.0 or newer.
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
Multiple commands take an RID as a command line argument. However, the
handling, which usually involves falling back to detection of the
repository associated with the current directory, is duplicated many
times over.
Introduce `fn rid_or_cwd` which can be used by many commands.
Many commands take RIDs as arguments. Most of them call the
corresponding struct member `repo`, some call it `rid`.
For consistency, name these members `repo` for all commands.
This change is intended to be invisible to the user. That is why,
in some cases, the "long" version of the argument must be renamed to
match `--rid`.
The value of `RAD_SOCKET` influences the outcome of `cargo test`.
Users that set this environment variable to, e.g. point `rad` at
a socket at a custom location, were surprised that execution of
tests would interact with their node.
Split `Home::socket` into two functions. `Home::socket_default` is
"pure" and only dependent on the path represented by `Home`. On the
other hand, `Home::socket_from_env` interprets the environment.
Most users will want to use `Home::socket_from_env`.
The main motivation behind this change is to get just a little
telemetry information from nodes on the network, namely the version
of Radicle they are running.
This is achieved by rewriting `impl Default for UserAgent` which now
uses the version information provided by the build script also used
in other crates.
Also, a new configuration option `node.userAgent` is added, which
allows users to override the user agent if they so please, or set
the value `null`, which will in turn send the user agent
`/radicle/`, which is not really helpful, and the default prior to
this commit.
Creations of `UserAgent` in the whole workspace is cleaned up. In
order to do that `UserAgent::test` is introduced.
This makes the `radicle-ssh` crate obsolete.
Signed-off-by: Wiktor Kwapisiewicz <wiktor@metacode.biz>
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
Each revision now shows a `{base}..{head}` range instead of just the
head. This is meant to clarify when a patch is rebased, and to be
helpful when one might want to observe changes using 'git range-diff'.
Instead of passing the signer as an argument to many methods on `Store`,
scope the `Store` itself to a signer.
This further allows to differentiate two different access modes on the
store in `radicle::cob::store::access`: `WriteAs` (which requires signer)
and `ReadOnly` (which does not require a signer).
The caches for issues and patches in `radicle::cob::{issue,patch}::Cache`
are concretised by removing the first type parameter, since it was
specific to issues and patches anyway. This was done in this commit as
it touches very similar usage sites.
Make `Device` less prominent, and instead lean more heavily towards
traits from the `signature` crate, such as `Keypair` and `Verifier`
in addition to `Signer`. Trait bounds regarding `Signer` could be
simplified, but this is left for the future.
In `radicle-cli`, the function `term::cob::patches_mut`, which generates
errors with a hint is used instead of the lower-level `Profile::patches_mut`.
Commands `rad issue cache` and `rad patch cache` now construct a
writeable cache on top of a read-only store.
Many knock-on changes are handled as well, to arrive at a clean state.
The intent to drop outgoing connections is modeled as `Option::None`
which is brittle and easy to miss.
Extend `enum AddressConfig` with a variant that is more explicit.
For stable commits, use the same timestamp as the CLI tests do.
This preserves that commits that are created in the Signed References
module appears as "now" in the output.