rust/msrv: 1.85.0 → 1.88.0

`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
This commit is contained in:
Lorenz Leutgeb 2026-05-07 22:31:10 +02:00 committed by Fintan Halpenny
parent 0a0e70b1d1
commit 9ea040ccd0
37 changed files with 263 additions and 264 deletions

View File

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## Minimum Supported Rust Version (MSRV)
The MSRV is updated to `1.88.0` due to dependencies requiring a higher bound.
This effectively puts all published crates in `heartwood` to an MSRV of `1.88.0`.
## Domain Name Migration ## Domain Name Migration
Following a domain move of the project, the names of the bootstrap nodes change: Following a domain move of the project, the names of the bootstrap nodes change:

View File

@ -16,7 +16,7 @@ version = "0.9.0"
# *per crate*. If anyone ever wants to set it to a different # *per crate*. If anyone ever wants to set it to a different
# value per crate, this is of course possible. We're waiting # value per crate, this is of course possible. We're waiting
# for the day it makes a difference… # for the day it makes a difference…
rust-version = "1.85.0" rust-version = "1.88.0"
[workspace.dependencies] [workspace.dependencies]
amplify = { version = "4.0.0", default-features = false } amplify = { version = "4.0.0", default-features = false }

View File

@ -209,12 +209,12 @@ impl TestFormula {
for result in results { for result in results {
match result { match result {
Ok(msg) => { Ok(msg) => {
if let Ok(Message::CompilerArtifact(a)) = msg.decode() { if let Ok(Message::CompilerArtifact(a)) = msg.decode()
if let Some(e) = a.executable { && let Some(e) = a.executable
{
log::debug!(target: "test", "Built {}", e.display()); log::debug!(target: "test", "Built {}", e.display());
} }
} }
}
Err(e) => { Err(e) => {
log::error!(target: "test", "Error building package `{package}`: {e}"); log::error!(target: "test", "Error building package `{package}`: {e}");
} }

View File

@ -38,11 +38,11 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
} }
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };
if let Ok((remote, _)) = git::rad_remote(&repo) { if let Ok((remote, _)) = git::rad_remote(&repo)
if let Some(remote) = remote.url() { && let Some(remote) = remote.url()
{
bail!("repository is already initialized with remote {remote}"); bail!("repository is already initialized with remote {remote}");
} }
}
if let Some(rid) = args.existing { if let Some(rid) = args.existing {
init_existing(repo, rid, args, &profile) init_existing(repo, rid, args, &profile)

View File

@ -261,17 +261,17 @@ where
} }
}; };
if let Some(a) = assignee { if let Some(a) = assignee
if !issue.assignees().any(|v| v == &Did::from(a)) { && !issue.assignees().any(|v| v == &Did::from(a))
{
return None; return None;
} }
}
if let Some(s) = state { if let Some(s) = state
if s != issue.state() { && s != issue.state()
{
return None; return None;
} }
}
Some((id, issue)) Some((id, issue))
}) })

View File

@ -148,11 +148,11 @@ impl Rotate {
/// Remove the existing file, if it exists. Then create the next log, and /// Remove the existing file, if it exists. Then create the next log, and
/// create a hard link to it. /// create a hard link to it.
pub fn execute(self) -> io::Result<Rotated> { pub fn execute(self) -> io::Result<Rotated> {
if let Some(to_remove) = self.remove { if let Some(to_remove) = self.remove
if let Err(err) = to_remove.execute() { && let Err(err) = to_remove.execute()
{
log::warn!(target: "cli", "Failed to remove current log file: {err}"); log::warn!(target: "cli", "Failed to remove current log file: {err}");
} }
}
let log = OpenOptions::new() let log = OpenOptions::new()
.write(true) .write(true)

View File

@ -679,11 +679,11 @@ impl<'a> ReviewBuilder<'a> {
let total = queue.len(); let total = queue.len();
while let Some((ix, item)) = queue.next() { while let Some((ix, item)) = queue.next() {
if let Some(hunk) = self.hunk { if let Some(hunk) = self.hunk
if hunk != ix + 1 { && hunk != ix + 1
{
continue; continue;
} }
}
let progress = term::format::secondary(format!("({}/{total})", ix + 1)); let progress = term::format::secondary(format!("({}/{total})", ix + 1));
let file = match file.as_mut() { let file = match file.as_mut() {
Some(fr) => fr.set_item(&item), Some(fr) => fr.set_item(&item),

View File

@ -27,14 +27,15 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
for rid in rids { for rid in rids {
update(rid, scope, &mut node, &profile)?; update(rid, scope, &mut node, &profile)?;
if should_fetch && node.is_running() { if should_fetch
if let Err(e) = sync::fetch(rid, settings.clone(), &mut node, &profile) { && node.is_running()
&& let Err(e) = sync::fetch(rid, settings.clone(), &mut node, &profile)
{
term::error(e); term::error(e);
} }
} }
} }
} }
}
Ok(()) Ok(())
} }
@ -57,12 +58,12 @@ pub fn update(
let updated = profile.seed(rid, scope, node)?; let updated = profile.seed(rid, scope, node)?;
let outcome = if updated { "updated" } else { "exists" }; let outcome = if updated { "updated" } else { "exists" };
if let Ok(repo) = profile.storage.repository(rid) { if let Ok(repo) = profile.storage.repository(rid)
if repo.identity_doc()?.is_public() { && repo.identity_doc()?.is_public()
{
profile.add_inventory(rid, node)?; profile.add_inventory(rid, node)?;
term::success!("Inventory updated with {}", term::format::tertiary(rid)); term::success!("Inventory updated with {}", term::format::tertiary(rid));
} }
}
term::success!( term::success!(
"Seeding policy {outcome} for {} with scope '{scope}'", "Seeding policy {outcome} for {} with scope '{scope}'",

View File

@ -381,11 +381,11 @@ pub fn commit_ssh_fingerprint(path: &Path, sha1: &str) -> Result<Option<String>,
.transpose()?; .transpose()?;
// We only return a fingerprint if it's not an empty string // We only return a fingerprint if it's not an empty string
if let Some(s) = string { if let Some(s) = string
if !s.is_empty() { && !s.is_empty()
{
return Ok(Some(s)); return Ok(Some(s));
} }
}
Ok(None) Ok(None)
} }

View File

@ -65,11 +65,11 @@ pub fn fail(error: &anyhow::Error) {
} }
// Catch common node errors, and offer a hint. // Catch common node errors, and offer a hint.
if let Some(e) = error.downcast_ref::<radicle::node::Error>() { if let Some(e) = error.downcast_ref::<radicle::node::Error>()
if e.is_connection_err() { && e.is_connection_err()
{
io::hint("to start your node, run `rad node start`."); io::hint("to start your node, run `rad node start`.");
} }
}
if let Some(Error::WithHint { hint, .. }) = error.downcast_ref::<Error>() { if let Some(Error::WithHint { hint, .. }) = error.downcast_ref::<Error>() {
io::hint(hint); io::hint(hint);
} }

View File

@ -39,13 +39,13 @@ impl MigrateCallback for MigrateSpinner {
progress.rows.percentage() progress.rows.percentage()
)); ));
if progress.is_done() { if progress.is_done()
if let Some(spinner) = self.spinner.take() { && let Some(spinner) = self.spinner.take()
{
spinner.finish() spinner.finish()
} }
} }
} }
}
/// Migrate functions. /// Migrate functions.
pub mod migrate { pub mod migrate {

View File

@ -89,11 +89,11 @@ pub fn branches(target: &Oid, repo: &git::raw::Repository) -> anyhow::Result<Vec
if !r.is_branch() { if !r.is_branch() {
continue; continue;
} }
if let (Some(oid), Some(name)) = (&r.target(), &r.shorthand()) { if let (Some(oid), Some(name)) = (&r.target(), &r.shorthand())
if target == oid { && target == oid
{
branches.push(name.to_string()); branches.push(name.to_string());
}; };
};
} }
Ok(branches) Ok(branches)
} }

View File

@ -119,13 +119,13 @@ impl Keystore {
}); });
} }
if let Some(path_public) = &self.path_public { if let Some(path_public) = &self.path_public
if path_public.exists() { && path_public.exists()
{
return Err(Error::AlreadyInitialized { return Err(Error::AlreadyInitialized {
exists: path_public.to_path_buf(), exists: path_public.to_path_buf(),
}); });
} }
}
// NOTE: If [`PathBuf::parent`] returns `None`, // NOTE: If [`PathBuf::parent`] returns `None`,
// then the path is at root or empty, so don't // then the path is at root or empty, so don't

View File

@ -330,8 +330,9 @@ impl<K: Ord + Copy, V> Dag<K, V> {
stack.extend(from.dependents.iter()); stack.extend(from.dependents.iter());
while let Some(key) = stack.pop_front() { while let Some(key) = stack.pop_front() {
if let Some(node) = self.graph.get(&key) { if let Some(node) = self.graph.get(&key)
if visited.insert(key) { && visited.insert(key)
{
nodes.push(key); nodes.push(key);
for &neighbour in &node.dependents { for &neighbour in &node.dependents {
@ -339,7 +340,6 @@ impl<K: Ord + Copy, V> Dag<K, V> {
} }
} }
} }
}
nodes nodes
} }
@ -351,8 +351,9 @@ impl<K: Ord + Copy, V> Dag<K, V> {
stack.extend(from.dependencies.iter()); stack.extend(from.dependencies.iter());
while let Some(key) = stack.pop_front() { while let Some(key) = stack.pop_front() {
if let Some(node) = self.graph.get(&key) { if let Some(node) = self.graph.get(&key)
if visited.insert(key) { && visited.insert(key)
{
nodes.push(key); nodes.push(key);
for &neighbour in &node.dependencies { for &neighbour in &node.dependencies {
@ -360,7 +361,6 @@ impl<K: Ord + Copy, V> Dag<K, V> {
} }
} }
} }
}
nodes nodes
} }

View File

@ -155,12 +155,12 @@ fn parse_body(body: &str) -> (String, Vec<OwnedTrailer>) {
if let Some(split) = body.rfind("\n\n") { if let Some(split) = body.rfind("\n\n") {
let candidate = &body[split + 2..]; let candidate = &body[split + 2..];
// Only treat non-empty paragraphs as trailers. // Only treat non-empty paragraphs as trailers.
if !candidate.trim().is_empty() { if !candidate.trim().is_empty()
if let Some(trailers) = try_parse_trailers(candidate) { && let Some(trailers) = try_parse_trailers(candidate)
{
return (body[..split].to_string(), trailers); return (body[..split].to_string(), trailers);
} }
} }
}
(body.to_string(), Vec::new()) (body.to_string(), Vec::new())
} }

View File

@ -301,16 +301,16 @@ impl<S: Session + Source> EventHandler for Transport<S> {
fn handle(&mut self, event: &Event) -> Vec<Self::Reaction> { fn handle(&mut self, event: &Event) -> Vec<Self::Reaction> {
let mut events = Vec::with_capacity(2); let mut events = Vec::with_capacity(2);
if event.is_writable() { if event.is_writable()
if let Some(event) = self.handle_io(Interest::WRITABLE) { && let Some(event) = self.handle_io(Interest::WRITABLE)
{
events.push(event); events.push(event);
} }
} if event.is_readable()
if event.is_readable() { && let Some(event) = self.handle_io(Interest::READABLE)
if let Some(event) = self.handle_io(Interest::READABLE) { {
events.push(event); events.push(event);
} }
}
events events
} }
} }

View File

@ -174,11 +174,11 @@ impl radicle::node::Handle for Handle {
let sessions = self.sessions()?; let sessions = self.sessions()?;
let session = sessions.iter().find(|s| s.nid == node); let session = sessions.iter().find(|s| s.nid == node);
if let Some(s) = session { if let Some(s) = session
if s.state.is_connected() { && s.state.is_connected()
{
return Ok(ConnectResult::Connected); return Ok(ConnectResult::Connected);
} }
}
self.command(service::Command::Connect(node, addr, opts))?; self.command(service::Command::Connect(node, addr, opts))?;
events events

View File

@ -249,12 +249,12 @@ impl<G: Signer<Signature> + cyphernet::Ecdh> NodeHandle<G> {
let events = self.handle.events(); let events = self.handle.events();
loop { loop {
if let Ok(repo) = self.storage.repository(*rid) { if let Ok(repo) = self.storage.repository(*rid)
if repo.remote(nid).is_ok() { && repo.remote(nid).is_ok()
{
log::debug!(target: "test", "Node {} has {rid}/{nid}", self.id); log::debug!(target: "test", "Node {} has {rid}/{nid}", self.id);
break; break;
} }
}
events events
.wait( .wait(
|e| matches!(e, Event::RefsFetched { .. }).then_some(()), |e| matches!(e, Event::RefsFetched { .. }).then_some(()),

View File

@ -329,9 +329,10 @@ where
pub fn refs_announcement(&self, rid: RepoId) -> Message { pub fn refs_announcement(&self, rid: RepoId) -> Message {
let mut refs = BoundedVec::new(); let mut refs = BoundedVec::new();
if let Ok(repo) = self.storage().repository(rid) { if let Ok(repo) = self.storage().repository(rid)
if let Ok(false) = repo.is_empty() { && let Ok(false) = repo.is_empty()
if let Ok(remotes) = repo.remotes() { && let Ok(remotes) = repo.remotes()
{
for (remote_id, _) in remotes.into_iter() { for (remote_id, _) in remotes.into_iter() {
match RefsAt::new(&repo, remote_id) { match RefsAt::new(&repo, remote_id) {
Ok(refs_at) => { Ok(refs_at) => {
@ -346,8 +347,6 @@ where
} }
} }
} }
}
}
self.announcement(RefsAnnouncement { self.announcement(RefsAnnouncement {
rid, rid,

View File

@ -331,7 +331,7 @@ where
// between individual nodes. We need to think about more realistic // between individual nodes. We need to think about more realistic
// scenarios. We should also think about creating various network // scenarios. We should also think about creating various network
// topologies. // topologies.
if self.time.as_secs() % 10 == 0 { if self.time.as_secs().is_multiple_of(10) {
for (i, x) in nodes.keys().enumerate() { for (i, x) in nodes.keys().enumerate() {
for y in nodes.keys().skip(i + 1) { for y in nodes.keys().skip(i + 1) {
if self.is_fallible() { if self.is_fallible() {

View File

@ -186,14 +186,14 @@ fn notify(
// for sigref verification. // for sigref verification.
continue; continue;
} }
if let Some(rest) = r.strip_prefix(git::fmt::refname!("refs/heads/patches")) { if let Some(rest) = r.strip_prefix(git::fmt::refname!("refs/heads/patches"))
if radicle::cob::ObjectId::from_str(rest.as_str()).is_ok() { && radicle::cob::ObjectId::from_str(rest.as_str()).is_ok()
{
// Don't notify about patch branches, since we already get // Don't notify about patch branches, since we already get
// notifications about patch updates. // notifications about patch updates.
continue; continue;
} }
} }
}
if let RefUpdate::Skipped { .. } = update { if let RefUpdate::Skipped { .. } = update {
// Don't notify about skipped refs. // Don't notify about skipped refs.
} else if let Err(e) = store.insert(rid, update, now) { } else if let Err(e) = store.insert(rid, update, now) {

View File

@ -464,11 +464,11 @@ where
continue; continue;
}; };
// Skip this repo if the sync status matches what we have in storage. // Skip this repo if the sync status matches what we have in storage.
if let Some(announced) = announced.get(&rid) { if let Some(announced) = announced.get(&rid)
if updated_at.oid == announced.oid { && updated_at.oid == announced.oid
{
continue; continue;
} }
}
// Make sure our local node's sync status is up to date with storage. // Make sure our local node's sync status is up to date with storage.
if self.db.seeds_mut().synced( if self.db.seeds_mut().synced(
&rid, &rid,
@ -1300,17 +1300,15 @@ where
self.outbox.write_all(peer, msgs); self.outbox.write_all(peer, msgs);
} }
Entry::Vacant(e) => { Entry::Vacant(e) => {
if let HostName::Ip(ip) = addr.host { if let HostName::Ip(ip) = addr.host
if !address::is_local(&ip) { && !address::is_local(&ip)
if let Err(e) = && let Err(e) =
self.db self.db
.addresses_mut() .addresses_mut()
.record_ip(&remote, ip, self.clock.into()) .record_ip(&remote, ip, self.clock.into())
{ {
log::debug!(target: "service", "Failed to record IP address for {remote}: {e}"); log::debug!(target: "service", "Failed to record IP address for {remote}: {e}");
} }
}
}
let peer = e.insert(Session::inbound( let peer = e.insert(Session::inbound(
remote, remote,
addr, addr,
@ -1811,8 +1809,9 @@ where
let relayer = remote; let relayer = remote;
let relayer_addr = peer.addr.clone(); let relayer_addr = peer.addr.clone();
if let Some(id) = self.handle_announcement(relayer, &relayer_addr, &ann)? { if let Some(id) = self.handle_announcement(relayer, &relayer_addr, &ann)?
if self.config.is_relay() { && self.config.is_relay()
{
if let AnnouncementMessage::Inventory(_) = ann.message { if let AnnouncementMessage::Inventory(_) = ann.message {
if let Err(e) = self if let Err(e) = self
.database_mut() .database_mut()
@ -1827,7 +1826,6 @@ where
} }
} }
} }
}
Message::Subscribe(subscribe) => { Message::Subscribe(subscribe) => {
// Filter announcements by interest. // Filter announcements by interest.
match self match self
@ -1876,13 +1874,13 @@ where
); );
} }
Message::Pong { zeroes } => { Message::Pong { zeroes } => {
if let Some((ping, latencies)) = connected { if let Some((ping, latencies)) = connected
if let session::PingState::AwaitingResponse { && let session::PingState::AwaitingResponse {
len: ponglen, len: ponglen,
since, since,
} = *ping } = *ping
&& (ponglen as usize) == zeroes.len()
{ {
if (ponglen as usize) == zeroes.len() {
*ping = session::PingState::Ok; *ping = session::PingState::Ok;
// Keep track of peer latency. // Keep track of peer latency.
latencies.push_back(self.clock - since); latencies.push_back(self.clock - since);
@ -1892,8 +1890,6 @@ where
} }
} }
} }
}
}
Ok(()) Ok(())
} }
@ -1929,13 +1925,13 @@ where
/// Add a seed to our routing table. /// Add a seed to our routing table.
fn seed_discovered(&mut self, rid: RepoId, nid: NodeId, time: Timestamp) { fn seed_discovered(&mut self, rid: RepoId, nid: NodeId, time: Timestamp) {
if let Ok(result) = self.db.routing_mut().add_inventory([&rid], nid, time) { if let Ok(result) = self.db.routing_mut().add_inventory([&rid], nid, time)
if let &[(_, InsertResult::SeedAdded)] = result.as_slice() { && let &[(_, InsertResult::SeedAdded)] = result.as_slice()
{
self.emitter.emit(Event::SeedDiscovered { rid, nid }); self.emitter.emit(Event::SeedDiscovered { rid, nid });
debug!(target: "service", "Routing table updated for {rid} with seed {nid}"); debug!(target: "service", "Routing table updated for {rid} with seed {nid}");
} }
} }
}
/// Set of initial messages to send to a peer. /// Set of initial messages to send to a peer.
fn initial(&mut self, _link: Link) -> Vec<Message> { fn initial(&mut self, _link: Link) -> Vec<Message> {

View File

@ -36,11 +36,11 @@ impl RateLimiter {
tokens: &T, tokens: &T,
now: LocalTime, now: LocalTime,
) -> bool { ) -> bool {
if let Some(nid) = nid { if let Some(nid) = nid
if self.bypass.contains(nid) { && self.bypass.contains(nid)
{
return false; return false;
} }
}
if let HostName::Ip(ip) = addr { if let HostName::Ip(ip) = addr {
// Don't limit LAN addresses. // Don't limit LAN addresses.
if !address::is_routable(&ip) { if !address::is_routable(&ip) {

View File

@ -218,14 +218,14 @@ impl Session {
ref mut stable, ref mut stable,
.. ..
} = self.state } = self.state
&& now >= since
&& now.duration_since(since) >= CONNECTION_STABLE_THRESHOLD
{ {
if now >= since && now.duration_since(since) >= CONNECTION_STABLE_THRESHOLD {
*stable = true; *stable = true;
// Reset number of attempts for stable connections. // Reset number of attempts for stable connections.
self.attempts = 0; self.attempts = 0;
} }
} }
}
pub fn to_attempted(&mut self) { pub fn to_attempted(&mut self) {
assert!( assert!(

View File

@ -245,11 +245,11 @@ fn run(profile: radicle::Profile) -> Result<(), Error> {
let git = service::RealGitService; let git = service::RealGitService;
let mut node = service::RealNodeSession::new(&profile); let mut node = service::RealNodeSession::new(&profile);
if let Err(e) = radicle::io::set_file_limit(4096) { if let Err(e) = radicle::io::set_file_limit(4096)
if debug { && debug
{
eprintln!("{}: unable to set open file limit: {e}", VERSION.name); eprintln!("{}: unable to set open file limit: {e}", VERSION.name);
} }
}
run_loop( run_loop(
stdin.lock(), stdin.lock(),

View File

@ -662,9 +662,9 @@ where
// Set up current branch so that pushing updates the patch. // Set up current branch so that pushing updates the patch.
else if let Some(branch) = else if let Some(branch) =
rad::setup_patch_upstream(&patch, *head, working, upstream, false)? rad::setup_patch_upstream(&patch, *head, working, upstream, false)?
&& let Some(name) = branch.name()?
&& profile.hints()
{ {
if let Some(name) = branch.name()? {
if profile.hints() {
// Remove the remote portion of the name, i.e. // Remove the remote portion of the name, i.e.
// rad/patches/deadbeef -> patches/deadbeef // rad/patches/deadbeef -> patches/deadbeef
let name = name.split_once('/').unwrap_or_default().1; let name = name.split_once('/').unwrap_or_default().1;
@ -673,8 +673,6 @@ where
)); ));
} }
} }
}
}
Ok(Some(ExplorerResource::Patch { id: patch })) Ok(Some(ExplorerResource::Patch { id: patch }))
} }

View File

@ -204,16 +204,16 @@ impl Editor {
/// Get the default editor command. /// Get the default editor command.
fn default_editor() -> Option<OsString> { fn default_editor() -> Option<OsString> {
// First check the standard environment variables. // First check the standard environment variables.
if let Ok(visual) = env::var("VISUAL") { if let Ok(visual) = env::var("VISUAL")
if !visual.is_empty() { && !visual.is_empty()
{
return Some(visual.into()); return Some(visual.into());
} }
} if let Ok(editor) = env::var("EDITOR")
if let Ok(editor) = env::var("EDITOR") { && !editor.is_empty()
if !editor.is_empty() { {
return Some(editor.into()); return Some(editor.into());
} }
}
// Check Git. The user might have configured their editor there. // Check Git. The user might have configured their editor there.
// On Windows, custom editors configured via Git are not supported, // On Windows, custom editors configured via Git are not supported,

View File

@ -59,11 +59,11 @@ pub struct Spinner {
impl Drop for Spinner { impl Drop for Spinner {
fn drop(&mut self) { fn drop(&mut self) {
if let Ok(mut progress) = self.progress.lock() { if let Ok(mut progress) = self.progress.lock()
if let State::Running = progress.state { && let State::Running = progress.state
{
progress.state = State::Canceled; progress.state = State::Canceled;
} }
}
unsafe { ManuallyDrop::take(&mut self.handle) } unsafe { ManuallyDrop::take(&mut self.handle) }
.join() .join()

View File

@ -48,14 +48,14 @@ pub fn run(
.ok_or(Error::MalformedJsonSchema)?; .ok_or(Error::MalformedJsonSchema)?;
for (_, review) in reviews.iter_mut() { for (_, review) in reviews.iter_mut() {
if let Some(list) = review.as_array_mut() { if let Some(list) = review.as_array_mut()
if let Some(last) = list.pop() { && let Some(last) = list.pop()
{
*review = last; *review = last;
transformed = true; transformed = true;
} }
} }
} }
}
if transformed { if transformed {
let obj = json::to_string(&patch).map_err(Error::MalformedJson)?; let obj = json::to_string(&patch).map_err(Error::MalformedJson)?;

View File

@ -726,11 +726,11 @@ impl Patch {
review, comment, .. review, comment, ..
} }
| Action::ReviewCommentRedact { review, comment } => { | Action::ReviewCommentRedact { review, comment } => {
if let Some((_, review)) = lookup::review(self, review)? { if let Some((_, review)) = lookup::review(self, review)?
if let Some(comment) = review.comments.comment(comment) { && let Some(comment) = review.comments.comment(comment)
{
return Ok(Authorization::from(*actor == comment.author())); return Ok(Authorization::from(*actor == comment.author()));
} }
}
// Redacted. // Redacted.
Authorization::Unknown Authorization::Unknown
} }
@ -739,15 +739,15 @@ impl Patch {
// The reviewer, commenter or revision author can resolve and unresolve review comments. // The reviewer, commenter or revision author can resolve and unresolve review comments.
Action::ReviewCommentResolve { review, comment } Action::ReviewCommentResolve { review, comment }
| Action::ReviewCommentUnresolve { review, comment } => { | Action::ReviewCommentUnresolve { review, comment } => {
if let Some((revision, review)) = lookup::review(self, review)? { if let Some((revision, review)) = lookup::review(self, review)?
if let Some(comment) = review.comments.comment(comment) { && let Some(comment) = review.comments.comment(comment)
{
return Ok(Authorization::from( return Ok(Authorization::from(
actor == &comment.author() actor == &comment.author()
|| actor == review.author.public_key() || actor == review.author.public_key()
|| actor == revision.author.public_key(), || actor == revision.author.public_key(),
)); ));
} }
}
// Redacted. // Redacted.
Authorization::Unknown Authorization::Unknown
} }
@ -773,11 +773,11 @@ impl Patch {
| Action::RevisionCommentRedact { | Action::RevisionCommentRedact {
revision, comment, .. revision, comment, ..
} => { } => {
if let Some(revision) = lookup::revision(self, revision)? { if let Some(revision) = lookup::revision(self, revision)?
if let Some(comment) = revision.discussion.comment(comment) { && let Some(comment) = revision.discussion.comment(comment)
{
return Ok(Authorization::from(actor == &comment.author())); return Ok(Authorization::from(actor == &comment.author()));
} }
}
// Redacted. // Redacted.
Authorization::Unknown Authorization::Unknown
} }

View File

@ -399,11 +399,11 @@ impl<L> Thread<Comment<L>> {
to: &'a CommentId, to: &'a CommentId,
) -> impl Iterator<Item = (&'a CommentId, &'a Comment<L>)> { ) -> impl Iterator<Item = (&'a CommentId, &'a Comment<L>)> {
self.comments().filter_map(move |(id, c)| { self.comments().filter_map(move |(id, c)| {
if let Some(reply_to) = c.reply_to { if let Some(reply_to) = c.reply_to
if &reply_to == to { && &reply_to == to
{
return Some((id, c)); return Some((id, c));
} }
}
None None
}) })
} }
@ -503,11 +503,11 @@ pub fn comment<L>(
if body.is_empty() { if body.is_empty() {
return Err(Error::Comment(id)); return Err(Error::Comment(id));
} }
if let Some(id) = reply_to { if let Some(id) = reply_to
if !thread.comments.contains_key(&id) { && !thread.comments.contains_key(&id)
{
return Err(Error::Missing(id)); return Err(Error::Missing(id));
} }
}
debug_assert!(!thread.timeline.contains(&id)); debug_assert!(!thread.timeline.contains(&id));
thread.timeline.push(id); thread.timeline.push(id);

View File

@ -347,20 +347,20 @@ impl SymbolicRefs {
// A [`Target::Direct`] whose string is already a key is actually // A [`Target::Direct`] whose string is already a key is actually
// an intermediate link — downgrade to [`Target::Symbolic`]. // an intermediate link — downgrade to [`Target::Symbolic`].
if let Target::Direct(q) = &target { if let Target::Direct(q) = &target
if self.0.contains_key(&q.as_ref().to_ref_string()) { && self.0.contains_key(&q.as_ref().to_ref_string())
{
target = Target::symbolic(q.to_ref_string()); target = Target::symbolic(q.to_ref_string());
} }
}
if let Target::Symbolic(s) = &target { if let Target::Symbolic(s) = &target
if self.resolve(s.as_ref()).is_none() { && self.resolve(s.as_ref()).is_none()
{
return Err(InsertionError::TargetNotQualified { return Err(InsertionError::TargetNotQualified {
name: name.into_inner(), name: name.into_inner(),
target: target_str, target: target_str,
}); });
} }
}
self.reclassify_targets(&name); self.reclassify_targets(&name);
self.0.insert(name, target); self.0.insert(name, target);
@ -373,14 +373,14 @@ impl SymbolicRefs {
fn reclassify_targets(&mut self, new_key: &Name) { fn reclassify_targets(&mut self, new_key: &Name) {
let key = new_key.as_ref(); let key = new_key.as_ref();
for existing in self.0.values_mut() { for existing in self.0.values_mut() {
if let Target::Direct(q) = existing { if let Target::Direct(q) = existing
if q == key { && q == key
{
*existing = Target::symbolic(q.to_ref_string()); *existing = Target::symbolic(q.to_ref_string());
} }
} }
} }
} }
}
impl TryFrom<IndexMap<Name, Unprotected<RefString>>> for SymbolicRefs { impl TryFrom<IndexMap<Name, Unprotected<RefString>>> for SymbolicRefs {
type Error = InsertionError; type Error = InsertionError;

View File

@ -91,11 +91,11 @@ pub mod env {
// because of the complexity surrounding how the pager command is // because of the complexity surrounding how the pager command is
// parsed and executed. See also <https://stackoverflow.com/a/773973/1835188>. // parsed and executed. See also <https://stackoverflow.com/a/773973/1835188>.
#[cfg(not(windows))] #[cfg(not(windows))]
if let Ok(cfg) = crate::git::raw::Config::open_default() { if let Ok(cfg) = crate::git::raw::Config::open_default()
if let Ok(pager) = cfg.get_string("core.pager") { && let Ok(pager) = cfg.get_string("core.pager")
{
return Some(pager); return Some(pager);
} }
}
if let Ok(pager) = var("PAGER") { if let Ok(pager) = var("PAGER") {
return Some(pager); return Some(pager);
} }

View File

@ -187,11 +187,12 @@ impl Config {
// Handle deprecated policy configuration. // Handle deprecated policy configuration.
// Nb. This will override "seedingPolicy" if set! This code should be removed after 1.0. // Nb. This will override "seedingPolicy" if set! This code should be removed after 1.0.
if let (Some(p), Some(s)) = (cfg.node.extra.get("policy"), cfg.node.extra.get("scope")) { if let (Some(p), Some(s)) = (cfg.node.extra.get("policy"), cfg.node.extra.get("scope"))
if let (Ok(policy), Ok(scope)) = ( && let (Ok(policy), Ok(scope)) = (
json::from_value::<Policy>(p.clone()), json::from_value::<Policy>(p.clone()),
json::from_value::<Scope>(s.clone()), json::from_value::<Scope>(s.clone()),
) { )
{
log::warn!(target: "radicle", "Overwriting `seedingPolicy` configuration"); log::warn!(target: "radicle", "Overwriting `seedingPolicy` configuration");
cfg.node.seeding_policy = match policy { cfg.node.seeding_policy = match policy {
Policy::Allow => DefaultSeedingPolicy::Allow { Policy::Allow => DefaultSeedingPolicy::Allow {
@ -200,7 +201,6 @@ impl Config {
Policy::Block => DefaultSeedingPolicy::Block, Policy::Block => DefaultSeedingPolicy::Block,
} }
} }
}
Ok(cfg) Ok(cfg)
} }

View File

@ -85,11 +85,11 @@ where
if let Err(e) = project.remove() { if let Err(e) = project.remove() {
log::warn!(target: "radicle", "Failed to remove project during `rad::init` cleanup: {e}"); log::warn!(target: "radicle", "Failed to remove project during `rad::init` cleanup: {e}");
} }
if repo.find_remote(&REMOTE_NAME).is_ok() { if repo.find_remote(&REMOTE_NAME).is_ok()
if let Err(e) = repo.remote_delete(&REMOTE_NAME) { && let Err(e) = repo.remote_delete(&REMOTE_NAME)
{
log::warn!(target: "radicle", "Failed to remove remote during `rad::init` cleanup: {e}"); log::warn!(target: "radicle", "Failed to remove remote during `rad::init` cleanup: {e}");
} }
}
Err(err) Err(err)
} }
} }
@ -497,11 +497,11 @@ pub fn setup_patch_upstream<'a>(
)?; )?;
assert!(remote_branch.is_remote()); assert!(remote_branch.is_remote());
if let Some(name) = name { if let Some(name) = name
if force || branch.upstream().is_err() { && (force || branch.upstream().is_err())
{
git::set_upstream(working, remote, name.as_str(), git::refs::patch(patch))?; git::set_upstream(working, remote, name.as_str(), git::refs::patch(patch))?;
} }
}
Ok(Some(crate::git::raw::Branch::wrap(remote_branch))) Ok(Some(crate::git::raw::Branch::wrap(remote_branch)))
} }

View File

@ -842,11 +842,11 @@ impl ReadRepository for Repository {
fn head(&self) -> Result<(Qualified<'_>, Oid), RepositoryError> { fn head(&self) -> Result<(Qualified<'_>, Oid), RepositoryError> {
// If `HEAD` is already set locally, just return that. // If `HEAD` is already set locally, just return that.
if let Ok(head) = self.backend.head() { if let Ok(head) = self.backend.head()
if let Ok((name, oid)) = git::refs::qualified_from(&head) { && let Ok((name, oid)) = git::refs::qualified_from(&head)
{
return Ok((name.to_owned(), oid)); return Ok((name.to_owned(), oid));
} }
}
self.canonical_head() self.canonical_head()
} }

View File

@ -34,13 +34,13 @@ pub fn fetch<W: WriteRepository>(
}; };
callbacks.update_tips(|name, old, new| { callbacks.update_tips(|name, old, new| {
if let Ok(name) = git::fmt::RefString::try_from(name) { if let Ok(name) = git::fmt::RefString::try_from(name)
if name.to_namespaced().is_some() { && name.to_namespaced().is_some()
{
updates.push(RefUpdate::from(name, old, new)); updates.push(RefUpdate::from(name, old, new));
// Returning `true` ensures the process is not aborted. // Returning `true` ensures the process is not aborted.
return true; return true;
} }
}
false false
}); });
opts.remote_callbacks(callbacks); opts.remote_callbacks(callbacks);