mirror of
https://github.com/denoland/deno.git
synced 2025-01-19 20:26:20 -05:00
9dbb99a83c
This separates npm resolution code from npm installation (more work towards moving resolution code out of the CLI and cleaning up this code).
221 lines
6.3 KiB
Rust
221 lines
6.3 KiB
Rust
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
use std::io::Read;
|
|
use std::sync::Arc;
|
|
|
|
use deno_cache_dir::file_fetcher::File;
|
|
use deno_config::deno_json::NodeModulesDirMode;
|
|
use deno_core::error::AnyError;
|
|
use deno_runtime::WorkerExecutionMode;
|
|
|
|
use crate::args::EvalFlags;
|
|
use crate::args::Flags;
|
|
use crate::args::WatchFlagsWithPaths;
|
|
use crate::factory::CliFactory;
|
|
use crate::npm::installer::PackageCaching;
|
|
use crate::util;
|
|
use crate::util::file_watcher::WatcherRestartMode;
|
|
|
|
pub mod hmr;
|
|
|
|
pub fn check_permission_before_script(flags: &Flags) {
|
|
if !flags.has_permission() && flags.has_permission_in_argv() {
|
|
log::warn!(
|
|
"{}",
|
|
crate::colors::yellow(
|
|
r#"Permission flags have likely been incorrectly set after the script argument.
|
|
To grant permissions, set them before the script argument. For example:
|
|
deno run --allow-read=. main.js"#
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
fn set_npm_user_agent() {
|
|
static ONCE: std::sync::Once = std::sync::Once::new();
|
|
ONCE.call_once(|| {
|
|
std::env::set_var(
|
|
crate::npm::NPM_CONFIG_USER_AGENT_ENV_VAR,
|
|
crate::npm::get_npm_config_user_agent(),
|
|
);
|
|
});
|
|
}
|
|
|
|
pub async fn run_script(
|
|
mode: WorkerExecutionMode,
|
|
flags: Arc<Flags>,
|
|
watch: Option<WatchFlagsWithPaths>,
|
|
) -> Result<i32, AnyError> {
|
|
check_permission_before_script(&flags);
|
|
|
|
if let Some(watch_flags) = watch {
|
|
return run_with_watch(mode, flags, watch_flags).await;
|
|
}
|
|
|
|
// TODO(bartlomieju): actually I think it will also fail if there's an import
|
|
// map specified and bare specifier is used on the command line
|
|
let factory = CliFactory::from_flags(flags);
|
|
let cli_options = factory.cli_options()?;
|
|
let deno_dir = factory.deno_dir()?;
|
|
let http_client = factory.http_client_provider();
|
|
|
|
// Run a background task that checks for available upgrades or output
|
|
// if an earlier run of this background task found a new version of Deno.
|
|
#[cfg(feature = "upgrade")]
|
|
super::upgrade::check_for_upgrades(
|
|
http_client.clone(),
|
|
deno_dir.upgrade_check_file_path(),
|
|
);
|
|
|
|
let main_module = cli_options.resolve_main_module()?;
|
|
|
|
if main_module.scheme() == "npm" {
|
|
set_npm_user_agent();
|
|
}
|
|
|
|
maybe_npm_install(&factory).await?;
|
|
|
|
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
|
let mut worker = worker_factory
|
|
.create_main_worker(mode, main_module.clone())
|
|
.await?;
|
|
|
|
let exit_code = worker.run().await?;
|
|
Ok(exit_code)
|
|
}
|
|
|
|
pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|
let factory = CliFactory::from_flags(flags);
|
|
let cli_options = factory.cli_options()?;
|
|
let main_module = cli_options.resolve_main_module()?;
|
|
|
|
maybe_npm_install(&factory).await?;
|
|
|
|
let file_fetcher = factory.file_fetcher()?;
|
|
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
|
let mut source = Vec::new();
|
|
std::io::stdin().read_to_end(&mut source)?;
|
|
// Save a fake file into file fetcher cache
|
|
// to allow module access by TS compiler
|
|
file_fetcher.insert_memory_files(File {
|
|
url: main_module.clone(),
|
|
maybe_headers: None,
|
|
source: source.into(),
|
|
});
|
|
|
|
let mut worker = worker_factory
|
|
.create_main_worker(WorkerExecutionMode::Run, main_module.clone())
|
|
.await?;
|
|
let exit_code = worker.run().await?;
|
|
Ok(exit_code)
|
|
}
|
|
|
|
// TODO(bartlomieju): this function is not handling `exit_code` set by the runtime
|
|
// code properly.
|
|
async fn run_with_watch(
|
|
mode: WorkerExecutionMode,
|
|
flags: Arc<Flags>,
|
|
watch_flags: WatchFlagsWithPaths,
|
|
) -> Result<i32, AnyError> {
|
|
util::file_watcher::watch_recv(
|
|
flags,
|
|
util::file_watcher::PrintConfig::new_with_banner(
|
|
if watch_flags.hmr { "HMR" } else { "Watcher" },
|
|
"Process",
|
|
!watch_flags.no_clear_screen,
|
|
),
|
|
WatcherRestartMode::Automatic,
|
|
move |flags, watcher_communicator, changed_paths| {
|
|
watcher_communicator.show_path_changed(changed_paths.clone());
|
|
Ok(async move {
|
|
let factory = CliFactory::from_flags_for_watcher(
|
|
flags,
|
|
watcher_communicator.clone(),
|
|
);
|
|
let cli_options = factory.cli_options()?;
|
|
let main_module = cli_options.resolve_main_module()?;
|
|
|
|
if main_module.scheme() == "npm" {
|
|
set_npm_user_agent();
|
|
}
|
|
|
|
maybe_npm_install(&factory).await?;
|
|
|
|
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
|
|
|
let mut worker = factory
|
|
.create_cli_main_worker_factory()
|
|
.await?
|
|
.create_main_worker(mode, main_module.clone())
|
|
.await?;
|
|
|
|
if watch_flags.hmr {
|
|
worker.run().await?;
|
|
} else {
|
|
worker.run_for_watcher().await?;
|
|
}
|
|
|
|
Ok(())
|
|
})
|
|
},
|
|
)
|
|
.await?;
|
|
|
|
Ok(0)
|
|
}
|
|
|
|
pub async fn eval_command(
|
|
flags: Arc<Flags>,
|
|
eval_flags: EvalFlags,
|
|
) -> Result<i32, AnyError> {
|
|
let factory = CliFactory::from_flags(flags);
|
|
let cli_options = factory.cli_options()?;
|
|
let file_fetcher = factory.file_fetcher()?;
|
|
let main_module = cli_options.resolve_main_module()?;
|
|
|
|
maybe_npm_install(&factory).await?;
|
|
|
|
// Create a dummy source file.
|
|
let source_code = if eval_flags.print {
|
|
format!("console.log({})", eval_flags.code)
|
|
} else {
|
|
eval_flags.code
|
|
};
|
|
|
|
// Save a fake file into file fetcher cache
|
|
// to allow module access by TS compiler.
|
|
file_fetcher.insert_memory_files(File {
|
|
url: main_module.clone(),
|
|
maybe_headers: None,
|
|
source: source_code.into_bytes().into(),
|
|
});
|
|
|
|
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
|
let mut worker = worker_factory
|
|
.create_main_worker(WorkerExecutionMode::Eval, main_module.clone())
|
|
.await?;
|
|
let exit_code = worker.run().await?;
|
|
Ok(exit_code)
|
|
}
|
|
|
|
pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
|
|
let cli_options = factory.cli_options()?;
|
|
// ensure an "npm install" is done if the user has explicitly
|
|
// opted into using a managed node_modules directory
|
|
if cli_options.node_modules_dir()? == Some(NodeModulesDirMode::Auto) {
|
|
if let Some(npm_installer) = factory.npm_installer_if_managed()? {
|
|
let already_done = npm_installer
|
|
.ensure_top_level_package_json_install()
|
|
.await?;
|
|
if !already_done
|
|
&& matches!(
|
|
cli_options.default_npm_caching_strategy(),
|
|
crate::graph_util::NpmCachingStrategy::Eager
|
|
)
|
|
{
|
|
npm_installer.cache_packages(PackageCaching::All).await?;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|