mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
feat(install): bundle before installation (#5276)
This commit is contained in:
parent
a14b3c9e30
commit
34e98fa59c
2 changed files with 116 additions and 134 deletions
240
cli/installer.rs
240
cli/installer.rs
|
@ -1,5 +1,8 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::flags::Flags;
|
||||
use crate::global_state::GlobalState;
|
||||
use deno_core::ErrBox;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use log::Level;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use std::env;
|
||||
|
@ -79,14 +82,18 @@ deno {} "$@"
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_config_file(
|
||||
file_path: PathBuf,
|
||||
config_file_name: String,
|
||||
) -> Result<(), Error> {
|
||||
let config_file_copy_path = get_config_file_path(&file_path);
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
let config_file_path = cwd.join(config_file_name);
|
||||
fs::copy(config_file_path, config_file_copy_path)?;
|
||||
async fn generate_bundle(
|
||||
flags: Flags,
|
||||
module_specifier: ModuleSpecifier,
|
||||
script_path: PathBuf,
|
||||
) -> Result<(), ErrBox> {
|
||||
let global_state = GlobalState::new(flags.clone())?;
|
||||
let source = global_state
|
||||
.ts_compiler
|
||||
.bundle(&global_state, module_specifier)
|
||||
.await?;
|
||||
let mut file = File::create(&script_path)?;
|
||||
file.write_all(source.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -127,14 +134,14 @@ fn infer_name_from_url(url: &Url) -> Option<String> {
|
|||
Some(stem)
|
||||
}
|
||||
|
||||
pub fn install(
|
||||
pub async fn install(
|
||||
flags: Flags,
|
||||
module_url: &str,
|
||||
args: Vec<String>,
|
||||
name: Option<String>,
|
||||
root: Option<PathBuf>,
|
||||
force: bool,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), ErrBox> {
|
||||
let root = if let Some(root) = root {
|
||||
root.canonicalize()?
|
||||
} else {
|
||||
|
@ -145,56 +152,47 @@ pub fn install(
|
|||
// ensure directory exists
|
||||
if let Ok(metadata) = fs::metadata(&installation_dir) {
|
||||
if !metadata.is_dir() {
|
||||
return Err(Error::new(
|
||||
return Err(ErrBox::from(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Installation path is not a directory",
|
||||
));
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
fs::create_dir_all(&installation_dir)?;
|
||||
};
|
||||
|
||||
// Check if module_url is remote
|
||||
let module_url = if is_remote_url(module_url) {
|
||||
Url::parse(module_url).expect("Should be valid url")
|
||||
} else {
|
||||
let module_path = PathBuf::from(module_url);
|
||||
let module_path = if module_path.is_absolute() {
|
||||
module_path
|
||||
} else {
|
||||
let cwd = env::current_dir().unwrap();
|
||||
cwd.join(module_path)
|
||||
};
|
||||
Url::from_file_path(module_path).expect("Path should be absolute")
|
||||
};
|
||||
let module_specifier = ModuleSpecifier::resolve_url_or_path(module_url)?;
|
||||
let module_specifier_ = module_specifier.clone();
|
||||
let url = module_specifier_.as_url();
|
||||
|
||||
let name = name.or_else(|| infer_name_from_url(&module_url));
|
||||
let name = name.or_else(|| infer_name_from_url(&url));
|
||||
|
||||
let name = match name {
|
||||
Some(name) => name,
|
||||
None => return Err(Error::new(
|
||||
None => return Err(ErrBox::from(Error::new(
|
||||
ErrorKind::Other,
|
||||
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
|
||||
)),
|
||||
))),
|
||||
};
|
||||
|
||||
validate_name(name.as_str())?;
|
||||
let mut file_path = installation_dir.join(&name);
|
||||
let script_path = file_path.with_extension("js");
|
||||
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
if file_path.exists() && !force {
|
||||
return Err(Error::new(
|
||||
return Err(ErrBox::from(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Existing installation found. Aborting (Use -f to overwrite).",
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
let mut executable_args = vec!["run".to_string()];
|
||||
executable_args.extend_from_slice(&flags.to_permission_args());
|
||||
if let Some(ca_file) = flags.ca_file {
|
||||
if let Some(ca_file) = flags.ca_file.clone() {
|
||||
executable_args.push("--cert".to_string());
|
||||
executable_args.push(ca_file)
|
||||
}
|
||||
|
@ -207,10 +205,10 @@ pub fn install(
|
|||
Level::Debug => "debug",
|
||||
Level::Info => "info",
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
return Err(ErrBox::from(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("invalid log level {}", log_level),
|
||||
))
|
||||
)))
|
||||
}
|
||||
};
|
||||
executable_args.push(log_level.to_string());
|
||||
|
@ -225,22 +223,11 @@ pub fn install(
|
|||
executable_args.push("--unstable".to_string());
|
||||
}
|
||||
|
||||
if flags.config_path.is_some() {
|
||||
let config_file_path = get_config_file_path(&file_path);
|
||||
let config_file_path_option = config_file_path.to_str();
|
||||
if let Some(config_file_path_string) = config_file_path_option {
|
||||
executable_args.push("--config".to_string());
|
||||
executable_args.push(config_file_path_string.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
executable_args.push(module_url.to_string());
|
||||
executable_args.push(script_path.to_string_lossy().to_string());
|
||||
executable_args.extend_from_slice(&args);
|
||||
|
||||
generate_executable_file(file_path.to_owned(), executable_args)?;
|
||||
if let Some(config_path) = flags.config_path {
|
||||
generate_config_file(file_path.to_owned(), config_path)?;
|
||||
}
|
||||
generate_bundle(flags, module_specifier, script_path).await?;
|
||||
|
||||
println!("✅ Successfully installed {}", name);
|
||||
println!("{}", file_path.to_string_lossy());
|
||||
|
@ -269,12 +256,6 @@ fn is_in_path(dir: &PathBuf) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
fn get_config_file_path(file_path: &PathBuf) -> PathBuf {
|
||||
let mut config_file_copy_path = PathBuf::from(file_path);
|
||||
config_file_copy_path.set_extension("tsconfig.json");
|
||||
config_file_copy_path
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -368,9 +349,10 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_basic() {
|
||||
#[tokio::test]
|
||||
async fn install_basic() {
|
||||
let _guard = ENV_LOCK.lock().ok();
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let temp_dir_str = temp_dir.path().to_string_lossy().to_string();
|
||||
// NOTE: this test overrides environmental variables
|
||||
|
@ -392,6 +374,7 @@ mod tests {
|
|||
None,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = temp_dir.path().join(".deno/bin/echo_test");
|
||||
|
@ -405,8 +388,8 @@ mod tests {
|
|||
// It's annoying when shell scripts don't have NL at the end.
|
||||
assert_eq!(content.chars().last().unwrap(), '\n');
|
||||
|
||||
assert!(content
|
||||
.contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#));
|
||||
assert!(content.contains(r#""run""#));
|
||||
assert!(content.contains(r#"echo_test.js"#));
|
||||
if let Some(home) = original_home {
|
||||
env::set_var("HOME", home);
|
||||
}
|
||||
|
@ -418,8 +401,9 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_unstable() {
|
||||
#[tokio::test]
|
||||
async fn install_unstable() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -435,6 +419,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -443,16 +428,17 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
println!("this is the file path {:?}", content);
|
||||
assert!(content.contains(
|
||||
r#""run" "--unstable" "http://localhost:4545/cli/tests/echo_server.ts"#
|
||||
));
|
||||
assert!(content.contains(r#""run" "--unstable""#));
|
||||
assert!(content.contains(r#"echo_test.js"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_inferred_name() {
|
||||
#[tokio::test]
|
||||
async fn install_inferred_name() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -465,6 +451,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_server");
|
||||
|
@ -473,13 +460,16 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content
|
||||
.contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#));
|
||||
assert!(content.contains(r#""run""#));
|
||||
assert!(content.contains(r#"echo_server.js"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_inferred_name_from_parent() {
|
||||
#[tokio::test]
|
||||
async fn install_inferred_name_from_parent() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -492,6 +482,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("subdir");
|
||||
|
@ -500,13 +491,17 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content
|
||||
.contains(r#""run" "http://localhost:4545/cli/tests/subdir/main.ts""#));
|
||||
assert!(content.contains(r#""run""#));
|
||||
assert!(content.contains(r#"subdir.js"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_custom_dir_option() {
|
||||
#[tokio::test]
|
||||
async fn install_custom_dir_option() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -519,6 +514,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -527,14 +523,17 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content
|
||||
.contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#));
|
||||
assert!(content.contains(r#""run""#));
|
||||
assert!(content.contains(r#"echo_test.js"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_custom_dir_env_var() {
|
||||
#[tokio::test]
|
||||
async fn install_custom_dir_env_var() {
|
||||
let _guard = ENV_LOCK.lock().ok();
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -549,6 +548,7 @@ mod tests {
|
|||
None,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -557,16 +557,20 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content
|
||||
.contains(r#""run" "http://localhost:4545/cli/tests/echo_server.ts""#));
|
||||
assert!(content.contains(r#""run""#));
|
||||
assert!(content.contains(r#"echo_test.js"#));
|
||||
|
||||
if let Some(install_root) = original_install_root {
|
||||
env::set_var("DENO_INSTALL_ROOT", install_root);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_flags() {
|
||||
#[tokio::test]
|
||||
async fn install_with_flags() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -585,6 +589,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -593,17 +598,21 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content.contains(r#""run" "--allow-read" "--allow-net" "--quiet" "--no-check" "http://localhost:4545/cli/tests/echo_server.ts" "--foobar""#));
|
||||
assert!(content.contains(
|
||||
r#""run" "--allow-read" "--allow-net" "--quiet" "--no-check""#
|
||||
));
|
||||
assert!(content.contains(r#"echo_test.js" "--foobar""#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_local_module() {
|
||||
#[tokio::test]
|
||||
async fn install_local_module() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
let local_module = env::current_dir().unwrap().join("echo_server.ts");
|
||||
let local_module_url = Url::from_file_path(&local_module).unwrap();
|
||||
let local_module = env::current_dir().unwrap().join("tests/echo_server.ts");
|
||||
let local_module_str = local_module.to_string_lossy();
|
||||
|
||||
install(
|
||||
|
@ -614,6 +623,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -622,12 +632,14 @@ mod tests {
|
|||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content.contains(&local_module_url.to_string()));
|
||||
assert!(content.contains("echo_test.js"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_force() {
|
||||
#[tokio::test]
|
||||
async fn install_force() {
|
||||
let _http_server_guard = test_util::http_server();
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
@ -640,6 +652,7 @@ mod tests {
|
|||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
|
@ -647,16 +660,21 @@ mod tests {
|
|||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
assert!(file_path.exists());
|
||||
assert!(file_path.with_extension("js").exists());
|
||||
|
||||
// No force. Install failed.
|
||||
let no_force_result = install(
|
||||
Flags::default(),
|
||||
Flags {
|
||||
unstable: true,
|
||||
..Flags::default()
|
||||
},
|
||||
"http://localhost:4545/cli/tests/cat.ts", // using a different URL
|
||||
vec![],
|
||||
Some("echo_test".to_string()),
|
||||
Some(temp_dir.path().to_path_buf()),
|
||||
false,
|
||||
);
|
||||
)
|
||||
.await;
|
||||
assert!(no_force_result.is_err());
|
||||
assert!(no_force_result
|
||||
.unwrap_err()
|
||||
|
@ -664,52 +682,24 @@ mod tests {
|
|||
.contains("Existing installation found"));
|
||||
// Assert not modified
|
||||
let file_content = fs::read_to_string(&file_path).unwrap();
|
||||
assert!(file_content.contains("echo_server.ts"));
|
||||
assert!(!file_content.contains("--unstable"));
|
||||
|
||||
// Force. Install success.
|
||||
let force_result = install(
|
||||
Flags::default(),
|
||||
Flags {
|
||||
unstable: true,
|
||||
..Flags::default()
|
||||
},
|
||||
"http://localhost:4545/cli/tests/cat.ts", // using a different URL
|
||||
vec![],
|
||||
Some("echo_test".to_string()),
|
||||
Some(temp_dir.path().to_path_buf()),
|
||||
true,
|
||||
);
|
||||
)
|
||||
.await;
|
||||
assert!(force_result.is_ok());
|
||||
// Assert modified
|
||||
let file_content_2 = fs::read_to_string(&file_path).unwrap();
|
||||
assert!(file_content_2.contains("cat.ts"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_config() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
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 {
|
||||
config_path: Some(config_file_path.to_string_lossy().to_string()),
|
||||
..Flags::default()
|
||||
},
|
||||
"http://localhost:4545/cli/tests/cat.ts",
|
||||
vec![],
|
||||
Some("echo_test".to_string()),
|
||||
Some(temp_dir.path().to_path_buf()),
|
||||
true,
|
||||
);
|
||||
eprintln!("result {:?}", result);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let config_file_name = "echo_test.tsconfig.json";
|
||||
|
||||
let file_path = bin_dir.join(config_file_name.to_string());
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
assert!(content == "{}");
|
||||
assert!(file_content_2.contains("--unstable"));
|
||||
}
|
||||
}
|
||||
|
|
10
cli/main.rs
10
cli/main.rs
|
@ -304,15 +304,7 @@ async fn install_command(
|
|||
root: Option<PathBuf>,
|
||||
force: bool,
|
||||
) -> Result<(), ErrBox> {
|
||||
// Firstly fetch and compile module, this step ensures that module exists.
|
||||
let mut fetch_flags = flags.clone();
|
||||
fetch_flags.reload = true;
|
||||
let global_state = GlobalState::new(fetch_flags)?;
|
||||
let main_module = ModuleSpecifier::resolve_url_or_path(&module_url)?;
|
||||
let mut worker = MainWorker::create(&global_state, main_module.clone())?;
|
||||
worker.preload_module(&main_module).await?;
|
||||
installer::install(flags, &module_url, args, name, root, force)
|
||||
.map_err(ErrBox::from)
|
||||
installer::install(flags, &module_url, args, name, root, force).await
|
||||
}
|
||||
|
||||
async fn lint_command(
|
||||
|
|
Loading…
Add table
Reference in a new issue