resq_cli/utils.rs
1/*
2 * Copyright 2026 ResQ
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Utility functions for the ResQ CLI.
18//
19// Provides common functions for path resolution, project detection,
20// and other shared functionality.
21
22use std::env;
23use std::path::PathBuf;
24
25/// Markers that indicate the root of the project
26const ROOT_MARKERS: &[&str] = &[
27 "resQ.sln",
28 "package.json",
29 "Cargo.toml",
30 "pyproject.toml",
31 ".git",
32];
33
34/// Finds the project root by climbing up the directory tree from the CWD.
35/// Returns the current directory if no root marker is found.
36pub fn find_project_root() -> PathBuf {
37 let cwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
38
39 for ancestor in cwd.ancestors() {
40 for marker in ROOT_MARKERS {
41 if ancestor.join(marker).exists() {
42 return ancestor.to_path_buf();
43 }
44 }
45 }
46
47 cwd
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use std::fs;
54 use tempfile::tempdir;
55
56 #[test]
57 fn test_find_project_root() -> anyhow::Result<()> {
58 let dir = tempdir()?;
59 let root = dir.path();
60
61 // Create a marker file
62 fs::write(root.join("resQ.sln"), "")?;
63
64 // Create a subdirectory
65 let sub = root.join("a/b/c");
66 fs::create_dir_all(&sub)?;
67
68 // Save current CWD to restore later
69 let original_cwd = env::current_dir()?;
70
71 // Change CWD to sub
72 env::set_current_dir(&sub)?;
73
74 let found_root = find_project_root();
75
76 // Restore CWD
77 env::set_current_dir(original_cwd)?;
78
79 assert_eq!(found_root.canonicalize()?, root.canonicalize()?);
80 Ok(())
81 }
82}