summaryrefslogtreecommitdiff
path: root/cli/args/mod.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2024-05-23 22:26:23 +0100
committerGitHub <noreply@github.com>2024-05-23 23:26:23 +0200
commit959739f609dddacde3bbe9ecede2f409214fb34c (patch)
tree04d1776efbd3561205829f78288d26b6e14c3429 /cli/args/mod.rs
parent5de30c53239ac74843725d981afc0bb8c45bdf16 (diff)
FUTURE: initial support for .npmrc file (#23560)
This commit adds initial support for ".npmrc" files. Currently we only discover ".npmrc" files next to "package.json" files and discovering these files in user home dir is left for a follow up. This pass supports "_authToken" and "_auth" configuration for providing authentication. LSP support has been left for a follow up PR. Towards https://github.com/denoland/deno/issues/16105
Diffstat (limited to 'cli/args/mod.rs')
-rw-r--r--cli/args/mod.rs98
1 files changed, 98 insertions, 0 deletions
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 03a6357aa..bc384a132 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -13,6 +13,8 @@ use ::import_map::ImportMap;
use deno_ast::SourceMapOption;
use deno_core::resolve_url_or_path;
use deno_graph::GraphKind;
+use deno_npm::npm_rc::NpmRc;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_tls::RootCertStoreProvider;
@@ -546,6 +548,83 @@ fn discover_package_json(
Ok(None)
}
+/// Discover `.npmrc` file - currently we only support it next to `package.json`
+/// or next to `deno.json`.
+///
+/// In the future we will need to support it in user directory or global directory
+/// as per https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#files.
+fn discover_npmrc(
+ maybe_package_json_path: Option<PathBuf>,
+ maybe_deno_json_path: Option<PathBuf>,
+) -> Result<Arc<ResolvedNpmRc>, AnyError> {
+ if !*DENO_FUTURE {
+ return Ok(create_default_npmrc());
+ }
+
+ const NPMRC_NAME: &str = ".npmrc";
+
+ fn get_env_var(var_name: &str) -> Option<String> {
+ std::env::var(var_name).ok()
+ }
+
+ fn try_to_read_npmrc(
+ dir: &Path,
+ ) -> Result<Option<(String, PathBuf)>, AnyError> {
+ let path = dir.join(NPMRC_NAME);
+ let maybe_source = match std::fs::read_to_string(&path) {
+ Ok(source) => Some(source),
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
+ Err(err) => {
+ bail!("Error loading .npmrc at {}. {:#}", path.display(), err)
+ }
+ };
+
+ Ok(maybe_source.map(|source| (source, path)))
+ }
+
+ fn try_to_parse_npmrc(
+ source: String,
+ path: &Path,
+ ) -> Result<Arc<ResolvedNpmRc>, AnyError> {
+ let npmrc = NpmRc::parse(&source, &get_env_var).with_context(|| {
+ format!("Failed to parse .npmrc at {}", path.display())
+ })?;
+ let resolved = npmrc
+ .as_resolved(npm_registry_url())
+ .context("Failed to resolve .npmrc options")?;
+ Ok(Arc::new(resolved))
+ }
+
+ if let Some(package_json_path) = maybe_package_json_path {
+ if let Some(package_json_dir) = package_json_path.parent() {
+ if let Some((source, path)) = try_to_read_npmrc(package_json_dir)? {
+ return try_to_parse_npmrc(source, &path);
+ }
+ }
+ }
+
+ if let Some(deno_json_path) = maybe_deno_json_path {
+ if let Some(deno_json_dir) = deno_json_path.parent() {
+ if let Some((source, path)) = try_to_read_npmrc(deno_json_dir)? {
+ return try_to_parse_npmrc(source, &path);
+ }
+ }
+ }
+
+ log::debug!("No .npmrc file found");
+ Ok(create_default_npmrc())
+}
+
+pub fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
+ Arc::new(ResolvedNpmRc {
+ default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
+ registry_url: npm_registry_url().clone(),
+ config: Default::default(),
+ },
+ scopes: Default::default(),
+ })
+}
+
struct CliRootCertStoreProvider {
cell: OnceCell<RootCertStore>,
maybe_root_path: Option<PathBuf>,
@@ -722,6 +801,7 @@ pub struct CliOptions {
maybe_vendor_folder: Option<PathBuf>,
maybe_config_file: Option<ConfigFile>,
maybe_package_json: Option<PackageJson>,
+ npmrc: Arc<ResolvedNpmRc>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
overrides: CliOptionOverrides,
maybe_workspace_config: Option<WorkspaceConfig>,
@@ -736,6 +816,7 @@ impl CliOptions {
maybe_config_file: Option<ConfigFile>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
maybe_package_json: Option<PackageJson>,
+ npmrc: Arc<ResolvedNpmRc>,
force_global_cache: bool,
) -> Result<Self, AnyError> {
if let Some(insecure_allowlist) =
@@ -798,6 +879,7 @@ impl CliOptions {
maybe_config_file,
maybe_lockfile,
maybe_package_json,
+ npmrc,
maybe_node_modules_folder,
maybe_vendor_folder,
overrides: Default::default(),
@@ -851,6 +933,16 @@ impl CliOptions {
} else {
maybe_package_json = discover_package_json(&flags, None, &initial_cwd)?;
}
+ let npmrc = discover_npmrc(
+ maybe_package_json.as_ref().map(|p| p.path.clone()),
+ maybe_config_file.as_ref().and_then(|cf| {
+ if cf.specifier.scheme() == "file" {
+ Some(cf.specifier.to_file_path().unwrap())
+ } else {
+ None
+ }
+ }),
+ )?;
let maybe_lock_file = lockfile::discover(
&flags,
@@ -863,6 +955,7 @@ impl CliOptions {
maybe_config_file,
maybe_lock_file.map(|l| Arc::new(Mutex::new(l))),
maybe_package_json,
+ npmrc,
false,
)
}
@@ -1172,6 +1265,7 @@ impl CliOptions {
maybe_vendor_folder: self.maybe_vendor_folder.clone(),
maybe_config_file: self.maybe_config_file.clone(),
maybe_package_json: self.maybe_package_json.clone(),
+ npmrc: self.npmrc.clone(),
maybe_lockfile: self.maybe_lockfile.clone(),
maybe_workspace_config: self.maybe_workspace_config.clone(),
overrides: self.overrides.clone(),
@@ -1303,6 +1397,10 @@ impl CliOptions {
&self.maybe_package_json
}
+ pub fn npmrc(&self) -> &Arc<ResolvedNpmRc> {
+ &self.npmrc
+ }
+
pub fn maybe_package_json_deps(&self) -> Option<PackageJsonDeps> {
if matches!(
self.flags.subcommand,