summaryrefslogtreecommitdiff
path: root/cli/npm/tarball.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-11-08 14:17:24 -0500
committerGitHub <noreply@github.com>2022-11-08 14:17:24 -0500
commitcbb3f854332c348bb253e1284f7dcd7287bdf28d (patch)
tree93e2db9439bd745d48118a931bdc8bea61b81af5 /cli/npm/tarball.rs
parent2c72e8d5f45f12948310c1f0e1e2ed4f1d80fb51 (diff)
feat(unstable/npm): support peer dependencies (#16561)
This adds support for peer dependencies in npm packages. 1. If not found higher in the tree (ancestor and ancestor siblings), peer dependencies are resolved like a dependency similar to npm 7. 2. Optional peer dependencies are only resolved if found higher in the tree. 3. This creates "copy packages" or duplicates of a package when a package has different resolution due to peer dependency resolution—see https://pnpm.io/how-peers-are-resolved. Unlike pnpm though, duplicates of packages will have `_1`, `_2`, etc. added to the end of the package version in the directory in order to minimize the chance of hitting the max file path limit on Windows. This is done for both the local "node_modules" directory and also the global npm cache. The files are hard linked in this case to reduce hard drive space. This is a first pass and the code is definitely more inefficient than it could be. Closes #15823
Diffstat (limited to 'cli/npm/tarball.rs')
-rw-r--r--cli/npm/tarball.rs82
1 files changed, 26 insertions, 56 deletions
diff --git a/cli/npm/tarball.rs b/cli/npm/tarball.rs
index 3971e0b07..751e093f5 100644
--- a/cli/npm/tarball.rs
+++ b/cli/npm/tarball.rs
@@ -6,18 +6,17 @@ use std::path::Path;
use std::path::PathBuf;
use deno_core::anyhow::bail;
-use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use flate2::read::GzDecoder;
use tar::Archive;
use tar::EntryType;
-use super::cache::NPM_PACKAGE_SYNC_LOCK_FILENAME;
+use super::cache::with_folder_sync_lock;
use super::registry::NpmPackageVersionDistInfo;
-use super::NpmPackageId;
+use super::semver::NpmVersion;
pub fn verify_and_extract_tarball(
- package: &NpmPackageId,
+ package: (&str, &NpmVersion),
data: &[u8],
dist_info: &NpmPackageVersionDistInfo,
output_folder: &Path,
@@ -27,50 +26,19 @@ pub fn verify_and_extract_tarball(
} else {
// todo(dsherret): check shasum here
bail!(
- "Errored on '{}': npm packages with no integrity are not implemented.",
- package
+ "Errored on '{}@{}': npm packages with no integrity are not implemented.",
+ package.0,
+ package.1,
);
}
- fs::create_dir_all(output_folder).with_context(|| {
- format!("Error creating '{}'.", output_folder.display())
- })?;
-
- // This sync lock file is a way to ensure that partially created
- // npm package directories aren't considered valid. This could maybe
- // be a bit smarter in the future to not bother extracting here
- // if another process has taken the lock in the past X seconds and
- // wait for the other process to finish (it could try to create the
- // file with `create_new(true)` then if it exists, check the metadata
- // then wait until the other process finishes with a timeout), but
- // for now this is good enough.
- let sync_lock_path = output_folder.join(NPM_PACKAGE_SYNC_LOCK_FILENAME);
- match fs::OpenOptions::new()
- .write(true)
- .create(true)
- .open(&sync_lock_path)
- {
- Ok(_) => {
- extract_tarball(data, output_folder)?;
- // extraction succeeded, so only now delete this file
- let _ignore = std::fs::remove_file(&sync_lock_path);
- Ok(())
- }
- Err(err) => {
- bail!(
- concat!(
- "Error creating package sync lock file at '{}'. ",
- "Maybe try manually deleting this folder.\n\n{:#}",
- ),
- output_folder.display(),
- err
- );
- }
- }
+ with_folder_sync_lock(package, output_folder, || {
+ extract_tarball(data, output_folder)
+ })
}
fn verify_tarball_integrity(
- package: &NpmPackageId,
+ package: (&str, &NpmVersion),
data: &[u8],
npm_integrity: &str,
) -> Result<(), AnyError> {
@@ -81,16 +49,18 @@ fn verify_tarball_integrity(
let algo = match hash_kind {
"sha512" => &SHA512,
hash_kind => bail!(
- "Not implemented hash function for {}: {}",
- package,
+ "Not implemented hash function for {}@{}: {}",
+ package.0,
+ package.1,
hash_kind
),
};
(algo, checksum.to_lowercase())
}
None => bail!(
- "Not implemented integrity kind for {}: {}",
- package,
+ "Not implemented integrity kind for {}@{}: {}",
+ package.0,
+ package.1,
npm_integrity
),
};
@@ -101,8 +71,9 @@ fn verify_tarball_integrity(
let tarball_checksum = base64::encode(digest.as_ref()).to_lowercase();
if tarball_checksum != expected_checksum {
bail!(
- "Tarball checksum did not match what was provided by npm registry for {}.\n\nExpected: {}\nActual: {}",
- package,
+ "Tarball checksum did not match what was provided by npm registry for {}@{}.\n\nExpected: {}\nActual: {}",
+ package.0,
+ package.1,
expected_checksum,
tarball_checksum,
)
@@ -162,32 +133,31 @@ mod test {
#[test]
pub fn test_verify_tarball() {
- let package_id = NpmPackageId {
- name: "package".to_string(),
- version: NpmVersion::parse("1.0.0").unwrap(),
- };
+ let package_name = "package".to_string();
+ let package_version = NpmVersion::parse("1.0.0").unwrap();
+ let package = (package_name.as_str(), &package_version);
let actual_checksum =
"z4phnx7vul3xvchq1m2ab9yg5aulvxxcg/spidns6c5h0ne8xyxysp+dgnkhfuwvy7kxvudbeoglodj6+sfapg==";
assert_eq!(
- verify_tarball_integrity(&package_id, &Vec::new(), "test")
+ verify_tarball_integrity(package, &Vec::new(), "test")
.unwrap_err()
.to_string(),
"Not implemented integrity kind for package@1.0.0: test",
);
assert_eq!(
- verify_tarball_integrity(&package_id, &Vec::new(), "sha1-test")
+ verify_tarball_integrity(package, &Vec::new(), "sha1-test")
.unwrap_err()
.to_string(),
"Not implemented hash function for package@1.0.0: sha1",
);
assert_eq!(
- verify_tarball_integrity(&package_id, &Vec::new(), "sha512-test")
+ verify_tarball_integrity(package, &Vec::new(), "sha512-test")
.unwrap_err()
.to_string(),
format!("Tarball checksum did not match what was provided by npm registry for package@1.0.0.\n\nExpected: test\nActual: {}", actual_checksum),
);
assert!(verify_tarball_integrity(
- &package_id,
+ package,
&Vec::new(),
&format!("sha512-{}", actual_checksum)
)