1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use anyhow::{Context, Result};

use std::{
  fs,
  path::{Path, PathBuf},
  process::Command,
};

pub fn create_dir_if_missing(p: impl AsRef<Path>) -> Result<()> {
  let p = p.as_ref();
  if p.exists() {
    return Ok(());
  }
  fs::create_dir_all(p).with_context(|| format!("Could not create directory: {}", p.display()))
}

pub fn get_git_root(cwd: &Path) -> Option<PathBuf> {
  let mut cmd = Command::new("git");
  cmd.args(["rev-parse", "--show-toplevel"]).current_dir(cwd);
  let output = cmd.output().ok()?;
  output
    .status
    .success()
    .then(|| PathBuf::from(String::from_utf8(output.stdout).unwrap().trim()))
}

pub fn remove_dir_all_if_exists(dir: impl AsRef<Path>) -> Result<()> {
  let dir = dir.as_ref();
  if !dir.exists() {
    return Ok(());
  }
  fs::remove_dir_all(dir).with_context(|| format!("Could not remove dir: {}", dir.display()))
}

#[macro_export]
macro_rules! packages {
  ($($manifest:tt),*) => {{
    use $crate::workspace::package::{Package, PackageManifest, Target, Platform, PackageDepotConfig};
    let index = std::cell::Cell::new(0);
    [$({
      let mut manifest: package_json_schema::PackageJson =
        serde_json::from_value(serde_json::json!($manifest)).expect("Manifest failed to parse");
      let other = manifest.other.as_mut().unwrap();
      if !other.contains_key("depot") {
        other.insert(String::from("depot"), serde_json::to_value(PackageDepotConfig {
          platform: Platform::Browser
        }).unwrap());
      }
      let manifest = PackageManifest::from_json(manifest, std::path::Path::new("dummy.rs")).expect("Manifest failed to convert to Depot format");
      let pkg = Package::from_parts("dummy.rs".into(), manifest, index.get(), "dummy".into(), Target::Lib).expect("Package failed to build");
      index.set(index.get() + 1);
      pkg
    }),*]
  }};
}

#[macro_export]
macro_rules! shareable {
  ($name:ident, $inner:ty) => {
    #[derive(Clone)]
    pub struct $name(std::sync::Arc<$inner>);

    impl std::ops::Deref for $name {
      type Target = $inner;

      fn deref(&self) -> &Self::Target {
        &self.0
      }
    }

    impl std::hash::Hash for $name {
      fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        std::ptr::hash(&*self.0, hasher)
      }
    }

    impl PartialEq for $name {
      fn eq(&self, other: &Self) -> bool {
        std::ptr::eq(&*self.0, &*other.0)
      }
    }

    impl Eq for $name {}

    impl $name {
      pub fn new(inner: $inner) -> Self {
        $name(Arc::new(inner))
      }
    }
  };
}