bookdata/layout/
workdir.rs

1use std::path::Path;
2use std::{env::current_dir, path::PathBuf};
3
4use anyhow::{anyhow, Result};
5use log::*;
6use relative_path::{RelativePath, RelativePathBuf};
7
8fn is_bookdata_root(path: &Path) -> Result<bool> {
9    let dvc = path.join(".dvc");
10    let config = path.join("config.yaml");
11    if dvc.try_exists()? {
12        debug!("found DVC path at {}", dvc.display());
13        if config.try_exists()? {
14            debug!("found config.yaml at {}", config.display());
15            Ok(true)
16        } else {
17            warn!("found .dvc but not config.yaml, weird directory?");
18            Ok(false)
19        }
20    } else {
21        Ok(false)
22    }
23}
24
25/// Find a relative path from the current directory to the repository.
26pub fn find_root_relpath() -> Result<RelativePathBuf> {
27    let mut rp = RelativePathBuf::new();
28    let cwd = current_dir()?;
29    debug!("looking for root from working directory {}", cwd.display());
30    loop {
31        let path = rp.to_logical_path(&cwd);
32        debug!("looking for DVC in {}", path.display());
33        if is_bookdata_root(&path)? {
34            info!("found bookdata root at {}", path.display());
35            return Ok(rp);
36        }
37
38        if path.parent().is_some() {
39            rp.push("..");
40        } else {
41            error!("scanned parents and could not find bookdata root");
42            return Err(anyhow!("bookdata not found"));
43        }
44    }
45}
46
47/// Get the absolute path to the repository root.
48#[allow(dead_code)]
49pub fn find_root_abspath() -> Result<PathBuf> {
50    Ok(find_root_relpath()?.to_path(current_dir()?))
51}
52
53/// Given a path relative to the GoodReads repository root,
54/// obtain a path to open the file.
55pub fn resolve_path<P: AsRef<RelativePath>>(path: P) -> Result<PathBuf> {
56    let root = find_root_relpath()?;
57    let rrp = root.join_normalized(path.as_ref());
58    let resolved = rrp.to_logical_path(current_dir()?);
59    debug!("resolved {} to {}", path.as_ref(), resolved.display());
60    debug!("root: {}", root);
61    debug!("rrp: {}", rrp);
62    Ok(resolved)
63}
64
65/// Require that we are in the root directory.
66pub fn require_working_root() -> Result<()> {
67    let cwd = current_dir()?;
68    if is_bookdata_root(&cwd)? {
69        Ok(())
70    } else {
71        error!("working directory is not bookdata root");
72        Err(anyhow!("incorrect working directory"))
73    }
74}
75
76/// Expect that we are in a particular subdirectory.
77pub fn require_working_dir<P: AsRef<Path>>(path: P) -> Result<()> {
78    let path = path.as_ref();
79    let cwd = current_dir()?;
80
81    if !cwd.ends_with(path) {
82        error!("expected to be run in {:?}", path);
83        Err(anyhow!("incorrect working directory"))
84    } else {
85        Ok(())
86    }
87}