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}