2022-01-07 22:09:52 -05:00
|
|
|
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
2021-11-29 17:23:30 -05:00
|
|
|
|
|
2022-06-27 16:54:09 -04:00
|
|
|
|
use crate::args::ConfigFlag;
|
|
|
|
|
use crate::args::Flags;
|
|
|
|
|
use crate::args::InstallFlags;
|
|
|
|
|
use crate::args::TypeCheckMode;
|
2022-11-14 22:40:05 -05:00
|
|
|
|
use crate::fs_util;
|
|
|
|
|
use crate::npm::NpmPackageReference;
|
|
|
|
|
use deno_core::anyhow::Context;
|
2020-09-14 12:48:57 -04:00
|
|
|
|
use deno_core::error::generic_error;
|
|
|
|
|
use deno_core::error::AnyError;
|
2021-05-19 07:40:23 -04:00
|
|
|
|
use deno_core::resolve_url_or_path;
|
2020-09-16 14:28:07 -04:00
|
|
|
|
use deno_core::url::Url;
|
2020-04-11 11:47:27 -04:00
|
|
|
|
use log::Level;
|
2021-12-18 16:14:42 -05:00
|
|
|
|
use once_cell::sync::Lazy;
|
2021-03-26 12:34:25 -04:00
|
|
|
|
use regex::Regex;
|
|
|
|
|
use regex::RegexBuilder;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
use std::env;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::fs::File;
|
2020-09-14 12:48:57 -04:00
|
|
|
|
use std::io;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
use std::io::Write;
|
2021-03-25 14:17:37 -04:00
|
|
|
|
use std::path::Path;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
2021-03-26 12:34:25 -04:00
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
|
|
2021-12-18 16:14:42 -05:00
|
|
|
|
static EXEC_NAME_RE: Lazy<Regex> = Lazy::new(|| {
|
|
|
|
|
RegexBuilder::new(r"^[a-z][\w-]*$")
|
|
|
|
|
.case_insensitive(true)
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap()
|
|
|
|
|
});
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2020-09-14 12:48:57 -04:00
|
|
|
|
fn validate_name(exec_name: &str) -> Result<(), AnyError> {
|
2020-01-30 18:42:39 -05:00
|
|
|
|
if EXEC_NAME_RE.is_match(exec_name) {
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
2020-09-14 12:48:57 -04:00
|
|
|
|
Err(generic_error(format!(
|
|
|
|
|
"Invalid executable name: {}",
|
|
|
|
|
exec_name
|
|
|
|
|
)))
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
2021-01-04 11:52:43 -05:00
|
|
|
|
/// On Windows, 2 files are generated.
|
|
|
|
|
/// One compatible with cmd & powershell with a .cmd extension
|
|
|
|
|
/// A second compatible with git bash / MINGW64
|
2020-02-07 03:31:19 -05:00
|
|
|
|
/// Generate batch script to satisfy that.
|
2022-01-14 13:23:47 -05:00
|
|
|
|
fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> {
|
|
|
|
|
let args: Vec<String> = shim_data
|
|
|
|
|
.args
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|c| format!("\"{}\"", c))
|
|
|
|
|
.collect();
|
2020-01-30 18:42:39 -05:00
|
|
|
|
let template = format!(
|
2021-04-18 13:38:40 -04:00
|
|
|
|
"% generated by deno install %\n@deno {} %*\n",
|
2021-01-18 22:34:37 -05:00
|
|
|
|
args
|
|
|
|
|
.iter()
|
2022-02-24 20:03:12 -05:00
|
|
|
|
.map(|arg| arg.replace('%', "%%"))
|
2021-01-18 22:34:37 -05:00
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.join(" ")
|
2020-01-30 18:42:39 -05:00
|
|
|
|
);
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let mut file = File::create(&shim_data.file_path)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
file.write_all(template.as_bytes())?;
|
2021-01-04 11:52:43 -05:00
|
|
|
|
|
|
|
|
|
// write file for bash
|
|
|
|
|
// create filepath without extensions
|
|
|
|
|
let template = format!(
|
|
|
|
|
r#"#!/bin/sh
|
|
|
|
|
# generated by deno install
|
|
|
|
|
deno {} "$@"
|
|
|
|
|
"#,
|
|
|
|
|
args.join(" "),
|
|
|
|
|
);
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let mut file = File::create(&shim_data.file_path.with_extension(""))?;
|
2021-01-04 11:52:43 -05:00
|
|
|
|
file.write_all(template.as_bytes())?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> {
|
2020-11-09 14:08:12 -05:00
|
|
|
|
use shell_escape::escape;
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let args: Vec<String> = shim_data
|
|
|
|
|
.args
|
|
|
|
|
.iter()
|
2020-11-09 14:08:12 -05:00
|
|
|
|
.map(|c| escape(c.into()).into_owned())
|
|
|
|
|
.collect();
|
2020-01-30 18:42:39 -05:00
|
|
|
|
let template = format!(
|
|
|
|
|
r#"#!/bin/sh
|
2020-02-07 03:31:19 -05:00
|
|
|
|
# generated by deno install
|
2020-11-09 14:08:12 -05:00
|
|
|
|
exec deno {} "$@"
|
2020-01-30 18:42:39 -05:00
|
|
|
|
"#,
|
2020-02-07 03:31:19 -05:00
|
|
|
|
args.join(" "),
|
2020-01-30 18:42:39 -05:00
|
|
|
|
);
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let mut file = File::create(&shim_data.file_path)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
file.write_all(template.as_bytes())?;
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let _metadata = fs::metadata(&shim_data.file_path)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
let mut permissions = _metadata.permissions();
|
|
|
|
|
permissions.set_mode(0o755);
|
2022-01-14 13:23:47 -05:00
|
|
|
|
fs::set_permissions(&shim_data.file_path, permissions)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 12:48:57 -04:00
|
|
|
|
fn get_installer_root() -> Result<PathBuf, io::Error> {
|
2020-05-09 13:14:56 -04:00
|
|
|
|
if let Ok(env_dir) = env::var("DENO_INSTALL_ROOT") {
|
|
|
|
|
if !env_dir.is_empty() {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
return fs_util::canonicalize_path_maybe_not_exists(&PathBuf::from(
|
|
|
|
|
env_dir,
|
|
|
|
|
));
|
2020-05-09 13:14:56 -04:00
|
|
|
|
}
|
2020-04-16 18:15:42 -04:00
|
|
|
|
}
|
2020-06-05 16:03:47 -04:00
|
|
|
|
// Note: on Windows, the $HOME environment variable may be set by users or by
|
|
|
|
|
// third party software, but it is non-standard and should not be relied upon.
|
|
|
|
|
let home_env_var = if cfg!(windows) { "USERPROFILE" } else { "HOME" };
|
|
|
|
|
let mut home_path =
|
|
|
|
|
env::var_os(home_env_var)
|
|
|
|
|
.map(PathBuf::from)
|
|
|
|
|
.ok_or_else(|| {
|
2020-09-14 12:48:57 -04:00
|
|
|
|
io::Error::new(
|
|
|
|
|
io::ErrorKind::NotFound,
|
2020-06-05 16:03:47 -04:00
|
|
|
|
format!("${} is not defined", home_env_var),
|
|
|
|
|
)
|
|
|
|
|
})?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
home_path.push(".deno");
|
|
|
|
|
Ok(home_path)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-30 14:35:12 -05:00
|
|
|
|
pub fn infer_name_from_url(url: &Url) -> Option<String> {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
if let Ok(npm_ref) = NpmPackageReference::from_specifier(url) {
|
|
|
|
|
if let Some(sub_path) = npm_ref.sub_path {
|
|
|
|
|
if !sub_path.contains('/') {
|
|
|
|
|
return Some(sub_path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !npm_ref.req.name.contains('/') {
|
|
|
|
|
return Some(npm_ref.req.name);
|
|
|
|
|
}
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-01 15:33:11 -04:00
|
|
|
|
let path = PathBuf::from(url.path());
|
2020-08-27 16:55:58 -04:00
|
|
|
|
let mut stem = match path.file_stem() {
|
2020-05-01 15:33:11 -04:00
|
|
|
|
Some(stem) => stem.to_string_lossy().to_string(),
|
|
|
|
|
None => return None,
|
|
|
|
|
};
|
2020-08-27 16:55:58 -04:00
|
|
|
|
if stem == "main" || stem == "mod" || stem == "index" || stem == "cli" {
|
|
|
|
|
if let Some(parent_name) = path.parent().and_then(|p| p.file_name()) {
|
|
|
|
|
stem = parent_name.to_string_lossy().to_string();
|
2020-05-01 15:33:11 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-11 22:32:52 -04:00
|
|
|
|
|
|
|
|
|
// if atmark symbol appears in the index other than 0 (e.g. `foo@bar`) we use
|
|
|
|
|
// the former part as the inferred name because the latter part is most likely
|
|
|
|
|
// a version number.
|
|
|
|
|
match stem.find('@') {
|
|
|
|
|
Some(at_index) if at_index > 0 => {
|
|
|
|
|
stem = stem.split_at(at_index).0.to_string();
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-01 15:33:11 -04:00
|
|
|
|
Some(stem)
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-30 11:38:07 -04:00
|
|
|
|
pub fn uninstall(name: String, root: Option<PathBuf>) -> Result<(), AnyError> {
|
|
|
|
|
let root = if let Some(root) = root {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
fs_util::canonicalize_path_maybe_not_exists(&root)?
|
2021-09-30 11:38:07 -04:00
|
|
|
|
} else {
|
|
|
|
|
get_installer_root()?
|
|
|
|
|
};
|
|
|
|
|
let installation_dir = root.join("bin");
|
|
|
|
|
|
|
|
|
|
// ensure directory exists
|
|
|
|
|
if let Ok(metadata) = fs::metadata(&installation_dir) {
|
|
|
|
|
if !metadata.is_dir() {
|
|
|
|
|
return Err(generic_error("Installation path is not a directory"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 22:40:05 -05:00
|
|
|
|
let file_path = installation_dir.join(&name);
|
2021-09-30 11:38:07 -04:00
|
|
|
|
|
|
|
|
|
let mut removed = false;
|
|
|
|
|
|
|
|
|
|
if file_path.exists() {
|
|
|
|
|
fs::remove_file(&file_path)?;
|
|
|
|
|
println!("deleted {}", file_path.to_string_lossy());
|
|
|
|
|
removed = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if cfg!(windows) {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
let file_path = file_path.with_extension("cmd");
|
2021-09-30 11:38:07 -04:00
|
|
|
|
if file_path.exists() {
|
|
|
|
|
fs::remove_file(&file_path)?;
|
|
|
|
|
println!("deleted {}", file_path.to_string_lossy());
|
|
|
|
|
removed = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !removed {
|
|
|
|
|
return Err(generic_error(format!("No installation found for {}", name)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There might be some extra files to delete
|
|
|
|
|
for ext in ["tsconfig.json", "lock.json"] {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
let file_path = file_path.with_extension(ext);
|
2021-09-30 11:38:07 -04:00
|
|
|
|
if file_path.exists() {
|
|
|
|
|
fs::remove_file(&file_path)?;
|
|
|
|
|
println!("deleted {}", file_path.to_string_lossy());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println!("✅ Successfully uninstalled {}", name);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
pub fn install(
|
2020-02-26 05:52:15 -05:00
|
|
|
|
flags: Flags,
|
2021-12-21 09:49:27 -05:00
|
|
|
|
install_flags: InstallFlags,
|
2020-09-14 12:48:57 -04:00
|
|
|
|
) -> Result<(), AnyError> {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(&flags, &install_flags)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
|
|
|
|
// ensure directory exists
|
2022-01-14 13:23:47 -05:00
|
|
|
|
if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) {
|
2020-01-30 18:42:39 -05:00
|
|
|
|
if !metadata.is_dir() {
|
2020-09-14 12:48:57 -04:00
|
|
|
|
return Err(generic_error("Installation path is not a directory"));
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
fs::create_dir_all(&shim_data.installation_dir)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
};
|
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
if shim_data.file_path.exists() && !install_flags.force {
|
|
|
|
|
return Err(generic_error(
|
|
|
|
|
"Existing installation found. Aborting (Use -f to overwrite).",
|
|
|
|
|
));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
generate_executable_file(&shim_data)?;
|
|
|
|
|
for (path, contents) in shim_data.extra_files {
|
|
|
|
|
fs::write(path, contents)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println!("✅ Successfully installed {}", shim_data.name);
|
|
|
|
|
println!("{}", shim_data.file_path.display());
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
let display_path = shim_data.file_path.with_extension("");
|
|
|
|
|
println!("{} (shell)", display_path.display());
|
|
|
|
|
}
|
|
|
|
|
let installation_dir_str = shim_data.installation_dir.to_string_lossy();
|
|
|
|
|
|
|
|
|
|
if !is_in_path(&shim_data.installation_dir) {
|
|
|
|
|
println!("ℹ️ Add {} to PATH", installation_dir_str);
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
println!(" set PATH=%PATH%;{}", installation_dir_str);
|
|
|
|
|
} else {
|
|
|
|
|
println!(" export PATH=\"{}:$PATH\"", installation_dir_str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ShimData {
|
|
|
|
|
name: String,
|
|
|
|
|
installation_dir: PathBuf,
|
|
|
|
|
file_path: PathBuf,
|
|
|
|
|
args: Vec<String>,
|
|
|
|
|
extra_files: Vec<(PathBuf, String)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn resolve_shim_data(
|
|
|
|
|
flags: &Flags,
|
|
|
|
|
install_flags: &InstallFlags,
|
|
|
|
|
) -> Result<ShimData, AnyError> {
|
|
|
|
|
let root = if let Some(root) = &install_flags.root {
|
2022-11-14 22:40:05 -05:00
|
|
|
|
fs_util::canonicalize_path_maybe_not_exists(root)?
|
2022-01-14 13:23:47 -05:00
|
|
|
|
} else {
|
|
|
|
|
get_installer_root()?
|
|
|
|
|
};
|
|
|
|
|
let installation_dir = root.join("bin");
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
// Check if module_url is remote
|
2021-12-21 09:49:27 -05:00
|
|
|
|
let module_url = resolve_url_or_path(&install_flags.module_url)?;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2021-12-21 09:49:27 -05:00
|
|
|
|
let name = install_flags
|
|
|
|
|
.name
|
2022-01-14 13:23:47 -05:00
|
|
|
|
.clone()
|
2021-12-21 09:49:27 -05:00
|
|
|
|
.or_else(|| infer_name_from_url(&module_url));
|
2020-05-01 15:33:11 -04:00
|
|
|
|
|
|
|
|
|
let name = match name {
|
|
|
|
|
Some(name) => name,
|
2020-09-14 12:48:57 -04:00
|
|
|
|
None => return Err(generic_error(
|
2020-05-01 15:33:11 -04:00
|
|
|
|
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
|
2020-09-14 12:48:57 -04:00
|
|
|
|
)),
|
2020-05-01 15:33:11 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
validate_name(name.as_str())?;
|
|
|
|
|
let mut file_path = installation_dir.join(&name);
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2020-02-08 03:49:55 -05:00
|
|
|
|
if cfg!(windows) {
|
2020-03-04 03:40:56 -05:00
|
|
|
|
file_path = file_path.with_extension("cmd");
|
2020-02-08 03:49:55 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 15:19:20 -04:00
|
|
|
|
let mut extra_files: Vec<(PathBuf, String)> = vec![];
|
|
|
|
|
|
2020-02-07 03:31:19 -05:00
|
|
|
|
let mut executable_args = vec!["run".to_string()];
|
2020-01-30 18:42:39 -05:00
|
|
|
|
executable_args.extend_from_slice(&flags.to_permission_args());
|
2021-01-07 13:06:08 -05:00
|
|
|
|
if let Some(url) = flags.location.as_ref() {
|
|
|
|
|
executable_args.push("--location".to_string());
|
|
|
|
|
executable_args.push(url.to_string());
|
|
|
|
|
}
|
2022-01-14 13:23:47 -05:00
|
|
|
|
if let Some(ca_file) = &flags.ca_file {
|
2020-02-17 11:59:51 -05:00
|
|
|
|
executable_args.push("--cert".to_string());
|
2022-01-14 13:23:47 -05:00
|
|
|
|
executable_args.push(ca_file.to_owned())
|
2020-02-17 11:59:51 -05:00
|
|
|
|
}
|
2020-04-11 11:47:27 -04:00
|
|
|
|
if let Some(log_level) = flags.log_level {
|
|
|
|
|
if log_level == Level::Error {
|
|
|
|
|
executable_args.push("--quiet".to_string());
|
|
|
|
|
} else {
|
|
|
|
|
executable_args.push("--log-level".to_string());
|
|
|
|
|
let log_level = match log_level {
|
|
|
|
|
Level::Debug => "debug",
|
|
|
|
|
Level::Info => "info",
|
|
|
|
|
_ => {
|
2020-09-14 12:48:57 -04:00
|
|
|
|
return Err(generic_error(format!("invalid log level {}", log_level)))
|
2020-04-11 11:47:27 -04:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
executable_args.push(log_level.to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-04 07:35:00 -04:00
|
|
|
|
|
2021-11-29 17:23:30 -05:00
|
|
|
|
// we should avoid a default branch here to ensure we continue to cover any
|
|
|
|
|
// changes to this flag.
|
2022-04-10 19:12:51 -04:00
|
|
|
|
match flags.type_check_mode {
|
2022-05-17 17:53:42 -04:00
|
|
|
|
TypeCheckMode::All => executable_args.push("--check=all".to_string()),
|
|
|
|
|
TypeCheckMode::None => {}
|
|
|
|
|
TypeCheckMode::Local => executable_args.push("--check".to_string()),
|
2020-08-12 14:22:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 07:35:00 -04:00
|
|
|
|
if flags.unstable {
|
|
|
|
|
executable_args.push("--unstable".to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 15:19:20 -04:00
|
|
|
|
if flags.no_remote {
|
|
|
|
|
executable_args.push("--no-remote".to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-07 09:33:51 -04:00
|
|
|
|
if flags.no_npm {
|
|
|
|
|
executable_args.push("--no-npm".to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 15:19:20 -04:00
|
|
|
|
if flags.lock_write {
|
|
|
|
|
executable_args.push("--lock-write".to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if flags.cached_only {
|
2021-01-19 07:46:08 -05:00
|
|
|
|
executable_args.push("--cached-only".to_string());
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-12 22:13:21 -05:00
|
|
|
|
if flags.no_prompt {
|
|
|
|
|
executable_args.push("--no-prompt".to_string());
|
2022-01-14 09:59:32 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-12-06 12:19:21 -05:00
|
|
|
|
if !flags.v8_flags.is_empty() {
|
|
|
|
|
executable_args.push(format!("--v8-flags={}", flags.v8_flags.join(",")));
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(seed) = flags.seed {
|
|
|
|
|
executable_args.push("--seed".to_string());
|
|
|
|
|
executable_args.push(seed.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(inspect) = flags.inspect {
|
2022-01-15 01:10:12 -05:00
|
|
|
|
executable_args.push(format!("--inspect={}", inspect));
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(inspect_brk) = flags.inspect_brk {
|
2022-01-15 01:10:12 -05:00
|
|
|
|
executable_args.push(format!("--inspect-brk={}", inspect_brk));
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
if let Some(import_map_path) = &flags.import_map_path {
|
|
|
|
|
let import_map_url = resolve_url_or_path(import_map_path)?;
|
2020-10-20 08:30:59 -04:00
|
|
|
|
executable_args.push("--import-map".to_string());
|
2021-05-09 20:48:30 -04:00
|
|
|
|
executable_args.push(import_map_url.to_string());
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-13 11:40:50 -04:00
|
|
|
|
if let ConfigFlag::Path(config_path) = &flags.config_flag {
|
2020-10-19 15:19:20 -04:00
|
|
|
|
let mut copy_path = file_path.clone();
|
|
|
|
|
copy_path.set_extension("tsconfig.json");
|
|
|
|
|
executable_args.push("--config".to_string());
|
|
|
|
|
executable_args.push(copy_path.to_str().unwrap().to_string());
|
2022-11-14 22:40:05 -05:00
|
|
|
|
extra_files.push((
|
|
|
|
|
copy_path,
|
|
|
|
|
fs::read_to_string(config_path)
|
|
|
|
|
.with_context(|| format!("error reading {}", config_path))?,
|
|
|
|
|
));
|
2020-10-19 15:19:20 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 22:40:05 -05:00
|
|
|
|
if flags.no_lock {
|
|
|
|
|
executable_args.push("--no-lock".to_string());
|
|
|
|
|
} else if flags.lock.is_some()
|
|
|
|
|
// always use a lockfile for an npm entrypoint unless --no-lock
|
|
|
|
|
|| NpmPackageReference::from_specifier(&module_url).is_ok()
|
|
|
|
|
{
|
2020-10-19 15:19:20 -04:00
|
|
|
|
let mut copy_path = file_path.clone();
|
|
|
|
|
copy_path.set_extension("lock.json");
|
|
|
|
|
executable_args.push("--lock".to_string());
|
|
|
|
|
executable_args.push(copy_path.to_str().unwrap().to_string());
|
2022-11-14 22:40:05 -05:00
|
|
|
|
|
|
|
|
|
if let Some(lock_path) = &flags.lock {
|
|
|
|
|
extra_files.push((
|
|
|
|
|
copy_path,
|
|
|
|
|
fs::read_to_string(lock_path)
|
|
|
|
|
.with_context(|| format!("error reading {}", lock_path.display()))?,
|
|
|
|
|
));
|
2022-11-21 14:24:51 -05:00
|
|
|
|
} else {
|
|
|
|
|
// Provide an empty lockfile so that this overwrites any existing lockfile
|
|
|
|
|
// from a previous installation. This will get populated on first run.
|
|
|
|
|
extra_files.push((copy_path, "{}".to_string()));
|
2022-11-14 22:40:05 -05:00
|
|
|
|
}
|
2020-09-16 11:56:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
executable_args.push(module_url.to_string());
|
2021-12-21 09:49:27 -05:00
|
|
|
|
executable_args.extend_from_slice(&install_flags.args);
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
Ok(ShimData {
|
|
|
|
|
name,
|
|
|
|
|
installation_dir,
|
|
|
|
|
file_path,
|
|
|
|
|
args: executable_args,
|
|
|
|
|
extra_files,
|
|
|
|
|
})
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 14:17:37 -04:00
|
|
|
|
fn is_in_path(dir: &Path) -> bool {
|
2020-01-30 18:42:39 -05:00
|
|
|
|
if let Some(paths) = env::var_os("PATH") {
|
|
|
|
|
for p in env::split_paths(&paths) {
|
|
|
|
|
if *dir == p {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2022-03-22 13:37:15 -04:00
|
|
|
|
|
2022-06-27 16:54:09 -04:00
|
|
|
|
use crate::args::ConfigFlag;
|
2021-01-18 22:34:37 -05:00
|
|
|
|
use std::process::Command;
|
2021-08-11 10:20:47 -04:00
|
|
|
|
use test_util::testdata_path;
|
2022-04-01 11:15:37 -04:00
|
|
|
|
use test_util::TempDir;
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2020-05-01 15:33:11 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_infer_name_from_url() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc/server.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("server".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc/main.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc/mod.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc/index.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc/cli.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("https://example.com/main.ts").unwrap()),
|
|
|
|
|
Some("main".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("https://example.com").unwrap()),
|
|
|
|
|
None
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("file:///abc/server.ts").unwrap()),
|
|
|
|
|
Some("server".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("file:///abc/main.ts").unwrap()),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("file:///main.ts").unwrap()),
|
|
|
|
|
Some("main".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(infer_name_from_url(&Url::parse("file:///").unwrap()), None);
|
2020-08-27 16:55:58 -04:00
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc@0.1.0").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc@0.1.0/main.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/abc@def@ghi").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("abc".to_string())
|
|
|
|
|
);
|
2022-10-11 22:32:52 -04:00
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("https://example.com/@abc.ts").unwrap()),
|
|
|
|
|
Some("@abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(
|
|
|
|
|
&Url::parse("https://example.com/@abc/mod.ts").unwrap()
|
|
|
|
|
),
|
|
|
|
|
Some("@abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("file:///@abc.ts").unwrap()),
|
|
|
|
|
Some("@abc".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("file:///@abc/cli.ts").unwrap()),
|
|
|
|
|
Some("@abc".to_string())
|
|
|
|
|
);
|
2022-11-14 22:40:05 -05:00
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("npm:cowsay@1.2/cowthink").unwrap()),
|
|
|
|
|
Some("cowthink".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("npm:cowsay@1.2/cowthink/test").unwrap()),
|
|
|
|
|
Some("cowsay".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("npm:cowsay@1.2").unwrap()),
|
|
|
|
|
Some("cowsay".to_string())
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
infer_name_from_url(&Url::parse("npm:@types/node@1.2").unwrap()),
|
|
|
|
|
None
|
|
|
|
|
);
|
2020-05-01 15:33:11 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_unstable() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2020-05-04 07:35:00 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
|
|
|
|
|
|
|
|
|
install(
|
|
|
|
|
Flags {
|
|
|
|
|
unstable: true,
|
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-05-04 07:35:00 -04:00
|
|
|
|
)
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2020-05-04 07:35:00 -04:00
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
|
|
|
|
println!("this is the file path {:?}", content);
|
2020-11-09 14:08:12 -05:00
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
assert!(content.contains(
|
2022-06-13 17:13:16 -04:00
|
|
|
|
r#""run" "--unstable" "http://localhost:4545/echo_server.ts""#
|
2020-11-09 14:08:12 -05:00
|
|
|
|
));
|
|
|
|
|
} else {
|
2022-06-13 17:13:16 -04:00
|
|
|
|
assert!(content
|
|
|
|
|
.contains(r#"run --unstable 'http://localhost:4545/echo_server.ts'"#));
|
2020-11-09 14:08:12 -05:00
|
|
|
|
}
|
2020-05-04 07:35:00 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_inferred_name() {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags::default(),
|
|
|
|
|
&InstallFlags {
|
2021-12-21 09:49:27 -05:00
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: None,
|
2022-01-14 13:23:47 -05:00
|
|
|
|
root: Some(env::temp_dir()),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-05-01 15:33:11 -04:00
|
|
|
|
)
|
2022-01-14 13:23:47 -05:00
|
|
|
|
.unwrap();
|
2020-05-01 15:33:11 -04:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
assert_eq!(shim_data.name, "echo_server");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-06-13 17:13:16 -04:00
|
|
|
|
vec!["run", "http://localhost:4545/echo_server.ts",]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
);
|
2020-05-01 15:33:11 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_inferred_name_from_parent() {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags::default(),
|
|
|
|
|
&InstallFlags {
|
2021-12-21 09:49:27 -05:00
|
|
|
|
module_url: "http://localhost:4545/subdir/main.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: None,
|
2022-01-14 13:23:47 -05:00
|
|
|
|
root: Some(env::temp_dir()),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-05-01 15:33:11 -04:00
|
|
|
|
)
|
2022-01-14 13:23:47 -05:00
|
|
|
|
.unwrap();
|
2020-05-01 15:33:11 -04:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
assert_eq!(shim_data.name, "subdir");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-06-13 17:13:16 -04:00
|
|
|
|
vec!["run", "http://localhost:4545/subdir/main.ts",]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
);
|
2020-05-01 15:33:11 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_custom_dir_option() {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags::default(),
|
|
|
|
|
&InstallFlags {
|
2021-12-21 09:49:27 -05:00
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
2022-01-14 13:23:47 -05:00
|
|
|
|
root: Some(env::temp_dir()),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-01-30 18:42:39 -05:00
|
|
|
|
)
|
2022-01-14 13:23:47 -05:00
|
|
|
|
.unwrap();
|
2020-04-16 18:15:42 -04:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
assert_eq!(shim_data.name, "echo_test");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-06-13 17:13:16 -04:00
|
|
|
|
vec!["run", "http://localhost:4545/echo_server.ts",]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
);
|
2020-04-16 18:15:42 -04:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_with_flags() {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags {
|
2020-12-29 13:34:35 -05:00
|
|
|
|
allow_net: Some(vec![]),
|
|
|
|
|
allow_read: Some(vec![]),
|
2022-04-10 19:12:51 -04:00
|
|
|
|
type_check_mode: TypeCheckMode::None,
|
2020-04-11 11:47:27 -04:00
|
|
|
|
log_level: Some(Level::Error),
|
2020-02-26 05:52:15 -05:00
|
|
|
|
..Flags::default()
|
2020-01-30 18:42:39 -05:00
|
|
|
|
},
|
2022-01-14 13:23:47 -05:00
|
|
|
|
&InstallFlags {
|
2021-12-21 09:49:27 -05:00
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec!["--foobar".to_string()],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
2022-01-14 13:23:47 -05:00
|
|
|
|
root: Some(env::temp_dir()),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-01-30 18:42:39 -05:00
|
|
|
|
)
|
2022-01-14 13:23:47 -05:00
|
|
|
|
.unwrap();
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
assert_eq!(shim_data.name, "echo_test");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
|
|
|
|
vec![
|
|
|
|
|
"run",
|
|
|
|
|
"--allow-read",
|
|
|
|
|
"--allow-net",
|
|
|
|
|
"--quiet",
|
|
|
|
|
"http://localhost:4545/echo_server.ts",
|
|
|
|
|
"--foobar",
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_prompt() {
|
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags {
|
2022-02-12 22:13:21 -05:00
|
|
|
|
no_prompt: true,
|
2022-01-14 13:23:47 -05:00
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
|
|
|
|
&InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(env::temp_dir()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-06-13 17:13:16 -04:00
|
|
|
|
vec!["run", "--no-prompt", "http://localhost:4545/echo_server.ts",]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
);
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 09:22:03 -05:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_allow_all() {
|
2022-01-14 13:23:47 -05:00
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags {
|
2022-01-10 09:22:03 -05:00
|
|
|
|
allow_all: true,
|
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
2022-01-14 13:23:47 -05:00
|
|
|
|
&InstallFlags {
|
2022-01-10 09:22:03 -05:00
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
2022-01-14 13:23:47 -05:00
|
|
|
|
root: Some(env::temp_dir()),
|
2022-01-10 09:22:03 -05:00
|
|
|
|
force: false,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2022-01-14 13:23:47 -05:00
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-06-13 17:13:16 -04:00
|
|
|
|
vec!["run", "--allow-all", "http://localhost:4545/echo_server.ts",]
|
2022-01-14 13:23:47 -05:00
|
|
|
|
);
|
2022-01-10 09:22:03 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 22:40:05 -05:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_npm_lockfile_default() {
|
|
|
|
|
let temp_dir = fs_util::canonicalize_path(&env::temp_dir()).unwrap();
|
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags {
|
|
|
|
|
allow_all: true,
|
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
|
|
|
|
&InstallFlags {
|
|
|
|
|
module_url: "npm:cowsay".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: None,
|
|
|
|
|
root: Some(temp_dir.clone()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2022-11-21 14:24:51 -05:00
|
|
|
|
let lock_path = temp_dir.join("bin").join("cowsay.lock.json");
|
2022-11-14 22:40:05 -05:00
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
2022-11-21 14:24:51 -05:00
|
|
|
|
vec![
|
|
|
|
|
"run",
|
|
|
|
|
"--allow-all",
|
|
|
|
|
"--lock",
|
|
|
|
|
&lock_path.to_string_lossy(),
|
|
|
|
|
"npm:cowsay"
|
|
|
|
|
]
|
2022-11-14 22:40:05 -05:00
|
|
|
|
);
|
2022-11-21 14:24:51 -05:00
|
|
|
|
assert_eq!(shim_data.extra_files, vec![(lock_path, "{}".to_string())]);
|
2022-11-14 22:40:05 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_npm_no_lock() {
|
|
|
|
|
let shim_data = resolve_shim_data(
|
|
|
|
|
&Flags {
|
|
|
|
|
allow_all: true,
|
|
|
|
|
no_lock: true,
|
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
|
|
|
|
&InstallFlags {
|
|
|
|
|
module_url: "npm:cowsay".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: None,
|
|
|
|
|
root: Some(env::temp_dir()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
shim_data.args,
|
|
|
|
|
vec!["run", "--allow-all", "--no-lock", "npm:cowsay"]
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(shim_data.extra_files, vec![]);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_local_module() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2020-04-16 18:15:42 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
2020-09-16 11:56:06 -04:00
|
|
|
|
let local_module = env::current_dir().unwrap().join("echo_server.ts");
|
|
|
|
|
let local_module_url = Url::from_file_path(&local_module).unwrap();
|
2020-01-30 18:42:39 -05:00
|
|
|
|
let local_module_str = local_module.to_string_lossy();
|
|
|
|
|
|
|
|
|
|
install(
|
2020-02-26 05:52:15 -05:00
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: local_module_str.to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-01-30 18:42:39 -05:00
|
|
|
|
)
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2020-01-30 18:42:39 -05:00
|
|
|
|
|
2020-04-16 18:15:42 -04:00
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
2020-01-30 18:42:39 -05:00
|
|
|
|
if cfg!(windows) {
|
2020-03-04 03:40:56 -05:00
|
|
|
|
file_path = file_path.with_extension("cmd");
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
2020-09-16 11:56:06 -04:00
|
|
|
|
assert!(content.contains(&local_module_url.to_string()));
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|
2020-02-08 03:49:55 -05:00
|
|
|
|
|
2020-09-16 11:56:06 -04:00
|
|
|
|
#[test]
|
|
|
|
|
fn install_force() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2020-04-16 18:15:42 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
2020-02-08 03:49:55 -05:00
|
|
|
|
|
|
|
|
|
install(
|
2020-02-26 05:52:15 -05:00
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-02-08 03:49:55 -05:00
|
|
|
|
)
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2020-02-08 03:49:55 -05:00
|
|
|
|
|
2020-04-16 18:15:42 -04:00
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
2020-02-08 03:49:55 -05:00
|
|
|
|
if cfg!(windows) {
|
2020-03-04 03:40:56 -05:00
|
|
|
|
file_path = file_path.with_extension("cmd");
|
2020-02-08 03:49:55 -05:00
|
|
|
|
}
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
|
|
|
|
|
// No force. Install failed.
|
|
|
|
|
let no_force_result = install(
|
2020-09-16 11:56:06 -04:00
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/cat.ts".to_string(), // using a different URL
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-09-16 11:56:06 -04:00
|
|
|
|
);
|
2020-02-08 03:49:55 -05:00
|
|
|
|
assert!(no_force_result.is_err());
|
|
|
|
|
assert!(no_force_result
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.to_string()
|
|
|
|
|
.contains("Existing installation found"));
|
|
|
|
|
// Assert not modified
|
|
|
|
|
let file_content = fs::read_to_string(&file_path).unwrap();
|
2020-09-16 11:56:06 -04:00
|
|
|
|
assert!(file_content.contains("echo_server.ts"));
|
2020-02-08 03:49:55 -05:00
|
|
|
|
|
|
|
|
|
// Force. Install success.
|
|
|
|
|
let force_result = install(
|
2020-09-16 11:56:06 -04:00
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/cat.ts".to_string(), // using a different URL
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: true,
|
|
|
|
|
},
|
2020-09-16 11:56:06 -04:00
|
|
|
|
);
|
2020-02-08 03:49:55 -05:00
|
|
|
|
assert!(force_result.is_ok());
|
|
|
|
|
// Assert modified
|
|
|
|
|
let file_content_2 = fs::read_to_string(&file_path).unwrap();
|
2020-09-16 11:56:06 -04:00
|
|
|
|
assert!(file_content_2.contains("cat.ts"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_with_config() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2020-09-16 11:56:06 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
let config_file_path = temp_dir.path().join("test_tsconfig.json");
|
|
|
|
|
let config = "{}";
|
|
|
|
|
let mut config_file = File::create(&config_file_path).unwrap();
|
|
|
|
|
let result = config_file.write_all(config.as_bytes());
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
let result = install(
|
|
|
|
|
Flags {
|
2022-05-13 11:40:50 -04:00
|
|
|
|
config_flag: ConfigFlag::Path(
|
|
|
|
|
config_file_path.to_string_lossy().to_string(),
|
|
|
|
|
),
|
2020-09-16 11:56:06 -04:00
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/cat.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: true,
|
|
|
|
|
},
|
2020-09-16 11:56:06 -04:00
|
|
|
|
);
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
let config_file_name = "echo_test.tsconfig.json";
|
|
|
|
|
|
2022-02-24 20:03:12 -05:00
|
|
|
|
let file_path = bin_dir.join(config_file_name);
|
2020-09-16 11:56:06 -04:00
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
|
|
|
|
assert!(content == "{}");
|
2020-07-12 09:05:47 -04:00
|
|
|
|
}
|
2020-11-09 14:08:12 -05:00
|
|
|
|
|
|
|
|
|
// TODO: enable on Windows after fixing batch escaping
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_shell_escaping() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2020-11-09 14:08:12 -05:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
|
|
|
|
|
|
|
|
|
install(
|
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
|
|
|
|
args: vec!["\"".to_string()],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2020-11-09 14:08:12 -05:00
|
|
|
|
)
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2020-11-09 14:08:12 -05:00
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
|
|
|
|
println!("{}", content);
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
// TODO: see comment above this test
|
|
|
|
|
} else {
|
2022-06-13 17:13:16 -04:00
|
|
|
|
assert!(
|
|
|
|
|
content.contains(r#"run 'http://localhost:4545/echo_server.ts' '"'"#)
|
|
|
|
|
);
|
2020-11-09 14:08:12 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-18 22:34:37 -05:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_unicode() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2021-01-18 22:34:37 -05:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
|
|
|
|
let unicode_dir = temp_dir.path().join("Magnús");
|
|
|
|
|
std::fs::create_dir(&unicode_dir).unwrap();
|
|
|
|
|
let local_module = unicode_dir.join("echo_server.ts");
|
|
|
|
|
let local_module_str = local_module.to_string_lossy();
|
|
|
|
|
std::fs::write(&local_module, "// Some JavaScript I guess").unwrap();
|
|
|
|
|
|
|
|
|
|
install(
|
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: local_module_str.to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: false,
|
|
|
|
|
},
|
2021-01-18 22:34:37 -05:00
|
|
|
|
)
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2021-01-18 22:34:37 -05:00
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to actually run it to make sure the URL is interpreted correctly
|
2022-03-22 13:37:15 -04:00
|
|
|
|
let status = Command::new(file_path)
|
|
|
|
|
.env_clear()
|
|
|
|
|
// use the deno binary in the target directory
|
|
|
|
|
.env("PATH", test_util::target_dir())
|
|
|
|
|
.spawn()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.wait()
|
|
|
|
|
.unwrap();
|
2021-01-18 22:34:37 -05:00
|
|
|
|
assert!(status.success());
|
|
|
|
|
}
|
2021-05-09 20:48:30 -04:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_with_import_map() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2021-05-09 20:48:30 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
let import_map_path = temp_dir.path().join("import_map.json");
|
|
|
|
|
let import_map_url = Url::from_file_path(&import_map_path).unwrap();
|
|
|
|
|
let import_map = "{ \"imports\": {} }";
|
|
|
|
|
let mut import_map_file = File::create(&import_map_path).unwrap();
|
|
|
|
|
let result = import_map_file.write_all(import_map.as_bytes());
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
let result = install(
|
|
|
|
|
Flags {
|
|
|
|
|
import_map_path: Some(import_map_path.to_string_lossy().to_string()),
|
|
|
|
|
..Flags::default()
|
|
|
|
|
},
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: "http://localhost:4545/cat.ts".to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: true,
|
|
|
|
|
},
|
2021-05-09 20:48:30 -04:00
|
|
|
|
);
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
}
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
|
|
|
|
|
let mut expected_string = format!(
|
2021-08-11 10:20:47 -04:00
|
|
|
|
"--import-map '{}' 'http://localhost:4545/cat.ts'",
|
2022-01-15 01:10:12 -05:00
|
|
|
|
import_map_url
|
2021-05-09 20:48:30 -04:00
|
|
|
|
);
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
expected_string = format!(
|
2021-08-11 10:20:47 -04:00
|
|
|
|
"\"--import-map\" \"{}\" \"http://localhost:4545/cat.ts\"",
|
2022-01-15 01:10:12 -05:00
|
|
|
|
import_map_url
|
2021-05-09 20:48:30 -04:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
|
|
|
|
assert!(content.contains(&expected_string));
|
|
|
|
|
}
|
2021-05-19 07:40:23 -04:00
|
|
|
|
|
|
|
|
|
// Regression test for https://github.com/denoland/deno/issues/10556.
|
|
|
|
|
#[test]
|
|
|
|
|
fn install_file_url() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2021-05-19 07:40:23 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
2021-08-11 10:20:47 -04:00
|
|
|
|
let module_path = fs::canonicalize(testdata_path().join("cat.ts")).unwrap();
|
2021-05-19 07:40:23 -04:00
|
|
|
|
let file_module_string =
|
|
|
|
|
Url::from_file_path(module_path).unwrap().to_string();
|
|
|
|
|
assert!(file_module_string.starts_with("file:///"));
|
|
|
|
|
|
|
|
|
|
let result = install(
|
|
|
|
|
Flags::default(),
|
2021-12-21 09:49:27 -05:00
|
|
|
|
InstallFlags {
|
|
|
|
|
module_url: file_module_string.to_string(),
|
|
|
|
|
args: vec![],
|
|
|
|
|
name: Some("echo_test".to_string()),
|
|
|
|
|
root: Some(temp_dir.path().to_path_buf()),
|
|
|
|
|
force: true,
|
|
|
|
|
},
|
2021-05-19 07:40:23 -04:00
|
|
|
|
);
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
}
|
|
|
|
|
assert!(file_path.exists());
|
|
|
|
|
|
2022-06-13 17:13:16 -04:00
|
|
|
|
let mut expected_string = format!("run '{}'", &file_module_string);
|
2021-05-19 07:40:23 -04:00
|
|
|
|
if cfg!(windows) {
|
2022-06-13 17:13:16 -04:00
|
|
|
|
expected_string = format!("\"run\" \"{}\"", &file_module_string);
|
2021-05-19 07:40:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let content = fs::read_to_string(file_path).unwrap();
|
|
|
|
|
assert!(content.contains(&expected_string));
|
|
|
|
|
}
|
2021-09-30 11:38:07 -04:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn uninstall_basic() {
|
2022-04-01 11:15:37 -04:00
|
|
|
|
let temp_dir = TempDir::new();
|
2021-09-30 11:38:07 -04:00
|
|
|
|
let bin_dir = temp_dir.path().join("bin");
|
|
|
|
|
std::fs::create_dir(&bin_dir).unwrap();
|
|
|
|
|
|
|
|
|
|
let mut file_path = bin_dir.join("echo_test");
|
|
|
|
|
File::create(&file_path).unwrap();
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
File::create(&file_path).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create extra files
|
2022-11-14 22:40:05 -05:00
|
|
|
|
{
|
|
|
|
|
let file_path = file_path.with_extension("tsconfig.json");
|
|
|
|
|
File::create(&file_path).unwrap();
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let file_path = file_path.with_extension("lock.json");
|
|
|
|
|
File::create(&file_path).unwrap();
|
|
|
|
|
}
|
2021-09-30 11:38:07 -04:00
|
|
|
|
|
|
|
|
|
uninstall("echo_test".to_string(), Some(temp_dir.path().to_path_buf()))
|
2022-03-22 13:37:15 -04:00
|
|
|
|
.unwrap();
|
2021-09-30 11:38:07 -04:00
|
|
|
|
|
|
|
|
|
assert!(!file_path.exists());
|
|
|
|
|
assert!(!file_path.with_extension("tsconfig.json").exists());
|
|
|
|
|
assert!(!file_path.with_extension("lock.json").exists());
|
|
|
|
|
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
file_path = file_path.with_extension("cmd");
|
|
|
|
|
assert!(!file_path.exists());
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-30 18:42:39 -05:00
|
|
|
|
}
|