├── .gitignore ├── Cargo.toml ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .idea/ 4 | .vscode/ 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "project-root" 3 | description = "Simple utility to return the absolute path to your project root" 4 | version = "0.2.2" 5 | authors = ["Neil Chambers "] 6 | edition = "2018" 7 | license = "MIT OR Apache-2.0" 8 | keywords = ["util", "rootdir"] 9 | categories = ["config", "development-tools", "filesystem"] 10 | repository = "https://github.com/neilwashere/rust-project-root" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # project root 2 | 3 | A simple utility to obtain the absolute path to your project root. 4 | 5 | ## Usage 6 | 7 | ```rust 8 | match project_root::get_project_root() { 9 | Ok(p) => println!("Current project root is {:?}", p), 10 | Err(e) => println!("Error obtaining project root {:?}", e) 11 | }; 12 | ``` 13 | 14 | ## Motivation 15 | 16 | I was trying to slurp in some config files during a test but the directory location 17 | was not what I expected - and indeed would not be the final location of that directory 18 | on a deployment. 19 | 20 | I couldn't find an immediately obvious way of finding out my position relative to 21 | the project root so built this little helper. 22 | 23 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # project root 2 | //! 3 | //! Helper to find the absolute root directory path of a project as it stands relative 4 | //! to the location of the nearest Cargo.lock file. 5 | 6 | use std::ffi::OsString; 7 | use std::fs::read_dir; 8 | use std::path::PathBuf; 9 | use std::{env, io}; 10 | use std::io::ErrorKind; 11 | 12 | /// Get the project root (relative to closest Cargo.lock file) 13 | /// ```rust 14 | /// match project_root::get_project_root() { 15 | /// Ok(p) => println!("Current project root is {:?}", p), 16 | /// Err(e) => println!("Error obtaining project root {:?}", e) 17 | /// }; 18 | /// ``` 19 | pub fn get_project_root() -> io::Result { 20 | let path = env::current_dir()?; 21 | let mut path_ancestors = path.as_path().ancestors(); 22 | 23 | while let Some(p) = path_ancestors.next() { 24 | let has_cargo = 25 | read_dir(p)? 26 | .into_iter() 27 | .any(|p| p.unwrap().file_name() == OsString::from("Cargo.lock")); 28 | if has_cargo { 29 | return Ok(PathBuf::from(p)) 30 | } 31 | } 32 | Err(io::Error::new(ErrorKind::NotFound, "Ran out of places to find Cargo.toml")) 33 | 34 | } 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use crate::get_project_root; 39 | use std::fs::read_to_string; 40 | 41 | #[test] 42 | fn it_should_find_our_project_root() { 43 | let crate_name = "name = \"project-root\""; 44 | 45 | let project_root = get_project_root().expect("There is no project root"); 46 | 47 | let toml_path = project_root.to_str().unwrap().to_owned() + "/Cargo.toml"; 48 | let toml_string = read_to_string(toml_path).unwrap(); 49 | 50 | assert!(toml_string.contains(crate_name)); 51 | } 52 | } 53 | --------------------------------------------------------------------------------