diff --git a/.github/workflows/run_test_suite.yaml b/.github/workflows/run_test_suite.yaml index b92f6f42a..ebb1e430a 100644 --- a/.github/workflows/run_test_suite.yaml +++ b/.github/workflows/run_test_suite.yaml @@ -21,15 +21,12 @@ jobs: working-directory: ./rust run: cargo test shell: bash - - uses: taiki-e/install-action@v1 - with: - tool: cargo-binstall - name: 'Install Rust/WASM test dependencies' run: | rustup target install wasm32-unknown-unknown - cargo binstall --no-confirm toml-cli + cargo install toml-cli WASM_BINDGEN_VERSION=`toml get ./Cargo.lock . | jq '.package | map(select(.name == "wasm-bindgen"))[0].version' | xargs echo` - cargo binstall --no-confirm wasm-bindgen-cli --version "$WASM_BINDGEN_VERSION" + cargo install wasm-bindgen-cli --vers "$WASM_BINDGEN_VERSION" shell: bash # See: https://github.com/SeleniumHQ/selenium/blob/5d108f9a679634af0bbc387e7e3811bc1565912b/.github/actions/setup-chrome/action.yml - name: 'Setup Chrome and chromedriver' diff --git a/rust/noosphere-cli/src/native/workspace.rs b/rust/noosphere-cli/src/native/workspace.rs index b2003f977..b24e37d5f 100644 --- a/rust/noosphere-cli/src/native/workspace.rs +++ b/rust/noosphere-cli/src/native/workspace.rs @@ -13,11 +13,10 @@ use noosphere_storage::{ interface::{BlockStore, Store}, native::{NativeStorageInit, NativeStorageProvider, NativeStore}, }; -use path_absolutize::Absolutize; use pathdiff::diff_paths; use std::{ collections::{BTreeMap, BTreeSet}, - path::PathBuf, + path::{Path, PathBuf}, str::FromStr, }; use subtext::util::to_slug; @@ -549,6 +548,11 @@ The available keys are: Err(anyhow!("No keys found; have you created any yet?")) } + /// Returns true if the given path has a .sphere folder in it + fn has_sphere_directory(path: &Path) -> bool { + path.is_absolute() && path.join(SPHERE_DIRECTORY).is_dir() + } + /// Asserts that all related directories for the suggested working file /// tree root are present pub fn expect_local_directories(&self) -> Result<()> { @@ -559,7 +563,7 @@ The available keys are: )); } - if !self.sphere.is_dir() { + if !Workspace::has_sphere_directory(&self.root) { return Err(anyhow!( "The {:?} folder within {:?} is missing or corrupted", SPHERE_DIRECTORY, @@ -585,22 +589,12 @@ The available keys are: /// Creates all the directories needed to start rendering a sphere in the /// configured working file tree root pub async fn initialize_local_directories(&self) -> Result<()> { - let mut root = self.root.clone(); - - // Crawl up the directories to the root of the filesystem and make sure - // we aren't initializing a sphere within a sphere - while let Some(parent) = root.clone().parent() { - root = parent.to_path_buf(); - let working_paths = Workspace::new(&root, None)?; - if let Ok(_) = working_paths.expect_local_directories() { - return Err(anyhow!( - r#"Tried to initialize sphere directories in {:?} -...but a sphere is already initialized in {:?} -Unexpected things will happen if you try to nest spheres this way!"#, - self.root, - parent - ))?; - } + if let Ok(_) = self.expect_local_directories() { + return Err(anyhow!( + r#"Cannot initialize the sphere; a sphere is already initialized in {:?} +Unexpected (bad) things will happen if you try to nest spheres this way!"#, + self.root, + ))?; } fs::create_dir_all(&self.sphere).await?; @@ -617,12 +611,38 @@ Unexpected things will happen if you try to nest spheres this way!"#, Ok(()) } - pub fn new(root: &PathBuf, noosphere_global_root: Option<&PathBuf>) -> Result { - if !root.is_absolute() { - return Err(anyhow!("Ambiguous path to sphere root: {:?}", root)); + pub fn new( + current_working_directory: &PathBuf, + noosphere_global_root: Option<&PathBuf>, + ) -> Result { + if !current_working_directory.is_absolute() { + return Err(anyhow!( + "Ambiguous working directory: {:?} (must be an absolute path)", + current_working_directory + )); + } + + let mut root = current_working_directory.clone(); + + // Crawl up the directories to the root of the filesystem and use an + // existing `.sphere` directory to determine the root. If none are + // found, instead use the current working directory. + loop { + match root.parent() { + Some(parent) => { + root = parent.to_path_buf(); + + if Workspace::has_sphere_directory(&root) { + break; + } + } + None => { + root = current_working_directory.clone(); + break; + } + } } - let root = root.absolutize()?.to_path_buf(); let sphere = root.join(SPHERE_DIRECTORY); let blocks = sphere.join(BLOCKS_DIRECTORY); let authorization = sphere.join(AUTHORIZATION_FILE); @@ -668,3 +688,29 @@ Unexpected things will happen if you try to nest spheres this way!"#, ) } } + +#[cfg(test)] +mod tests { + use crate::native::commands::{key, sphere}; + use tokio::fs; + + use super::Workspace; + + #[tokio::test] + async fn it_chooses_an_ancestor_sphere_directory_as_root_if_one_exists() { + let workspace = Workspace::temporary().unwrap(); + + key::key_create("FOO", &workspace).await.unwrap(); + + sphere::sphere_create("FOO", &workspace).await.unwrap(); + + let subdirectory = workspace.root_path().join("foo/bar"); + + fs::create_dir_all(&subdirectory).await.unwrap(); + + let new_workspace = + Workspace::new(&subdirectory, Some(workspace.noosphere_path())).unwrap(); + + assert_eq!(workspace.root_path(), new_workspace.root_path()); + } +}