0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00

fix(npmrc): merge .npmrc in user's homedir and project (#27119)

This commit is contained in:
jia wei 2025-01-28 23:25:50 +08:00 committed by Bartek Iwańczuk
parent d58c70fbd1
commit 3097d99d76
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
7 changed files with 124 additions and 34 deletions

View file

@ -1,6 +1,7 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
@ -103,7 +104,7 @@ fn discover_npmrc<TSys: EnvVar + EnvHomeDir + FsRead>(
sys: &impl EnvVar,
source: &str,
path: &Path,
) -> Result<ResolvedNpmRc, NpmRcDiscoverError> {
) -> Result<NpmRc, NpmRcDiscoverError> {
let npmrc = NpmRc::parse(source, &|name| sys.env_var(name).ok()).map_err(
|source| {
NpmRcParseError {
@ -113,52 +114,50 @@ fn discover_npmrc<TSys: EnvVar + EnvHomeDir + FsRead>(
}
},
)?;
let resolved =
npmrc
.as_resolved(&npm_registry_url(sys))
.map_err(|source| NpmRcOptionsResolveError {
path: path.to_path_buf(),
source,
})?;
log::debug!(".npmrc found at: '{}'", path.display());
Ok(resolved)
Ok(npmrc)
}
// 1. Try `.npmrc` next to `package.json`
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(sys, package_json_dir)? {
return try_to_parse_npmrc(sys, &source, &path)
.map(|r| (r, Some(path)));
fn merge_npm_rc(project_rc: NpmRc, home_rc: NpmRc) -> NpmRc {
fn merge_maps<TValue>(
mut project: HashMap<String, TValue>,
home: HashMap<String, TValue>,
) -> HashMap<String, TValue> {
for (key, value) in home {
project.entry(key).or_insert(value);
}
project
}
NpmRc {
registry: project_rc.registry.or(home_rc.registry),
scope_registries: merge_maps(
project_rc.scope_registries,
home_rc.scope_registries,
),
registry_configs: merge_maps(
project_rc.registry_configs,
home_rc.registry_configs,
),
}
}
// 2. Try `.npmrc` next to `deno.json(c)`
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(sys, deno_json_dir)? {
return try_to_parse_npmrc(sys, &source, &path)
.map(|r| (r, Some(path)));
}
}
}
let mut home_npmrc = None;
let mut project_npmrc = None;
// TODO(bartlomieju): update to read both files - one in the project root and one and
// home dir and then merge them.
// 3. Try `.npmrc` in the user's home directory
// 1. Try `.npmrc` in the user's home directory
if let Some(home_dir) = sys.env_home_dir() {
match try_to_read_npmrc(sys, &home_dir) {
Ok(Some((source, path))) => {
return try_to_parse_npmrc(sys, &source, &path)
.map(|r| (r, Some(path)));
let npmrc = try_to_parse_npmrc(sys, &source, &path)?;
home_npmrc = Some((path, npmrc));
}
Ok(None) => {}
Err(err) if err.source.kind() == std::io::ErrorKind::PermissionDenied => {
log::debug!(
"Skipping .npmrc in home directory due to permission denied error. {:#}",
err
);
"Skipping .npmrc in home directory due to permission denied error. {:#}",
err
);
}
Err(err) => {
return Err(err.into());
@ -166,8 +165,59 @@ fn discover_npmrc<TSys: EnvVar + EnvHomeDir + FsRead>(
}
}
log::debug!("No .npmrc file found");
Ok((create_default_npmrc(sys), None))
// 2. Try `.npmrc` next to `package.json`
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(sys, package_json_dir)? {
let npmrc = try_to_parse_npmrc(sys, &source, &path)?;
project_npmrc = Some((path, npmrc));
}
}
}
// 3. Try `.npmrc` next to `deno.json(c)` when not found `package.json`
if project_npmrc.is_none() {
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(sys, deno_json_dir)? {
let npmrc = try_to_parse_npmrc(sys, &source, &path)?;
project_npmrc = Some((path, npmrc));
}
}
}
}
let resolve_npmrc = |path: PathBuf, npm_rc: NpmRc| {
Ok((
npm_rc
.as_resolved(&npm_registry_url(sys))
.map_err(|source| NpmRcOptionsResolveError {
path: path.to_path_buf(),
source,
})?,
Some(path),
))
};
match (home_npmrc, project_npmrc) {
(None, None) => {
log::debug!("No .npmrc file found");
Ok((create_default_npmrc(sys), None))
}
(None, Some((npmrc_path, project_rc))) => {
log::debug!("Only project .npmrc file found");
resolve_npmrc(npmrc_path, project_rc)
}
(Some((npmrc_path, home_rc)), None) => {
log::debug!("Only home .npmrc file found");
resolve_npmrc(npmrc_path, home_rc)
}
(Some((_, home_rc)), Some((npmrc_path, project_rc))) => {
log::debug!("Both home and project .npmrc files found");
let merged_npmrc = merge_npm_rc(project_rc, home_rc);
resolve_npmrc(npmrc_path, merged_npmrc)
}
}
}
pub fn create_default_npmrc(sys: &impl EnvVar) -> ResolvedNpmRc {

View file

@ -0,0 +1,4 @@
@denotest:registry=http://localhost:4261/
//localhost:4261/:_authToken=private-reg-token
@denotest2:registry=http://localhost:4262/
//localhost:4262/:_authToken=private-reg-token2

View file

@ -0,0 +1,10 @@
{
"tempDir": true,
"envs": {
"HOME": "$PWD/../",
"USERPROFILE": "$PWD\\..\\"
},
"cwd": "subdir",
"args": "install",
"output": "install.out"
}

View file

@ -0,0 +1,8 @@
[UNORDERED_START]
Download http://localhost:4262/@denotest2%2fbasic
Download http://localhost:4261/@denotest%2fbasic
Download http://localhost:4262/@denotest2/basic/1.0.0.tgz
Download http://localhost:4261/@denotest/basic/1.0.0.tgz
Initialize @denotest2/basic@1.0.0
Initialize @denotest/basic@1.0.0
[UNORDERED_END]

View file

@ -0,0 +1,2 @@
@denotest:registry=http://localhost:4261/
@denotest2:registry=http://localhost:4262/

View file

@ -0,0 +1,8 @@
import { getValue, setValue } from "@denotest/basic";
import * as test from "@denotest2/basic";
console.log(getValue());
setValue(42);
console.log(getValue());
console.log(test.getValue());

View file

@ -0,0 +1,8 @@
{
"name": "npmrc_homedir_package_both",
"version": "0.0.1",
"dependencies": {
"@denotest/basic": "1.0.0",
"@denotest2/basic": "1.0.0"
}
}