radicle: Prevent `RAD_SOCKET` from polluting tests
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`.
This commit is contained in:
parent
a2de55cbb9
commit
80c1bba76f
|
|
@ -30,7 +30,7 @@ pub use args::Args;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
if !node.is_running() {
|
if !node.is_running() {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use args::Operation;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
match Operation::from(args) {
|
match Operation::from(args) {
|
||||||
Operation::Follow { nid, alias, .. } => follow(nid, alias, &mut node, &profile)?,
|
Operation::Follow { nid, alias, .. } => follow(nid, alias, &mut node, &profile)?,
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ pub fn init(repo: git::Repository, args: Args, profile: &profile::Profile) -> an
|
||||||
};
|
};
|
||||||
|
|
||||||
let signer = term::signer(profile)?;
|
let signer = term::signer(profile)?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
let mut spinner = term::spinner("Initializing...");
|
let mut spinner = term::spinner("Initializing...");
|
||||||
let mut push_cmd = String::from("git push");
|
let mut push_cmd = String::from("git push");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if announce {
|
if announce {
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket_from_env());
|
||||||
node::announce(
|
node::announce(
|
||||||
&repo,
|
&repo,
|
||||||
node::SyncSettings::default(),
|
node::SyncSettings::default(),
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use args::{Addr, Command};
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
let command = args.command.unwrap_or_default();
|
let command = args.command.unwrap_or_default();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if announce {
|
if announce {
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket_from_env());
|
||||||
node::announce(
|
node::announce(
|
||||||
&repository,
|
&repository,
|
||||||
node::SyncSettings::default(),
|
node::SyncSettings::default(),
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
anyhow::bail!("fatal: repository storage is corrupt");
|
anyhow::bail!("fatal: repository storage is corrupt");
|
||||||
}
|
}
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
let spinner = term::spinner("Updating inventory..");
|
let spinner = term::spinner("Updating inventory..");
|
||||||
|
|
||||||
// The repository is now part of our inventory.
|
// The repository is now part of our inventory.
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ pub fn run(
|
||||||
sync: bool,
|
sync: bool,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if sync {
|
if sync {
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
if !profile.policies()?.is_following(nid)? {
|
if !profile.policies()?.is_following(nid)? {
|
||||||
let alias = name.as_ref().and_then(|n| Alias::from_str(n.as_str()).ok());
|
let alias = name.as_ref().and_then(|n| Alias::from_str(n.as_str()).ok());
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub use args::Args;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
match args::Operation::from(args) {
|
match args::Operation::from(args) {
|
||||||
args::Operation::List => seeding(&profile)?,
|
args::Operation::List => seeding(&profile)?,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
} else if args.nid {
|
} else if args.nid {
|
||||||
crate::warning::deprecated("rad self --nid", "rad node status --only nid");
|
crate::warning::deprecated("rad self --nid", "rad node status --only nid");
|
||||||
term::print(
|
term::print(
|
||||||
Node::new(profile.socket())
|
Node::new(profile.socket_from_env())
|
||||||
.nid()
|
.nid()
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_else(|| *profile.id()),
|
.unwrap_or_else(|| *profile.id()),
|
||||||
|
|
@ -54,7 +54,7 @@ fn all(profile: &Profile) -> anyhow::Result<()> {
|
||||||
term::format::tertiary(did).into(),
|
term::format::tertiary(did).into(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let socket = profile.socket();
|
let socket = profile.socket_from_env();
|
||||||
let node = if Node::new(&socket).is_running() {
|
let node = if Node::new(&socket).is_running() {
|
||||||
term::format::positive(format!("running ({})", socket.display()))
|
term::format::positive(format!("running ({})", socket.display()))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ use args::{Command, SortBy, SyncDirection, SyncMode};
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
if !node.is_running() {
|
if !node.is_running() {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"to sync a repository, your node must be running. To start it, run `rad node start`"
|
"to sync a repository, your node must be running. To start it, run `rad node start`"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub use args::Args;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
let nid = args.nid;
|
let nid = args.nid;
|
||||||
|
|
||||||
let unfollowed = match node.unfollow(nid) {
|
let unfollowed = match node.unfollow(nid) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub use args::Args;
|
||||||
|
|
||||||
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(args: Args, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let mut node = radicle::Node::new(profile.socket());
|
let mut node = radicle::Node::new(profile.socket_from_env());
|
||||||
|
|
||||||
for rid in args.rids {
|
for rid in args.rids {
|
||||||
delete(rid, &mut node, &profile)?;
|
delete(rid, &mut node, &profile)?;
|
||||||
|
|
|
||||||
|
|
@ -329,11 +329,12 @@ fn execute(options: Options) -> Result<(), ExecutionError> {
|
||||||
signals
|
signals
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let socket = home.socket_from_env();
|
||||||
if options.force {
|
if options.force {
|
||||||
log::debug!(target: "node", "Removing existing control socket..");
|
log::debug!(target: "node", "Removing existing control socket..");
|
||||||
std::fs::remove_file(home.socket()).ok();
|
std::fs::remove_file(&socket).ok();
|
||||||
}
|
}
|
||||||
Runtime::init(home, config.node, listen, signals, signer)?.run()?;
|
Runtime::init(home, config.node, socket, listen, signals, signer)?.run()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ impl Runtime {
|
||||||
pub fn init<G>(
|
pub fn init<G>(
|
||||||
home: Home,
|
home: Home,
|
||||||
config: radicle::node::Config,
|
config: radicle::node::Config,
|
||||||
|
socket: PathBuf,
|
||||||
listen: Vec<net::SocketAddr>,
|
listen: Vec<net::SocketAddr>,
|
||||||
signals: chan::Receiver<Signal>,
|
signals: chan::Receiver<Signal>,
|
||||||
signer: Device<G>,
|
signer: Device<G>,
|
||||||
|
|
@ -233,7 +234,7 @@ impl Runtime {
|
||||||
wire.listen(listener);
|
wire.listen(listener);
|
||||||
}
|
}
|
||||||
let reactor = Reactor::new(wire, thread::name(&id, "service"))?;
|
let reactor = Reactor::new(wire, thread::name(&id, "service"))?;
|
||||||
let handle = Handle::new(home.clone(), reactor.controller(), emitter);
|
let handle = Handle::new(home.clone(), socket.clone(), reactor.controller(), emitter);
|
||||||
|
|
||||||
let nid = *signer.public_key();
|
let nid = *signer.public_key();
|
||||||
let fetch = worker::FetchConfig {
|
let fetch = worker::FetchConfig {
|
||||||
|
|
@ -255,7 +256,7 @@ impl Runtime {
|
||||||
policies_db: home.node().join(node::POLICIES_DB_FILE),
|
policies_db: home.node().join(node::POLICIES_DB_FILE),
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let control = Self::bind(home.socket())?;
|
let control = Self::bind(socket)?;
|
||||||
|
|
||||||
Ok(Runtime {
|
Ok(Runtime {
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::net;
|
use std::net;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::{fmt, io, time};
|
use std::{fmt, io, time};
|
||||||
|
|
@ -71,6 +72,10 @@ impl<T> From<chan::SendError<T>> for Error {
|
||||||
|
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
pub(crate) home: Home,
|
pub(crate) home: Home,
|
||||||
|
|
||||||
|
/// Path to the control socket in use. Required for shutdown.
|
||||||
|
pub(crate) socket: PathBuf,
|
||||||
|
|
||||||
pub(crate) controller: reactor::Controller,
|
pub(crate) controller: reactor::Controller,
|
||||||
|
|
||||||
/// Whether a shutdown was initiated or not. Prevents attempting to shutdown twice.
|
/// Whether a shutdown was initiated or not. Prevents attempting to shutdown twice.
|
||||||
|
|
@ -96,6 +101,7 @@ impl Clone for Handle {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
home: self.home.clone(),
|
home: self.home.clone(),
|
||||||
|
socket: self.socket.clone(),
|
||||||
controller: self.controller.clone(),
|
controller: self.controller.clone(),
|
||||||
shutdown: self.shutdown.clone(),
|
shutdown: self.shutdown.clone(),
|
||||||
emitter: self.emitter.clone(),
|
emitter: self.emitter.clone(),
|
||||||
|
|
@ -104,9 +110,15 @@ impl Clone for Handle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handle {
|
impl Handle {
|
||||||
pub fn new(home: Home, controller: reactor::Controller, emitter: Emitter<Event>) -> Self {
|
pub fn new(
|
||||||
|
home: Home,
|
||||||
|
socket: PathBuf,
|
||||||
|
controller: reactor::Controller,
|
||||||
|
emitter: Emitter<Event>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
home,
|
home,
|
||||||
|
socket,
|
||||||
controller,
|
controller,
|
||||||
shutdown: Arc::default(),
|
shutdown: Arc::default(),
|
||||||
emitter,
|
emitter,
|
||||||
|
|
@ -352,7 +364,7 @@ impl radicle::node::Handle for Handle {
|
||||||
// Send a shutdown request to our own control socket. This is the only way to kill the
|
// Send a shutdown request to our own control socket. This is the only way to kill the
|
||||||
// control thread gracefully. Since the control thread may have called this function,
|
// control thread gracefully. Since the control thread may have called this function,
|
||||||
// the control socket may already be disconnected. Ignore errors.
|
// the control socket may already be disconnected. Ignore errors.
|
||||||
UnixStream::connect(self.home.socket())
|
UnixStream::connect(self.socket)
|
||||||
.and_then(|sock| Command::Shutdown.to_writer(sock))
|
.and_then(|sock| Command::Shutdown.to_writer(sock))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -478,6 +478,7 @@ impl<G: cyphernet::Ecdh<Pk = NodeId> + Signer<Signature> + Clone + Debug> Node<G
|
||||||
let rt = Runtime::init(
|
let rt = Runtime::init(
|
||||||
self.home.clone(),
|
self.home.clone(),
|
||||||
self.config,
|
self.config,
|
||||||
|
self.home.socket_default(),
|
||||||
listen,
|
listen,
|
||||||
signals,
|
signals,
|
||||||
self.signer.clone(),
|
self.signer.clone(),
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ pub(super) struct RealNodeSession {
|
||||||
impl RealNodeSession {
|
impl RealNodeSession {
|
||||||
pub(super) fn new(profile: &Profile) -> Self {
|
pub(super) fn new(profile: &Profile) -> Self {
|
||||||
Self {
|
Self {
|
||||||
node: radicle::Node::new(profile.socket()),
|
node: radicle::Node::new(profile.socket_from_env()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- To obtain the location of the control socket, do not use `Home::socket`
|
||||||
|
(which was removed), but instead choose `Home::socket_from_env` or
|
||||||
|
`Home::socket_default` depending on your use-case.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
||||||
|
|
@ -667,12 +667,25 @@ impl Home {
|
||||||
self.path.join("cobs")
|
self.path.join("cobs")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socket(&self) -> PathBuf {
|
/// The location of the control socket of the node.
|
||||||
const DEFAULT_SOCKET_NAME: &str = "control.sock";
|
/// If the environment variable with name [`env::RAD_SOCKET`] is set,
|
||||||
|
/// its value is used.
|
||||||
|
/// Otherwise, the default socket name, which is relative to this
|
||||||
|
/// [`Home`], is used (see [`Self::socket_default`]).
|
||||||
|
pub fn socket_from_env(&self) -> PathBuf {
|
||||||
env::var_os(env::RAD_SOCKET)
|
env::var_os(env::RAD_SOCKET)
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|| self.node().join(DEFAULT_SOCKET_NAME))
|
.unwrap_or_else(|| self.socket_default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default location of the control socket of the node.
|
||||||
|
/// The returned value only depends on `self`, and not on
|
||||||
|
/// any environment variables.
|
||||||
|
///
|
||||||
|
/// See also [`Self::socket_from_env`].
|
||||||
|
pub fn socket_default(&self) -> PathBuf {
|
||||||
|
const DEFAULT_SOCKET_NAME: &str = "control.sock";
|
||||||
|
self.node().join(DEFAULT_SOCKET_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a read-write handle to the notifications database.
|
/// Return a read-write handle to the notifications database.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue