Skip to main content

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}