1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-05 05:49:20 -05:00

fix(vendor): ignore import map in output directory instead of erroring (#14998)

This commit is contained in:
David Sherret 2022-06-29 20:41:48 -04:00 committed by GitHub
parent d5ef14eca6
commit e46584a75a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 70 deletions

View file

@ -44,6 +44,14 @@ use crate::file_fetcher::CacheSetting;
use crate::lockfile::Lockfile; use crate::lockfile::Lockfile;
use crate::version; use crate::version;
/// Overrides for the options below that when set will
/// use these values over the values derived from the
/// CLI flags or config file.
#[derive(Default)]
struct CliOptionOverrides {
import_map_specifier: Option<Option<ModuleSpecifier>>,
}
/// Holds the common options used by many sub commands /// Holds the common options used by many sub commands
/// and provides some helper function for creating common objects. /// and provides some helper function for creating common objects.
pub struct CliOptions { pub struct CliOptions {
@ -51,6 +59,7 @@ pub struct CliOptions {
// application need not concern itself with, so keep these private // application need not concern itself with, so keep these private
flags: Flags, flags: Flags,
maybe_config_file: Option<ConfigFile>, maybe_config_file: Option<ConfigFile>,
overrides: CliOptionOverrides,
} }
impl CliOptions { impl CliOptions {
@ -72,6 +81,7 @@ impl CliOptions {
Ok(Self { Ok(Self {
maybe_config_file, maybe_config_file,
flags, flags,
overrides: Default::default(),
}) })
} }
@ -113,13 +123,21 @@ impl CliOptions {
/// Based on an optional command line import map path and an optional /// Based on an optional command line import map path and an optional
/// configuration file, return a resolved module specifier to an import map. /// configuration file, return a resolved module specifier to an import map.
pub fn resolve_import_map_path( pub fn resolve_import_map_specifier(
&self, &self,
) -> Result<Option<ModuleSpecifier>, AnyError> { ) -> Result<Option<ModuleSpecifier>, AnyError> {
resolve_import_map_specifier( match self.overrides.import_map_specifier.clone() {
Some(path) => Ok(path),
None => resolve_import_map_specifier(
self.flags.import_map_path.as_deref(), self.flags.import_map_path.as_deref(),
self.maybe_config_file.as_ref(), self.maybe_config_file.as_ref(),
) ),
}
}
/// Overrides the import map specifier to use.
pub fn set_import_map_specifier(&mut self, path: Option<ModuleSpecifier>) {
self.overrides.import_map_specifier = Some(path);
} }
pub fn resolve_root_cert_store(&self) -> Result<RootCertStore, AnyError> { pub fn resolve_root_cert_store(&self) -> Result<RootCertStore, AnyError> {

View file

@ -769,7 +769,7 @@ async fn bundle_command(
if let Ok(Some(import_map_path)) = ps if let Ok(Some(import_map_path)) = ps
.options .options
.resolve_import_map_path() .resolve_import_map_specifier()
.map(|ms| ms.and_then(|ref s| s.to_file_path().ok())) .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
{ {
paths_to_watch.push(import_map_path); paths_to_watch.push(import_map_path);
@ -1237,8 +1237,7 @@ async fn vendor_command(
flags: Flags, flags: Flags,
vendor_flags: VendorFlags, vendor_flags: VendorFlags,
) -> Result<i32, AnyError> { ) -> Result<i32, AnyError> {
let ps = ProcState::build(flags).await?; tools::vendor::vendor(flags, vendor_flags).await?;
tools::vendor::vendor(ps, vendor_flags).await?;
Ok(0) Ok(0)
} }

View file

@ -117,7 +117,7 @@ impl ProcState {
if let Ok(Some(import_map_path)) = ps if let Ok(Some(import_map_path)) = ps
.options .options
.resolve_import_map_path() .resolve_import_map_specifier()
.map(|ms| ms.and_then(|ref s| s.to_file_path().ok())) .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
{ {
files_to_watch_sender.send(vec![import_map_path]).unwrap(); files_to_watch_sender.send(vec![import_map_path]).unwrap();
@ -153,7 +153,8 @@ impl ProcState {
let lockfile = cli_options let lockfile = cli_options
.resolve_lock_file()? .resolve_lock_file()?
.map(|f| Arc::new(Mutex::new(f))); .map(|f| Arc::new(Mutex::new(f)));
let maybe_import_map_specifier = cli_options.resolve_import_map_path()?; let maybe_import_map_specifier =
cli_options.resolve_import_map_specifier()?;
let maybe_import_map = let maybe_import_map =
if let Some(import_map_specifier) = maybe_import_map_specifier { if let Some(import_map_specifier) = maybe_import_map_specifier {

View file

@ -72,43 +72,6 @@ fn output_dir_exists() {
assert!(status.success()); assert!(status.success());
} }
#[test]
fn import_map_output_dir() {
let t = TempDir::new();
t.write("mod.ts", "");
t.create_dir_all("vendor");
t.write(
"vendor/import_map.json",
"{ \"imports\": { \"https://localhost/\": \"./localhost/\" }}",
);
let deno = util::deno_cmd()
.current_dir(t.path())
.env("NO_COLOR", "1")
.arg("vendor")
.arg("--force")
.arg("--import-map")
.arg("vendor/import_map.json")
.arg("mod.ts")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let output = deno.wait_with_output().unwrap();
assert_eq!(
String::from_utf8_lossy(&output.stderr).trim(),
format!(
concat!(
"error: Specifying an import map file ({}) in the deno vendor ",
"output directory is not supported. Please specify no import ",
"map or one located outside this directory.",
),
PathBuf::from("vendor").join("import_map.json").display(),
),
);
assert!(!output.status.success());
}
#[test] #[test]
fn standard_test() { fn standard_test() {
let _server = http_server(); let _server = http_server();
@ -185,6 +148,57 @@ fn standard_test() {
assert!(output.status.success()); assert!(output.status.success());
} }
#[test]
fn import_map_output_dir() {
let _server = http_server();
let t = TempDir::new();
t.write("mod.ts", "");
t.create_dir_all("vendor");
t.write(
"vendor/import_map.json",
// will be ignored
"{ \"imports\": { \"https://localhost:4545/\": \"./localhost/\" }}",
);
t.write(
"deno.json",
"{ \"import_map\": \"./vendor/import_map.json\" }",
);
t.write(
"my_app.ts",
"import {Logger} from 'http://localhost:4545/vendor/logger.ts'; new Logger().log('outputted');",
);
let deno = util::deno_cmd()
.current_dir(t.path())
.env("NO_COLOR", "1")
.arg("vendor")
.arg("--force")
.arg("--import-map")
.arg("vendor/import_map.json")
.arg("my_app.ts")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let output = deno.wait_with_output().unwrap();
assert_eq!(
String::from_utf8_lossy(&output.stderr).trim(),
format!(
concat!(
"Ignoring import map. Specifying an import map file ({}) in the deno ",
"vendor output directory is not supported. If you wish to use an ",
"import map while vendoring, please specify one located outside this ",
"directory.\n",
"Download http://localhost:4545/vendor/logger.ts\n",
"{}",
),
PathBuf::from("vendor").join("import_map.json").display(),
success_text_updated_deno_json("1 module", "vendor/"),
)
);
assert!(output.status.success());
}
#[test] #[test]
fn remote_module_test() { fn remote_module_test() {
let _server = http_server(); let _server = http_server();
@ -487,16 +501,8 @@ fn update_existing_config_test() {
assert_eq!( assert_eq!(
String::from_utf8_lossy(&output.stderr).trim(), String::from_utf8_lossy(&output.stderr).trim(),
format!( format!(
concat!( "Download http://localhost:4545/vendor/logger.ts\n{}",
"Download http://localhost:4545/vendor/logger.ts\n", success_text_updated_deno_json("1 module", "vendor2",)
"Vendored 1 module into vendor2 directory.\n\n",
"Updated your local Deno configuration file with a reference to the ",
"new vendored import map at {}. Invoking Deno subcommands will ",
"now automatically resolve using the vendored modules. You may override ",
"this by providing the `--import-map <other-import-map>` flag or by ",
"manually editing your Deno configuration file."
),
PathBuf::from("vendor2").join("import_map.json").display(),
) )
); );
assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), ""); assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "");
@ -541,3 +547,27 @@ fn success_text(module_count: &str, dir: &str, has_import_map: bool) -> String {
} }
text text
} }
fn success_text_updated_deno_json(module_count: &str, dir: &str) -> String {
format!(
concat!(
"Vendored {} into {} directory.\n\n",
"Updated your local Deno configuration file with a reference to the ",
"new vendored import map at {}import_map.json. Invoking Deno subcommands will ",
"now automatically resolve using the vendored modules. You may override ",
"this by providing the `--import-map <other-import-map>` flag or by ",
"manually editing your Deno configuration file.",
),
module_count,
dir,
if dir != "vendor/" {
format!(
"{}{}",
dir.trim_end_matches('/'),
if cfg!(windows) { '\\' } else { '/' }
)
} else {
dir.to_string()
}
)
}

View file

@ -2,6 +2,7 @@
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
@ -11,6 +12,8 @@ use deno_core::resolve_url_or_path;
use deno_runtime::permissions::Permissions; use deno_runtime::permissions::Permissions;
use log::warn; use log::warn;
use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::FmtOptionsConfig; use crate::args::FmtOptionsConfig;
use crate::args::VendorFlags; use crate::args::VendorFlags;
use crate::fs_util; use crate::fs_util;
@ -30,14 +33,20 @@ mod specifiers;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
pub async fn vendor(ps: ProcState, flags: VendorFlags) -> Result<(), AnyError> { pub async fn vendor(
let raw_output_dir = match &flags.output_path { flags: Flags,
vendor_flags: VendorFlags,
) -> Result<(), AnyError> {
let mut cli_options = CliOptions::from_flags(flags)?;
let raw_output_dir = match &vendor_flags.output_path {
Some(output_path) => output_path.to_owned(), Some(output_path) => output_path.to_owned(),
None => PathBuf::from("vendor/"), None => PathBuf::from("vendor/"),
}; };
let output_dir = fs_util::resolve_from_cwd(&raw_output_dir)?; let output_dir = fs_util::resolve_from_cwd(&raw_output_dir)?;
validate_output_dir(&output_dir, &flags, &ps)?; validate_output_dir(&output_dir, &vendor_flags)?;
let graph = create_graph(&ps, &flags).await?; validate_options(&mut cli_options, &output_dir)?;
let ps = ProcState::from_options(Arc::new(cli_options)).await?;
let graph = create_graph(&ps, &vendor_flags).await?;
let vendored_count = build::build( let vendored_count = build::build(
graph, graph,
&output_dir, &output_dir,
@ -86,7 +95,6 @@ pub async fn vendor(ps: ProcState, flags: VendorFlags) -> Result<(), AnyError> {
fn validate_output_dir( fn validate_output_dir(
output_dir: &Path, output_dir: &Path,
flags: &VendorFlags, flags: &VendorFlags,
ps: &ProcState,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
if !flags.force && !is_dir_empty(output_dir)? { if !flags.force && !is_dir_empty(output_dir)? {
bail!(concat!( bail!(concat!(
@ -94,12 +102,17 @@ fn validate_output_dir(
"--force to ignore this error and potentially overwrite its contents.", "--force to ignore this error and potentially overwrite its contents.",
)); ));
} }
Ok(())
}
fn validate_options(
options: &mut CliOptions,
output_dir: &Path,
) -> Result<(), AnyError> {
// check the import map // check the import map
if let Some(import_map_path) = ps if let Some(import_map_path) = options
.maybe_import_map .resolve_import_map_specifier()?
.as_ref() .and_then(|p| specifier_to_file_path(&p).ok())
.and_then(|m| specifier_to_file_path(m.base_url()).ok())
.and_then(|p| fs_util::canonicalize_path(&p).ok()) .and_then(|p| fs_util::canonicalize_path(&p).ok())
{ {
// make the output directory in order to canonicalize it for the check below // make the output directory in order to canonicalize it for the check below
@ -114,11 +127,12 @@ fn validate_output_dir(
let cwd = fs_util::canonicalize_path(&std::env::current_dir()?)?; let cwd = fs_util::canonicalize_path(&std::env::current_dir()?)?;
// We don't allow using the output directory to help generate the // We don't allow using the output directory to help generate the
// new state because this may lead to cryptic error messages. // new state because this may lead to cryptic error messages.
bail!( log::warn!(
concat!( concat!(
"Specifying an import map file ({}) in the deno vendor output ", "Ignoring import map. Specifying an import map file ({}) in the ",
"directory is not supported. Please specify no import map or one ", "deno vendor output directory is not supported. If you wish to use ",
"located outside this directory." "an import map while vendoring, please specify one located outside ",
"this directory."
), ),
import_map_path import_map_path
.strip_prefix(&cwd) .strip_prefix(&cwd)
@ -126,6 +140,9 @@ fn validate_output_dir(
.display() .display()
.to_string(), .to_string(),
); );
// don't use an import map in the config
options.set_import_map_specifier(None);
} }
} }