Skip to content
This repository has been archived by the owner on Sep 21, 2024. It is now read-only.

feat(cli): Find the nearest ancestor sphere #119

Merged
merged 3 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .github/workflows/run_test_suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
92 changes: 69 additions & 23 deletions rust/noosphere-cli/src/native/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<()> {
Expand All @@ -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,
Expand All @@ -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?;
Expand All @@ -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<Self> {
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<Self> {
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);
Expand Down Expand Up @@ -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());
}
}