depot_js/
utils.rs

1use anyhow::{Context, Result};
2
3use std::{
4  fs,
5  path::{Path, PathBuf},
6  process::Command,
7};
8
9pub fn create_dir(path: impl AsRef<Path>) -> Result<()> {
10  let path = path.as_ref();
11  fs::create_dir(path).with_context(|| format!("Could not create directory: {}", path.display()))
12}
13
14pub fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
15  let path = path.as_ref();
16  fs::write(path, contents).with_context(|| format!("Could not write to file: {}", path.display()))
17}
18
19pub fn create_dir_if_missing(p: impl AsRef<Path>) -> Result<()> {
20  let p = p.as_ref();
21  if p.exists() {
22    return Ok(());
23  }
24  fs::create_dir_all(p).with_context(|| format!("Could not create directory: {}", p.display()))
25}
26
27pub fn get_git_root(cwd: &Path) -> Option<PathBuf> {
28  let mut cmd = Command::new("git");
29  cmd.args(["rev-parse", "--show-toplevel"]).current_dir(cwd);
30  let output = cmd.output().ok()?;
31  output
32    .status
33    .success()
34    .then(|| PathBuf::from(String::from_utf8(output.stdout).unwrap().trim()))
35}
36
37pub fn remove_dir_all_if_exists(dir: impl AsRef<Path>) -> Result<()> {
38  let dir = dir.as_ref();
39  if !dir.exists() {
40    return Ok(());
41  }
42  fs::remove_dir_all(dir).with_context(|| format!("Could not remove dir: {}", dir.display()))
43}
44
45#[macro_export]
46macro_rules! test_packages {
47  ($($manifest:tt),*) => {{
48    use $crate::workspace::package::{Package, PackageManifest, Target, Platform, PackageDepotConfig};
49    let index = std::cell::Cell::new(0);
50    [$({
51      let mut manifest: package_json_schema::PackageJson =
52        serde_json::from_value(serde_json::json!($manifest)).expect("Manifest failed to parse");
53      let other = manifest.other.as_mut().unwrap();
54      if !other.contains_key("depot") {
55        other.insert(String::from("depot"), serde_json::to_value(PackageDepotConfig {
56          platform: Platform::Browser,
57          ..Default::default()
58        }).unwrap());
59      }
60      let manifest = PackageManifest::from_json(manifest, std::path::Path::new("dummy.rs")).expect("Manifest failed to convert to Depot format");
61      let pkg = Package::from_parts("dummy.rs".into(), manifest, index.get(), Target::Lib).expect("Package failed to build");
62      index.set(index.get() + 1);
63      pkg
64    }),*]
65  }};
66}
67
68#[macro_export]
69macro_rules! shareable {
70  ($name:ident, $inner:ty) => {
71    #[derive(Clone)]
72    pub struct $name(std::sync::Arc<$inner>);
73
74    impl std::ops::Deref for $name {
75      type Target = $inner;
76
77      fn deref(&self) -> &Self::Target {
78        &self.0
79      }
80    }
81
82    impl std::hash::Hash for $name {
83      fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
84        std::ptr::hash(&*self.0, hasher)
85      }
86    }
87
88    impl PartialEq for $name {
89      fn eq(&self, other: &Self) -> bool {
90        std::ptr::eq(&*self.0, &*other.0)
91      }
92    }
93
94    impl Eq for $name {}
95
96    impl $name {
97      pub fn new(inner: $inner) -> Self {
98        $name(Arc::new(inner))
99      }
100    }
101  };
102}
103
104pub fn find_node() -> Option<PathBuf> {
105  pathsearch::find_executable_in_path("node")
106}
107
108pub fn find_pnpm(root: Option<&Path>) -> Option<PathBuf> {
109  let pnpm_in_root = root
110    .map(|root| root.join("bin").join("pnpm"))
111    .filter(|root| root.exists());
112  pnpm_in_root.or_else(|| pathsearch::find_executable_in_path("pnpm"))
113}