Merge branch 'master' of https://github.com/rustwasm/wasm-pack
commit
33c602cf82
@ -1,247 +1,257 @@ |
|||||||
//! Utilities for finding and installing binaries that we depend on.
|
//! Utilities for finding and installing binaries that we depend on.
|
||||||
|
|
||||||
use curl; |
use curl; |
||||||
use error::Error; |
use dirs; |
||||||
use failure; |
use failure::{Error, ResultExt}; |
||||||
use flate2; |
use flate2; |
||||||
use slog::Logger; |
use hex; |
||||||
|
use siphasher::sip::SipHasher13; |
||||||
use std::collections::HashSet; |
use std::collections::HashSet; |
||||||
|
use std::env; |
||||||
use std::ffi; |
use std::ffi; |
||||||
use std::fs; |
use std::fs; |
||||||
|
use std::hash::{Hash, Hasher}; |
||||||
use std::io; |
use std::io; |
||||||
use std::path::{Path, PathBuf}; |
use std::path::{Path, PathBuf}; |
||||||
use tar; |
use tar; |
||||||
use target; |
|
||||||
use which::which; |
|
||||||
use zip; |
use zip; |
||||||
|
|
||||||
/// Get the path for a crate's directory of locally-installed binaries.
|
/// Global cache for wasm-pack, currently containing binaries downloaded from
|
||||||
///
|
/// urls like wasm-bindgen and such.
|
||||||
/// This does not check whether or ensure that the directory exists.
|
pub struct Cache { |
||||||
pub fn local_bin_dir(crate_path: &Path) -> PathBuf { |
destination: PathBuf, |
||||||
crate_path.join("bin") |
|
||||||
} |
} |
||||||
|
|
||||||
/// Ensure that the crate's directory for locally-installed binaries exists.
|
/// Representation of a downloaded tarball/zip
|
||||||
pub fn ensure_local_bin_dir(crate_path: &Path) -> io::Result<()> { |
pub struct Download { |
||||||
fs::create_dir_all(local_bin_dir(crate_path)) |
root: PathBuf, |
||||||
} |
} |
||||||
|
|
||||||
/// Get the path for where `bin` would be if we have a crate-local install for
|
impl Cache { |
||||||
/// it.
|
/// Returns the global cache directory, as inferred from env vars and such.
|
||||||
///
|
///
|
||||||
/// This does *not* check whether there is a file at that path or not.
|
/// This function may return an error if a cache directory cannot be
|
||||||
///
|
/// determined.
|
||||||
/// This will automatically add the `.exe` extension for windows.
|
pub fn new() -> Result<Cache, Error> { |
||||||
pub fn local_bin_path(crate_path: &Path, bin: &str) -> PathBuf { |
let destination = dirs::cache_dir() |
||||||
let mut p = local_bin_dir(crate_path).join(bin); |
.map(|p| p.join("wasm-pack")) |
||||||
if target::WINDOWS { |
.or_else(|| { |
||||||
p.set_extension("exe"); |
let home = dirs::home_dir()?; |
||||||
|
Some(home.join(".wasm-pack")) |
||||||
|
}) |
||||||
|
.ok_or_else(|| format_err!("couldn't find your home directory, is $HOME not set?"))?; |
||||||
|
Ok(Cache::at(&destination)) |
||||||
} |
} |
||||||
p |
|
||||||
} |
|
||||||
|
|
||||||
/// Get the local (at `$CRATE/bin/$BIN`; preferred) or global (on `$PATH`) path
|
/// Creates a new cache specifically at a particular directory, useful in
|
||||||
/// for the given binary.
|
/// testing and such.
|
||||||
///
|
pub fn at(path: &Path) -> Cache { |
||||||
/// If this function returns `Some(path)`, then a file at that path exists (or
|
Cache { |
||||||
/// at least existed when we checked! In general, we aren't really worried about
|
destination: path.to_path_buf(), |
||||||
/// racing with an uninstall of a tool that we rely on.)
|
|
||||||
pub fn bin_path(log: &Logger, crate_path: &Path, bin: &str) -> Option<PathBuf> { |
|
||||||
assert!(!bin.ends_with(".exe")); |
|
||||||
debug!(log, "Searching for {} binary...", bin); |
|
||||||
|
|
||||||
// Return the path to the local binary, if it exists.
|
|
||||||
let local_path = |crate_path: &Path| -> Option<PathBuf> { |
|
||||||
let p = local_bin_path(crate_path, bin); |
|
||||||
debug!(log, "Checking for local {} binary at {}", bin, p.display()); |
|
||||||
if p.is_file() { |
|
||||||
Some(p) |
|
||||||
} else { |
|
||||||
None |
|
||||||
} |
} |
||||||
}; |
} |
||||||
|
|
||||||
// Return the path to the global binary, if it exists.
|
/// Joins a path to the destination of this cache, returning the result
|
||||||
let global_path = || -> Option<PathBuf> { |
pub fn join(&self, path: &Path) -> PathBuf { |
||||||
debug!(log, "Looking for global {} binary on $PATH", bin); |
self.destination.join(path) |
||||||
if let Ok(p) = which(bin) { |
} |
||||||
Some(p) |
|
||||||
} else { |
/// Downloads a tarball or zip file from the specified url, extracting it
|
||||||
None |
/// locally and returning the directory that the contents were extracted
|
||||||
|
/// into.
|
||||||
|
///
|
||||||
|
/// Note that this function requries that the contents of `url` never change
|
||||||
|
/// as the contents of the url are globally cached on the system and never
|
||||||
|
/// invalidated.
|
||||||
|
///
|
||||||
|
/// The `name` is a human-readable name used to go into the folder name of
|
||||||
|
/// the destination, and `binaries` is a list of binaries expected to be at
|
||||||
|
/// the url. If the URL's extraction doesn't contain all the binaries this
|
||||||
|
/// function will return an error.
|
||||||
|
pub fn download( |
||||||
|
&self, |
||||||
|
install_permitted: bool, |
||||||
|
name: &str, |
||||||
|
binaries: &[&str], |
||||||
|
url: &str, |
||||||
|
) -> Result<Option<Download>, Error> { |
||||||
|
let mut hasher = SipHasher13::new(); |
||||||
|
url.hash(&mut hasher); |
||||||
|
let result = hasher.finish(); |
||||||
|
let hex = hex::encode(&[ |
||||||
|
(result >> 0) as u8, |
||||||
|
(result >> 8) as u8, |
||||||
|
(result >> 16) as u8, |
||||||
|
(result >> 24) as u8, |
||||||
|
(result >> 32) as u8, |
||||||
|
(result >> 40) as u8, |
||||||
|
(result >> 48) as u8, |
||||||
|
(result >> 56) as u8, |
||||||
|
]); |
||||||
|
let dirname = format!("{}-{}", name, hex); |
||||||
|
|
||||||
|
let destination = self.destination.join(&dirname); |
||||||
|
if destination.exists() { |
||||||
|
return Ok(Some(Download { root: destination })); |
||||||
} |
} |
||||||
}; |
|
||||||
|
|
||||||
local_path(crate_path) |
|
||||||
.or_else(global_path) |
|
||||||
.map(|p| { |
|
||||||
let p = p.canonicalize().unwrap_or(p); |
|
||||||
debug!(log, "Using {} binary at {}", bin, p.display()); |
|
||||||
p |
|
||||||
}) |
|
||||||
.or_else(|| { |
|
||||||
debug!(log, "Could not find {} binary.", bin); |
|
||||||
None |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
fn with_url_context<T, E>(url: &str, r: Result<T, E>) -> Result<T, impl failure::Fail> |
if !install_permitted { |
||||||
where |
return Ok(None); |
||||||
Result<T, E>: failure::ResultExt<T, E>, |
} |
||||||
{ |
|
||||||
use failure::ResultExt; |
|
||||||
r.with_context(|_| format!("when requesting {}", url)) |
|
||||||
} |
|
||||||
|
|
||||||
fn transfer( |
let data = curl(&url).with_context(|_| format!("failed to download from {}", url))?; |
||||||
url: &str, |
|
||||||
easy: &mut curl::easy::Easy, |
|
||||||
data: &mut Vec<u8>, |
|
||||||
) -> Result<(), failure::Error> { |
|
||||||
let mut transfer = easy.transfer(); |
|
||||||
with_url_context( |
|
||||||
url, |
|
||||||
transfer.write_function(|part| { |
|
||||||
data.extend_from_slice(part); |
|
||||||
Ok(part.len()) |
|
||||||
}), |
|
||||||
)?; |
|
||||||
with_url_context(url, transfer.perform())?; |
|
||||||
Ok(()) |
|
||||||
} |
|
||||||
|
|
||||||
fn curl(url: &str) -> Result<Vec<u8>, failure::Error> { |
// Extract everything in a temporary directory in case we're ctrl-c'd.
|
||||||
let mut data = Vec::new(); |
// Don't want to leave around corrupted data!
|
||||||
|
let temp = self.destination.join(&format!(".{}", dirname)); |
||||||
|
drop(fs::remove_dir_all(&temp)); |
||||||
|
fs::create_dir_all(&temp)?; |
||||||
|
|
||||||
let mut easy = curl::easy::Easy::new(); |
if url.ends_with(".tar.gz") { |
||||||
with_url_context(url, easy.follow_location(true))?; |
self.extract_tarball(&data, &temp, binaries) |
||||||
with_url_context(url, easy.url(url))?; |
.with_context(|_| format!("failed to extract tarball from {}", url))?; |
||||||
transfer(url, &mut easy, &mut data)?; |
} else if url.ends_with(".zip") { |
||||||
|
self.extract_zip(&data, &temp, binaries) |
||||||
|
.with_context(|_| format!("failed to extract zip from {}", url))?; |
||||||
|
} else { |
||||||
|
// panic instead of runtime error as it's a static violation to
|
||||||
|
// download a different kind of url, all urls should be encoded into
|
||||||
|
// the binary anyway
|
||||||
|
panic!("don't know how to extract {}", url) |
||||||
|
} |
||||||
|
|
||||||
let status_code = with_url_context(url, easy.response_code())?; |
// Now that everything is ready move this over to our destination and
|
||||||
if 200 <= status_code && status_code < 300 { |
// we're good to go.
|
||||||
Ok(data) |
fs::rename(&temp, &destination)?; |
||||||
} else { |
Ok(Some(Download { root: destination })) |
||||||
Err(Error::http(&format!( |
|
||||||
"received a bad HTTP status code ({}) when requesting {}", |
|
||||||
status_code, url |
|
||||||
)) |
|
||||||
.into()) |
|
||||||
} |
} |
||||||
} |
|
||||||
|
|
||||||
/// Download the `.tar.gz` file at the given URL and unpack the given binaries
|
fn extract_tarball(&self, tarball: &[u8], dst: &Path, binaries: &[&str]) -> Result<(), Error> { |
||||||
/// from it into the given crate.
|
let mut binaries: HashSet<_> = binaries.into_iter().map(ffi::OsStr::new).collect(); |
||||||
///
|
let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(tarball)); |
||||||
/// Upon success, every `$BIN` in `binaries` will be at `$CRATE/bin/$BIN`.
|
|
||||||
pub fn install_binaries_from_targz_at_url<'a, I>( |
for entry in archive.entries()? { |
||||||
crate_path: &Path, |
let mut entry = entry?; |
||||||
url: &str, |
|
||||||
binaries: I, |
let dest = match entry.path()?.file_stem() { |
||||||
) -> Result<(), failure::Error> |
Some(f) if binaries.contains(f) => { |
||||||
where |
binaries.remove(f); |
||||||
I: IntoIterator<Item = &'a str>, |
dst.join(entry.path()?.file_name().unwrap()) |
||||||
{ |
} |
||||||
let mut binaries: HashSet<_> = binaries.into_iter().map(ffi::OsStr::new).collect(); |
_ => continue, |
||||||
|
}; |
||||||
let tarball = curl(&url).map_err(|e| Error::http(&e.to_string()))?; |
|
||||||
let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(&tarball[..])); |
entry.unpack(dest)?; |
||||||
|
} |
||||||
ensure_local_bin_dir(crate_path)?; |
|
||||||
let bin = local_bin_dir(crate_path); |
if !binaries.is_empty() { |
||||||
|
bail!( |
||||||
for entry in archive.entries()? { |
"the tarball was missing expected executables: {}", |
||||||
let mut entry = entry?; |
binaries |
||||||
|
.into_iter() |
||||||
let dest = match entry.path()?.file_stem() { |
.map(|s| s.to_string_lossy()) |
||||||
Some(f) if binaries.contains(f) => { |
.collect::<Vec<_>>() |
||||||
binaries.remove(f); |
.join(", "), |
||||||
bin.join(entry.path()?.file_name().unwrap()) |
) |
||||||
} |
} |
||||||
_ => continue, |
|
||||||
}; |
|
||||||
|
|
||||||
entry.unpack(dest)?; |
|
||||||
} |
|
||||||
|
|
||||||
if binaries.is_empty() { |
|
||||||
Ok(()) |
Ok(()) |
||||||
} else { |
} |
||||||
Err(Error::archive(&format!( |
|
||||||
"the tarball at {} was missing expected executables: {}", |
fn extract_zip(&self, zip: &[u8], dst: &Path, binaries: &[&str]) -> Result<(), Error> { |
||||||
url, |
let mut binaries: HashSet<_> = binaries.into_iter().map(ffi::OsStr::new).collect(); |
||||||
binaries |
|
||||||
.into_iter() |
let data = io::Cursor::new(zip); |
||||||
.map(|s| s.to_string_lossy()) |
let mut zip = zip::ZipArchive::new(data)?; |
||||||
.collect::<Vec<_>>() |
|
||||||
.join(", "), |
for i in 0..zip.len() { |
||||||
)) |
let mut entry = zip.by_index(i).unwrap(); |
||||||
.into()) |
let entry_path = entry.sanitized_name(); |
||||||
|
match entry_path.file_stem() { |
||||||
|
Some(f) if binaries.contains(f) => { |
||||||
|
binaries.remove(f); |
||||||
|
let mut dest = bin_open_options() |
||||||
|
.write(true) |
||||||
|
.create_new(true) |
||||||
|
.open(dst.join(entry_path.file_name().unwrap()))?; |
||||||
|
io::copy(&mut entry, &mut dest)?; |
||||||
|
} |
||||||
|
_ => continue, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
if !binaries.is_empty() { |
||||||
|
bail!( |
||||||
|
"the zip was missing expected executables: {}", |
||||||
|
binaries |
||||||
|
.into_iter() |
||||||
|
.map(|s| s.to_string_lossy()) |
||||||
|
.collect::<Vec<_>>() |
||||||
|
.join(", "), |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
return Ok(()); |
||||||
|
|
||||||
|
#[cfg(unix)] |
||||||
|
fn bin_open_options() -> fs::OpenOptions { |
||||||
|
use std::os::unix::fs::OpenOptionsExt; |
||||||
|
|
||||||
|
let mut opts = fs::OpenOptions::new(); |
||||||
|
opts.mode(0o755); |
||||||
|
opts |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(not(unix))] |
||||||
|
fn bin_open_options() -> fs::OpenOptions { |
||||||
|
fs::OpenOptions::new() |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
/// Install binaries from within the given zip at the given URL.
|
impl Download { |
||||||
///
|
/// Manually constructs a download at the specified path
|
||||||
/// Upon success, the binaries will be at the `$CRATE/bin/$BIN` path.
|
pub fn at(path: &Path) -> Download { |
||||||
pub fn install_binaries_from_zip_at_url<'a, I>( |
Download { |
||||||
crate_path: &Path, |
root: path.to_path_buf(), |
||||||
url: &str, |
} |
||||||
binaries: I, |
|
||||||
) -> Result<(), failure::Error> |
|
||||||
where |
|
||||||
I: IntoIterator<Item = &'a str>, |
|
||||||
{ |
|
||||||
let mut binaries: HashSet<_> = binaries.into_iter().map(ffi::OsStr::new).collect(); |
|
||||||
|
|
||||||
let data = curl(&url).map_err(|e| Error::http(&e.to_string()))?; |
|
||||||
let data = io::Cursor::new(data); |
|
||||||
let mut zip = zip::ZipArchive::new(data)?; |
|
||||||
|
|
||||||
ensure_local_bin_dir(crate_path)?; |
|
||||||
let bin = local_bin_dir(crate_path); |
|
||||||
|
|
||||||
for i in 0..zip.len() { |
|
||||||
let mut entry = zip.by_index(i).unwrap(); |
|
||||||
let entry_path = entry.sanitized_name(); |
|
||||||
match entry_path.file_stem() { |
|
||||||
Some(f) if binaries.contains(f) => { |
|
||||||
binaries.remove(f); |
|
||||||
let mut dest = bin_open_options() |
|
||||||
.write(true) |
|
||||||
.create_new(true) |
|
||||||
.open(bin.join(entry_path.file_name().unwrap()))?; |
|
||||||
io::copy(&mut entry, &mut dest)?; |
|
||||||
} |
|
||||||
_ => continue, |
|
||||||
}; |
|
||||||
} |
} |
||||||
|
|
||||||
if binaries.is_empty() { |
/// Returns the path to the binary `name` within this download
|
||||||
Ok(()) |
pub fn binary(&self, name: &str) -> PathBuf { |
||||||
} else { |
let ret = self |
||||||
Err(Error::archive(&format!( |
.root |
||||||
"the zip at {} was missing expected executables: {}", |
.join(name) |
||||||
url, |
.with_extension(env::consts::EXE_EXTENSION); |
||||||
binaries |
assert!(ret.exists(), "binary {} doesn't exist", ret.display()); |
||||||
.into_iter() |
return ret; |
||||||
.map(|s| s.to_string_lossy()) |
|
||||||
.collect::<Vec<_>>() |
|
||||||
.join(", "), |
|
||||||
)) |
|
||||||
.into()) |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
#[cfg(unix)] |
fn curl(url: &str) -> Result<Vec<u8>, Error> { |
||||||
fn bin_open_options() -> fs::OpenOptions { |
let mut data = Vec::new(); |
||||||
use std::os::unix::fs::OpenOptionsExt; |
|
||||||
|
|
||||||
let mut opts = fs::OpenOptions::new(); |
let mut easy = curl::easy::Easy::new(); |
||||||
opts.mode(0o755); |
easy.follow_location(true)?; |
||||||
opts |
easy.url(url)?; |
||||||
} |
easy.get(true)?; |
||||||
|
{ |
||||||
|
let mut transfer = easy.transfer(); |
||||||
|
transfer.write_function(|part| { |
||||||
|
data.extend_from_slice(part); |
||||||
|
Ok(part.len()) |
||||||
|
})?; |
||||||
|
transfer.perform()?; |
||||||
|
} |
||||||
|
|
||||||
#[cfg(not(unix))] |
let status_code = easy.response_code()?; |
||||||
fn bin_open_options() -> fs::OpenOptions { |
if 200 <= status_code && status_code < 300 { |
||||||
fs::OpenOptions::new() |
Ok(data) |
||||||
|
} else { |
||||||
|
bail!( |
||||||
|
"received a bad HTTP status code ({}) when requesting {}", |
||||||
|
status_code, |
||||||
|
url |
||||||
|
) |
||||||
|
} |
||||||
} |
} |
||||||
|
@ -1,234 +0,0 @@ |
|||||||
//! Code related to error handling for wasm-pack
|
|
||||||
use curl; |
|
||||||
use serde_json; |
|
||||||
use std::borrow::Cow; |
|
||||||
use std::io; |
|
||||||
use std::process::ExitStatus; |
|
||||||
use toml; |
|
||||||
use zip; |
|
||||||
|
|
||||||
/// Errors that can potentially occur in `wasm-pack`.
|
|
||||||
#[derive(Debug, Fail)] |
|
||||||
pub enum Error { |
|
||||||
/// Maps any underlying I/O errors that are thrown to this variant
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
Io(#[cause] io::Error), |
|
||||||
|
|
||||||
/// A JSON serialization or deserialization error.
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
SerdeJson(#[cause] serde_json::Error), |
|
||||||
|
|
||||||
/// A TOML serialization or deserialization error.
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
SerdeToml(#[cause] toml::de::Error), |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// A curl error.
|
|
||||||
Curl(#[cause] curl::Error), |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// An error handling zip archives.
|
|
||||||
Zip(#[cause] zip::result::ZipError), |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// An error in parsing your rustc version.
|
|
||||||
RustcMissing { |
|
||||||
/// Error message
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// An error from having an unsupported rustc version.
|
|
||||||
RustcVersion { |
|
||||||
/// Error message
|
|
||||||
message: String, |
|
||||||
/// The minor version of the local rust
|
|
||||||
local_minor_version: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// An error in parsing your wasm-pack version.
|
|
||||||
WasmPackMissing { |
|
||||||
/// Error message
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", _0)] |
|
||||||
/// An error from having an older wasm-pack version.
|
|
||||||
WasmPackVersion { |
|
||||||
/// Error message
|
|
||||||
message: String, |
|
||||||
/// Local version of wasm-pack
|
|
||||||
local_version: String, |
|
||||||
/// Latest version of wasm-pack
|
|
||||||
latest_version: String, |
|
||||||
}, |
|
||||||
|
|
||||||
/// An error invoking another CLI tool.
|
|
||||||
#[fail(display = "`{}` exited with {}", tool, exit_status)] |
|
||||||
Cli { |
|
||||||
/// Error message.
|
|
||||||
tool: String, |
|
||||||
/// The underlying CLI's `stdout` output.
|
|
||||||
stdout: String, |
|
||||||
/// The underlying CLI's `stderr` output.
|
|
||||||
stderr: String, |
|
||||||
/// The exit status of the subprocess
|
|
||||||
exit_status: ExitStatus, |
|
||||||
}, |
|
||||||
|
|
||||||
/// A crate configuration error.
|
|
||||||
#[fail(display = "{}", message)] |
|
||||||
CrateConfig { |
|
||||||
/// A message describing the configuration error.
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", message)] |
|
||||||
/// Error when the 'pkg' directory is not found.
|
|
||||||
PkgNotFound { |
|
||||||
/// Message describing the error.
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", message)] |
|
||||||
/// An error related to an archive that we downloaded.
|
|
||||||
Archive { |
|
||||||
/// Error message.
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", message)] |
|
||||||
/// Error when some operation or feature is unsupported for the current
|
|
||||||
/// target or environment.
|
|
||||||
Unsupported { |
|
||||||
/// Error message.
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
|
|
||||||
#[fail(display = "{}", message)] |
|
||||||
/// Error related to some HTTP request.
|
|
||||||
Http { |
|
||||||
/// Error message.
|
|
||||||
message: String, |
|
||||||
}, |
|
||||||
} |
|
||||||
|
|
||||||
impl Error { |
|
||||||
/// Construct a CLI error.
|
|
||||||
pub fn cli(tool: &str, stdout: Cow<str>, stderr: Cow<str>, exit_status: ExitStatus) -> Self { |
|
||||||
Error::Cli { |
|
||||||
tool: tool.to_string(), |
|
||||||
stdout: stdout.to_string(), |
|
||||||
stderr: stderr.to_string(), |
|
||||||
exit_status, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Construct a crate configuration error.
|
|
||||||
pub fn crate_config(message: &str) -> Self { |
|
||||||
Error::CrateConfig { |
|
||||||
message: message.to_string(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Construct an archive error.
|
|
||||||
pub fn archive(message: &str) -> Self { |
|
||||||
Error::Archive { |
|
||||||
message: message.to_string(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Construct an unsupported error.
|
|
||||||
pub fn unsupported(message: &str) -> Self { |
|
||||||
Error::Unsupported { |
|
||||||
message: message.to_string(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Construct an http error.
|
|
||||||
pub fn http(message: &str) -> Self { |
|
||||||
Error::Http { |
|
||||||
message: message.to_string(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Construct a rustc version error.
|
|
||||||
pub fn rustc_version_error(message: &str, local_version: &str) -> Self { |
|
||||||
Error::RustcVersion { |
|
||||||
message: message.to_string(), |
|
||||||
local_minor_version: local_version.to_string(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Get a string description of this error's type.
|
|
||||||
pub fn error_type(&self) -> String { |
|
||||||
match self { |
|
||||||
Error::Io(_) => "There was an I/O error. Details:\n\n", |
|
||||||
Error::SerdeJson(_) => "There was an JSON error. Details:\n\n", |
|
||||||
Error::SerdeToml(_) => "There was an TOML error. Details:\n\n", |
|
||||||
Error::Zip(_) => "There was an error handling zip files. Details:\n\n", |
|
||||||
Error::RustcMissing { |
|
||||||
message: _, |
|
||||||
} => "We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher.", |
|
||||||
Error::RustcVersion { |
|
||||||
message: _, |
|
||||||
local_minor_version: _, |
|
||||||
} => "Your rustc version is not supported. Please install version 1.30.0 or higher.", |
|
||||||
Error::WasmPackMissing { |
|
||||||
message: _, |
|
||||||
} => "We can't figure out what your wasm-pack version is, make sure the installation path is correct.", |
|
||||||
Error::WasmPackVersion { |
|
||||||
message: _, |
|
||||||
local_version: _, |
|
||||||
latest_version: _, |
|
||||||
} => "There's a newer version of wasm-pack available, the new version is: , you are using: ", |
|
||||||
Error::Cli { |
|
||||||
tool: _, |
|
||||||
stdout: _, |
|
||||||
stderr: _, |
|
||||||
exit_status: _, |
|
||||||
} => "There was an error while calling another CLI tool. Details:\n\n", |
|
||||||
Error::CrateConfig { message: _ } => { |
|
||||||
"There was a crate configuration error. Details:\n\n" |
|
||||||
} |
|
||||||
Error::PkgNotFound { |
|
||||||
message: _, |
|
||||||
} => "Unable to find the 'pkg' directory at the path, set the path as the parent of the 'pkg' directory \n\n", |
|
||||||
Error::Curl(_) => "There was an error making an HTTP request with curl. Details:\n\n", |
|
||||||
Error::Archive {..} => "There was an error related to an archive file. Details:\n\n", |
|
||||||
Error::Unsupported {..} => "There was an unsupported operation attempted. Details:\n\n", |
|
||||||
Error::Http {..} => "There wasn an HTTP error. Details:\n\n", |
|
||||||
}.to_string() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<io::Error> for Error { |
|
||||||
fn from(e: io::Error) -> Self { |
|
||||||
Error::Io(e) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<curl::Error> for Error { |
|
||||||
fn from(e: curl::Error) -> Self { |
|
||||||
Error::Curl(e) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<serde_json::Error> for Error { |
|
||||||
fn from(e: serde_json::Error) -> Self { |
|
||||||
Error::SerdeJson(e) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<zip::result::ZipError> for Error { |
|
||||||
fn from(e: zip::result::ZipError) -> Self { |
|
||||||
Error::Zip(e) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<toml::de::Error> for Error { |
|
||||||
fn from(e: toml::de::Error) -> Self { |
|
||||||
Error::SerdeToml(e) |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue