radicle: canonicalize home path
If a path was passed to `Home` in non-canonical form it would not use the right path for any initialisation or use. The aim is to use the `canonicalize` function for paths. However, this may return an error if none of the paths exist. To ensure that the path exists the `new` constructor for `Home` creates the directory and canonicalizes the path. Since `new` now initialises the home directory, it would be useful if it also initialised all the necessary subdirectories -- which removes the need for the `init` method. Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com> X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
parent
a7d2fa95cd
commit
8e26e4c046
|
|
@ -71,9 +71,7 @@ impl Environment {
|
||||||
/// Create a new profile in this environment.
|
/// Create a new profile in this environment.
|
||||||
/// This should be used when a running node is not required.
|
/// This should be used when a running node is not required.
|
||||||
pub fn profile(&mut self, name: &str) -> Profile {
|
pub fn profile(&mut self, name: &str) -> Profile {
|
||||||
let home = Home::new(self.tmp().join("home").join(name))
|
let home = Home::new(self.tmp().join("home").join(name)).unwrap();
|
||||||
.init()
|
|
||||||
.unwrap();
|
|
||||||
let storage = Storage::open(home.storage()).unwrap();
|
let storage = Storage::open(home.storage()).unwrap();
|
||||||
let keystore = Keystore::new(&home.keys());
|
let keystore = Keystore::new(&home.keys());
|
||||||
let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32]));
|
let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32]));
|
||||||
|
|
@ -232,7 +230,7 @@ impl Node<MockSigner> {
|
||||||
.take(8)
|
.take(8)
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
);
|
);
|
||||||
let home = Home::new(home).init().unwrap();
|
let home = Home::new(home).unwrap();
|
||||||
let signer = MockSigner::default();
|
let signer = MockSigner::default();
|
||||||
let storage = Storage::open(home.storage()).unwrap();
|
let storage = Storage::open(home.storage()).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,6 @@ pub struct Profile {
|
||||||
|
|
||||||
impl Profile {
|
impl Profile {
|
||||||
pub fn init(home: Home, passphrase: impl Into<Passphrase>) -> Result<Self, Error> {
|
pub fn init(home: Home, passphrase: impl Into<Passphrase>) -> Result<Self, Error> {
|
||||||
let home = home.init()?;
|
|
||||||
let storage = Storage::open(home.storage())?;
|
let storage = Storage::open(home.storage())?;
|
||||||
let keystore = Keystore::new(&home.keys());
|
let keystore = Keystore::new(&home.keys());
|
||||||
let public_key = keystore.init("radicle", passphrase)?;
|
let public_key = keystore.init("radicle", passphrase)?;
|
||||||
|
|
@ -142,9 +141,9 @@ impl Profile {
|
||||||
/// Get the path to the radicle home folder.
|
/// Get the path to the radicle home folder.
|
||||||
pub fn home() -> Result<Home, io::Error> {
|
pub fn home() -> Result<Home, io::Error> {
|
||||||
if let Some(home) = env::var_os(env::RAD_HOME) {
|
if let Some(home) = env::var_os(env::RAD_HOME) {
|
||||||
Ok(Home::new(PathBuf::from(home)))
|
Ok(Home::new(PathBuf::from(home))?)
|
||||||
} else if let Some(home) = env::var_os("HOME") {
|
} else if let Some(home) = env::var_os("HOME") {
|
||||||
Ok(Home::new(PathBuf::from(home).join(".radicle")))
|
Ok(Home::new(PathBuf::from(home).join(".radicle"))?)
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(
|
||||||
io::ErrorKind::NotFound,
|
io::ErrorKind::NotFound,
|
||||||
|
|
@ -166,14 +165,33 @@ impl From<PathBuf> for Home {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Home {
|
impl Home {
|
||||||
pub fn init(self) -> Result<Self, io::Error> {
|
/// Creates the Radicle Home directories.
|
||||||
fs::create_dir_all(self.node()).ok();
|
///
|
||||||
|
/// The `home` path is used as the base directory for all
|
||||||
|
/// necessary subdirectories.
|
||||||
|
///
|
||||||
|
/// If `home` does not already exist then it and any
|
||||||
|
/// subdirectories are created using [`fs::create_dir_all`].
|
||||||
|
///
|
||||||
|
/// The `home` path is also canonicalized using [`fs::canonicalize`].
|
||||||
|
///
|
||||||
|
/// All necessary subdirectories are also created.
|
||||||
|
pub fn new(home: impl Into<PathBuf>) -> Result<Self, io::Error> {
|
||||||
|
let path = home.into();
|
||||||
|
if !path.exists() {
|
||||||
|
fs::create_dir_all(path.clone())?;
|
||||||
|
}
|
||||||
|
let home = Self {
|
||||||
|
path: path.canonicalize()?,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(self)
|
for dir in &[home.storage(), home.keys(), home.node()] {
|
||||||
}
|
if !dir.exists() {
|
||||||
|
fs::create_dir_all(dir)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(home: impl Into<PathBuf>) -> Self {
|
Ok(home)
|
||||||
Self { path: home.into() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
|
|
@ -198,3 +216,33 @@ impl Home {
|
||||||
.unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
|
.unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use super::Home;
|
||||||
|
|
||||||
|
// Checks that if we have:
|
||||||
|
// '/run/user/1000/.tmpqfK6ih/../.tmpqfK6ih/Radicle/Home'
|
||||||
|
//
|
||||||
|
// that it gets normalized to:
|
||||||
|
// '/run/user/1000/.tmpqfK6ih/Radicle/Home'
|
||||||
|
#[test]
|
||||||
|
fn canonicalize_home() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let path = tmp.path().join("Home").join("Radicle");
|
||||||
|
fs::create_dir_all(path.clone()).unwrap();
|
||||||
|
|
||||||
|
let last = tmp.path().components().last().unwrap();
|
||||||
|
let home = Home::new(
|
||||||
|
tmp.path()
|
||||||
|
.join("..")
|
||||||
|
.join(last)
|
||||||
|
.join("Home")
|
||||||
|
.join("Radicle"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(home.path, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ pub mod setup {
|
||||||
let mut rng = fastrand::Rng::new();
|
let mut rng = fastrand::Rng::new();
|
||||||
let signer = MockSigner::new(&mut rng);
|
let signer = MockSigner::new(&mut rng);
|
||||||
let home = tmp.path().join("home");
|
let home = tmp.path().join("home");
|
||||||
let paths = Home::new(home.as_path());
|
let paths = Home::new(home.as_path()).unwrap();
|
||||||
let storage = Storage::open(paths.storage()).unwrap();
|
let storage = Storage::open(paths.storage()).unwrap();
|
||||||
let (id, _, _, _) = fixtures::project(tmp.path().join("copy"), &storage, &signer).unwrap();
|
let (id, _, _, _) = fixtures::project(tmp.path().join("copy"), &storage, &signer).unwrap();
|
||||||
let project = storage.repository(id).unwrap();
|
let project = storage.repository(id).unwrap();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue