cli/config: Obsolete `{get,set,push,remove,unset}`

This commit is contained in:
Lorenz Leutgeb 2026-04-20 16:41:59 +02:00 committed by Fintan Halpenny
parent f83eb57719
commit bbb1279604
5 changed files with 58 additions and 12 deletions

View File

@ -28,6 +28,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
connections via SOCKS proxy and I2P for `*.i2p{,.alt}` names is now supported. connections via SOCKS proxy and I2P for `*.i2p{,.alt}` names is now supported.
To enable making connections via I2P, configure `node.i2p`. To enable making connections via I2P, configure `node.i2p`.
## Deprecations
- The commands to read and modify particular values in Radicle configuration via
the CLI, i.e.,
- `rad config get`
- `rad config push`
- `rad config remove`
- `rad config set`
- `rad config unset`
were marked as obsolete. In the future, please modify Radicle configuration
with your favorite text editor (e.g. via `rad config edit`), or specialized
tools like `jq`.
## 1.8.0 ## 1.8.0
## New Features ## New Features

View File

@ -5,10 +5,13 @@ use args::Command;
use std::path::Path; use std::path::Path;
use radicle::profile::{Config, ConfigPath, RawConfig, config}; use radicle::profile::{Config, config};
#[allow(deprecated)]
use radicle::profile::config::{ConfigPath, RawConfig};
use crate::terminal as term;
use crate::terminal::Element as _; use crate::terminal::Element as _;
use crate::{terminal as term, warning};
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> { pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
let home = ctx.home()?; let home = ctx.home()?;
@ -23,6 +26,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
Command::Schema => { Command::Schema => {
term::json::to_pretty(&schemars::schema_for!(Config), path.as_path())?.print() term::json::to_pretty(&schemars::schema_for!(Config), path.as_path())?.print()
} }
#[allow(deprecated)]
Command::Get { key } => { Command::Get { key } => {
let mut temp_config = RawConfig::from_file(&path)?; let mut temp_config = RawConfig::from_file(&path)?;
let key: ConfigPath = key.into(); let key: ConfigPath = key.into();
@ -31,19 +35,27 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
})?; })?;
print_value(value)?; print_value(value)?;
} }
#[allow(deprecated)]
Command::Set { key, value } => { Command::Set { key, value } => {
warning::obsolete("rad config set");
let value = modify(path, |tmp| tmp.set(&key.into(), value.into()))?; let value = modify(path, |tmp| tmp.set(&key.into(), value.into()))?;
print_value(&value)?; print_value(&value)?;
} }
#[allow(deprecated)]
Command::Push { key, value } => { Command::Push { key, value } => {
warning::obsolete("rad config push");
let value = modify(path, |tmp| tmp.push(&key.into(), value.into()))?; let value = modify(path, |tmp| tmp.push(&key.into(), value.into()))?;
print_value(&value)?; print_value(&value)?;
} }
#[allow(deprecated)]
Command::Remove { key, value } => { Command::Remove { key, value } => {
warning::obsolete("rad config remove");
let value = modify(path, |tmp| tmp.remove(&key.into(), value.into()))?; let value = modify(path, |tmp| tmp.remove(&key.into(), value.into()))?;
print_value(&value)?; print_value(&value)?;
} }
#[allow(deprecated)]
Command::Unset { key } => { Command::Unset { key } => {
warning::obsolete("rad config unset");
let value = modify(path, |tmp| tmp.unset(&key.into()))?; let value = modify(path, |tmp| tmp.unset(&key.into()))?;
print_value(&value)?; print_value(&value)?;
} }
@ -68,6 +80,8 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
Ok(()) Ok(())
} }
#[deprecated]
#[allow(deprecated)]
fn modify<P, M>(path: P, modification: M) -> anyhow::Result<serde_json::Value> fn modify<P, M>(path: P, modification: M) -> anyhow::Result<serde_json::Value>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -83,6 +97,8 @@ where
} }
/// Print a JSON Value. /// Print a JSON Value.
#[deprecated]
#[allow(deprecated)]
fn print_value(value: &serde_json::Value) -> anyhow::Result<()> { fn print_value(value: &serde_json::Value) -> anyhow::Result<()> {
match value { match value {
serde_json::Value::Null => {} serde_json::Value::Null => {}

View File

@ -29,6 +29,8 @@ pub(crate) enum Command {
/// Open the config in your editor /// Open the config in your editor
Edit, Edit,
/// Get a value from the current configuration /// Get a value from the current configuration
// Command is obsolete.
#[command(hide = true)]
Get { Get {
/// The JSON key path to the value you want to get /// The JSON key path to the value you want to get
key: String, key: String,
@ -36,6 +38,8 @@ pub(crate) enum Command {
/// Prints the JSON Schema of the Radicle configuration /// Prints the JSON Schema of the Radicle configuration
Schema, Schema,
/// Set a key to a value in the current configuration /// Set a key to a value in the current configuration
// Command is obsolete.
#[command(hide = true)]
Set { Set {
/// The JSON key path to the value you want to set /// The JSON key path to the value you want to set
key: String, key: String,
@ -43,12 +47,16 @@ pub(crate) enum Command {
value: String, value: String,
}, },
/// Set a key in the current configuration to `null` /// Set a key in the current configuration to `null`
// Command is obsolete.
#[command(hide = true)]
Unset { Unset {
/// The JSON key path to the value you want to unset /// The JSON key path to the value you want to unset
key: String, key: String,
}, },
/// Push a value onto an array, which is identified by the key, in the /// Push a value onto an array, which is identified by the key, in the
/// current configuration /// current configuration
// Command is obsolete.
#[command(hide = true)]
Push { Push {
/// The JSON key path to the array you want to push to /// The JSON key path to the array you want to push to
key: String, key: String,
@ -59,6 +67,8 @@ pub(crate) enum Command {
/// current configuration /// current configuration
/// ///
/// All instances of the value in the array will be removed /// All instances of the value in the array will be removed
// Command is obsolete.
#[command(hide = true)]
Remove { Remove {
/// The JSON key path to the array you want to push to /// The JSON key path to the array you want to push to
key: String, key: String,

View File

@ -12,7 +12,7 @@
//! //!
pub mod config; pub mod config;
pub use config::{Config, ConfigPath, RawConfig, WriteError}; pub use config::{Config, WriteError};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};

View File

@ -206,15 +206,8 @@ impl Config {
/// Write configuration to disk. /// Write configuration to disk.
pub fn write(&self, path: &Path) -> Result<(), WriteError> { pub fn write(&self, path: &Path) -> Result<(), WriteError> {
let value = json::to_value(self).map_err(|err| WriteError::to_json(path, err))?; let contents = json::to_vec_pretty(self).map_err(|err| WriteError::to_json(path, err))?;
let tmp = RawConfig(value); fs::write(path, contents).map_err(|err| WriteError::write_file(path, err))
let file = fs::OpenOptions::new()
.create_new(true)
.write(true)
.open(path)
.map_err(|err| WriteError::open_file(path, err))?;
tmp.write_file(path, file)
} }
/// Get the user alias. /// Get the user alias.
@ -225,9 +218,11 @@ impl Config {
/// Offers utility functions for editing the configuration. Validates on write. /// Offers utility functions for editing the configuration. Validates on write.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[deprecated]
pub struct RawConfig(json::Value); pub struct RawConfig(json::Value);
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[allow(deprecated)]
pub enum ModifyError { pub enum ModifyError {
#[error("the path provided was empty")] #[error("the path provided was empty")]
EmptyPath, EmptyPath,
@ -241,6 +236,7 @@ pub enum ModifyError {
Upsert { key: String }, Upsert { key: String },
} }
#[allow(deprecated)]
impl RawConfig { impl RawConfig {
/// Creates a temporary configuration, by reading a configuration file from disk. /// Creates a temporary configuration, by reading a configuration file from disk.
pub fn from_file(path: &Path) -> Result<Self, WriteError> { pub fn from_file(path: &Path) -> Result<Self, WriteError> {
@ -396,6 +392,7 @@ impl RawConfig {
} }
} }
#[allow(deprecated)]
impl TryFrom<RawConfig> for Config { impl TryFrom<RawConfig> for Config {
type Error = json::Error; type Error = json::Error;
@ -406,11 +403,14 @@ impl TryFrom<RawConfig> for Config {
/// A struct that ensures all values are safe for JSON serialization, including handling special /// A struct that ensures all values are safe for JSON serialization, including handling special
/// floating point values like `NaN` and `Infinity`. Use the `From<&str>` implementation to create an instance. /// floating point values like `NaN` and `Infinity`. Use the `From<&str>` implementation to create an instance.
#[deprecated]
#[allow(deprecated)]
pub struct ConfigValue(RawConfigValue); pub struct ConfigValue(RawConfigValue);
/// This enum represents raw configuration values and should not be used directly. /// This enum represents raw configuration values and should not be used directly.
/// Use the `ConfigValue` type, which validates values using its `From<&str>` implementation. /// Use the `ConfigValue` type, which validates values using its `From<&str>` implementation.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[deprecated]
enum RawConfigValue { enum RawConfigValue {
Integer(i64), Integer(i64),
Float(f64), Float(f64),
@ -418,6 +418,7 @@ enum RawConfigValue {
String(String), String(String),
} }
#[allow(deprecated)]
impl From<&str> for ConfigValue { impl From<&str> for ConfigValue {
/// Guess the type of a Value. /// Guess the type of a Value.
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
@ -438,12 +439,14 @@ impl From<&str> for ConfigValue {
} }
} }
#[allow(deprecated)]
impl From<String> for ConfigValue { impl From<String> for ConfigValue {
fn from(value: String) -> Self { fn from(value: String) -> Self {
value.as_str().into() value.as_str().into()
} }
} }
#[allow(deprecated)]
impl From<ConfigValue> for json::Value { impl From<ConfigValue> for json::Value {
fn from(value: ConfigValue) -> Self { fn from(value: ConfigValue) -> Self {
match value { match value {
@ -461,8 +464,10 @@ impl From<ConfigValue> for json::Value {
/// Configuration attribute path. /// Configuration attribute path.
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
#[deprecated]
pub struct ConfigPath(Vec<String>); pub struct ConfigPath(Vec<String>);
#[allow(deprecated)]
impl ConfigPath { impl ConfigPath {
fn parent(&self) -> Option<Self> { fn parent(&self) -> Option<Self> {
self.0.split_last().map(|(_, tail)| Self(tail.to_vec())) self.0.split_last().map(|(_, tail)| Self(tail.to_vec()))
@ -477,12 +482,14 @@ impl ConfigPath {
} }
} }
#[allow(deprecated)]
impl fmt::Display for ConfigPath { impl fmt::Display for ConfigPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.join(".")) write!(f, "{}", self.0.join("."))
} }
} }
#[allow(deprecated)]
impl From<String> for ConfigPath { impl From<String> for ConfigPath {
fn from(value: String) -> Self { fn from(value: String) -> Self {
let parts: Vec<String> = value.split('.').map(|s| s.to_string()).collect(); let parts: Vec<String> = value.split('.').map(|s| s.to_string()).collect();