-
Notifications
You must be signed in to change notification settings - Fork 235
/
install.rs
144 lines (118 loc) · 4.29 KB
/
install.rs
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::{fs::OpenOptions, io::Write, path::PathBuf, process::Command};
use anyhow::Result;
use flate2::read::GzDecoder;
/// Checks if a binary with the specified name is on the user's path.
pub fn is_installed(name: &str) -> Result<Option<PathBuf>> {
let path = std::env::var_os("PATH").expect("could not read PATH environment variable");
let path_directories = std::env::split_paths(&path).filter_map(|path| {
std::fs::metadata(&path)
.ok()
.map(|meta| meta.is_dir())
.unwrap_or(false)
.then_some(path)
});
for dir in path_directories {
for entry in dir.read_dir()? {
let entry = entry?;
let file_type = entry.file_type()?;
let is_file_or_symlink = file_type.is_symlink() || file_type.is_file();
if is_file_or_symlink
&& entry.file_name() == format!("{name}{BINARY_EXTENSION}").as_str()
{
return Ok(Some(entry.path()));
}
}
}
Ok(None)
}
pub fn ensure_wasm_pack() -> Result<()> {
if is_installed("wasm-pack")?.is_none() {
println!("Installing wasm-pack...");
let exit_status = Command::new("cargo")
.args(["install", "wasm-pack"])
.spawn()?
.wait()?;
match exit_status.success() {
true => Ok(()),
false => anyhow::bail!(
"installation of wasm-pack exited with status {}",
exit_status
),
}
} else {
Ok(())
}
}
const ESBUILD_VERSION: &str = "0.14.47";
const BINARY_EXTENSION: &str = if cfg!(windows) { ".exe" } else { "" };
pub fn ensure_esbuild() -> Result<PathBuf> {
// If we already have it we can skip the download.
if let Some(path) = is_installed("esbuild")? {
return Ok(path);
};
let esbuild_binary = format!("esbuild-{}{BINARY_EXTENSION}", platform());
let esbuild_bin_path = dirs_next::cache_dir()
.unwrap_or_else(std::env::temp_dir)
.join(esbuild_binary);
if esbuild_bin_path.exists() {
return Ok(esbuild_bin_path);
}
let mut options = &mut std::fs::OpenOptions::new();
options = fix_permissions(options);
let mut file = options.create(true).write(true).open(&esbuild_bin_path)?;
println!("Installing esbuild...");
if let Err(e) = download_esbuild(&mut file) {
// Make sure we close the file before we remove it.
drop(file);
std::fs::remove_file(&esbuild_bin_path)?;
return Err(e);
}
Ok(esbuild_bin_path)
}
fn download_esbuild(writer: &mut impl Write) -> Result<()> {
let esbuild_url = format!(
"https://registry.npmjs.org/esbuild-{0}/-/esbuild-{0}-{ESBUILD_VERSION}.tgz",
platform()
);
let body = ureq::get(&esbuild_url).call()?.into_reader();
let deflater = GzDecoder::new(body);
let mut archive = tar::Archive::new(deflater);
for entry in archive.entries()? {
let mut entry = entry?;
let path = entry.path()?;
if path
.file_name()
.map(|name| name == format!("esbuild{BINARY_EXTENSION}").as_str())
.unwrap_or(false)
{
std::io::copy(&mut entry, writer)?;
return Ok(());
}
}
anyhow::bail!("no esbuild binary in archive")
}
#[cfg(target_family = "unix")]
fn fix_permissions(options: &mut OpenOptions) -> &mut OpenOptions {
use std::os::unix::fs::OpenOptionsExt;
options.mode(0o770)
}
#[cfg(target_family = "windows")]
fn fix_permissions(options: &mut OpenOptions) -> &mut OpenOptions {
options
}
/// Converts the user's platform from their Rust representation to their esbuild representation.
/// https://esbuild.github.io/getting-started/#download-a-build
pub fn platform() -> &'static str {
match (std::env::consts::OS, std::env::consts::ARCH) {
("macos", "x86_64") => "darwin-64",
("macos", "aarch64") => "darwin-arm64",
("linux", "x86") => "linux-32",
("linux", "x86_64") => "linux-64",
("linux", "arm") => "linux-arm",
("linux", "aarch64") => "linux-arm64",
("windows", "x86") => "windows-32",
("windows", "x86_64") => "windows-64",
("windows", "aarch64") => "windows-arm64",
_ => panic!("Platform unsupported by esbuild."),
}
}