equi_ty/
utils_misc.rs

1#![allow(unused)]
2
3use std::io::{IsTerminal as _, Write as _};
4use std::sync::LazyLock;
5use std::{env, fmt, fs, io, path};
6
7use color_eyre::eyre::{self, ContextCompat};
8use rustc_hir::def_id::DefId;
9use rustc_middle::ty::TyCtxt;
10use serde::Serialize;
11use tracing::{debug, instrument};
12use tracing_subscriber::EnvFilter;
13use walkdir::WalkDir;
14
15use crate::consts;
16
17static TRACING_INIT: LazyLock<()> = LazyLock::new(|| {
18    let no_color = env::var("NO_ANSI").ok().is_some_and(|val| val == "1");
19    let enable_ansi = !no_color || io::stdout().is_terminal();
20
21    tracing_subscriber::fmt()
22        .with_env_filter(EnvFilter::from_default_env())
23        .with_writer(io::stderr)
24        .with_ansi(enable_ansi)
25        .init();
26});
27
28pub fn init_tracing() {
29    let () = &*TRACING_INIT;
30}
31
32pub fn expect_one<T: fmt::Debug>(vs: Vec<T>) -> eyre::Result<T> {
33    eyre::ensure!(
34        vs.len() == 1,
35        "expected one item, found either none or multiple (vs: {vs:?})"
36    );
37
38    let fst = vs.into_iter().next().expect("already checked");
39    Ok(fst)
40}
41
42pub fn is_bin_on_path(bin: &str) -> eyre::Result<bool> {
43    if let Ok(paths) = env::var("PATH") {
44        for dir in paths.split(':') {
45            let full_path = path::Path::new(dir).join(bin);
46            if full_path.try_exists()? {
47                return Ok(true);
48            }
49        }
50    }
51    Ok(false)
52}
53
54#[instrument]
55pub(crate) fn copy_dir<P, Q>(from: P, to: Q) -> eyre::Result<()>
56where
57    P: AsRef<path::Path> + fmt::Debug,
58    Q: AsRef<path::Path> + fmt::Debug,
59{
60    let to = to.as_ref();
61    if to.exists() {
62        debug!("Removing existing {}", to.display());
63        fs::remove_dir_all(to)?;
64    }
65
66    for entry in WalkDir::new(&from) {
67        let entry = entry?;
68        let f = entry.path();
69        let t = to.join(f.strip_prefix(&from)?);
70
71        if entry.file_type().is_dir() {
72            // dirs
73            fs::create_dir(t)?;
74        } else if entry.file_type().is_file() {
75            // files
76            fs::copy(f, t)?;
77        } else {
78            // symlinks
79            let target = entry.path().read_link()?;
80            std::os::unix::fs::symlink(target, t)?;
81        }
82    }
83
84    Ok(())
85}
86
87pub fn should_save_intermediates() -> bool {
88    *consts::SAVE_INTERMEDIATES
89}
90
91pub fn save_intermediate<T: Serialize>(data: T, fname: &str) {
92    let intermediates_dir = env::current_dir()
93        .expect("failed to get current_dir")
94        .join(&*consts::INTERMEDIATES_DIR);
95    fs::create_dir_all(&intermediates_dir).expect("failed to create intermediates dir");
96
97    let fpath = intermediates_dir.join(fname);
98
99    save_to_json_file(&data, fpath).expect("failed to write to json file");
100}
101
102pub fn save_to_json_file<T>(value: &T, filename: impl AsRef<path::Path>) -> eyre::Result<()>
103where
104    T: ?Sized + Serialize,
105{
106    let file = fs::File::create(filename.as_ref())?;
107    // trace!(">> saving json to : {:?}", file);
108    let mut writer = io::BufWriter::new(file);
109    serde_json::to_writer_pretty(&mut writer, value)?;
110    writer.flush()?;
111    Ok(())
112}
113
114pub fn intermediates_dir() -> Option<impl AsRef<path::Path>> {
115    let intermediates_dir = env::current_dir()
116        .expect("failed to get current_dir")
117        .join(&*consts::INTERMEDIATES_DIR);
118
119    if intermediates_dir.is_dir() {
120        Some(intermediates_dir)
121    } else {
122        debug!(
123            "[!] intermediates_dir ({}) is not a dir",
124            intermediates_dir.display()
125        );
126        None
127    }
128}
129
130pub fn def_kind_descr(tcx: TyCtxt<'_>, def_id: DefId) -> &'static str {
131    let def_kind = tcx.def_kind(def_id);
132    tcx.def_kind_descr(def_kind, def_id)
133}
134
135pub fn remove_cratenum(path: &str) -> eyre::Result<String> {
136    if !path.contains('[') && !path.contains(']') {
137        return Ok(path.to_string());
138    }
139
140    let (crate_, rest) = path
141        .split_once('[')
142        .wrap_err_with(|| "'[' not found in path")?;
143
144    let (_, rest_path) = rest
145        .split_once(']')
146        .wrap_err_with(|| "']' not found in path")?;
147
148    let path = format!("{crate_}{rest_path}");
149    Ok(path)
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn test_remove_cratenum_prim_ty() {
158        let input = "u32";
159        let result = remove_cratenum(input).unwrap();
160        assert_eq!(result, "u32");
161    }
162
163    #[test]
164    fn test_remove_cratenum_valid_path() {
165        let input = "my_crate[123]::module::function";
166        let result = remove_cratenum(input).unwrap();
167        assert_eq!(result, "my_crate::module::function");
168    }
169
170    #[test]
171    fn test_remove_cratenum_with_zero() {
172        let input = "std[0]::collections::HashMap";
173        let result = remove_cratenum(input).unwrap();
174        assert_eq!(result, "std::collections::HashMap");
175    }
176
177    #[test]
178    fn test_remove_cratenum_missing_opening_bracket() {
179        let input = "my_crate123]::module::function";
180        let result = remove_cratenum(input);
181        assert!(result.is_err());
182        assert!(
183            result
184                .unwrap_err()
185                .to_string()
186                .contains("'[' not found in path")
187        );
188    }
189
190    #[test]
191    fn test_remove_cratenum_missing_closing_bracket() {
192        let input = "my_crate[123::module::function";
193        let result = remove_cratenum(input);
194        assert!(result.is_err());
195        assert!(
196            result
197                .unwrap_err()
198                .to_string()
199                .contains("']' not found in path")
200        );
201    }
202
203    #[test]
204    fn test_remove_cratenum_empty_brackets() {
205        let input = "my_crate[]::module::function";
206        let result = remove_cratenum(input).unwrap();
207        assert_eq!(result, "my_crate::module::function");
208    }
209}