mirror of
https://github.com/denoland/deno.git
synced 2024-12-01 16:51:13 -05:00
fix(npm): respect latest
dist tag for getting current version (#15746)
This commit is contained in:
parent
8de6411b79
commit
4255212d71
6 changed files with 108 additions and 5 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4627,6 +4627,7 @@ dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pemfile 1.0.0",
|
"rustls-pemfile 1.0.0",
|
||||||
|
"semver 1.0.13",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tar",
|
"tar",
|
||||||
|
|
|
@ -31,6 +31,8 @@ use super::semver::NpmVersionReq;
|
||||||
pub struct NpmPackageInfo {
|
pub struct NpmPackageInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub versions: HashMap<String, NpmPackageVersionInfo>,
|
pub versions: HashMap<String, NpmPackageVersionInfo>,
|
||||||
|
#[serde(rename = "dist-tags")]
|
||||||
|
pub dist_tags: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NpmDependencyEntry {
|
pub struct NpmDependencyEntry {
|
||||||
|
@ -39,7 +41,7 @@ pub struct NpmDependencyEntry {
|
||||||
pub version_req: NpmVersionReq,
|
pub version_req: NpmVersionReq,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
|
||||||
pub struct NpmPackageVersionInfo {
|
pub struct NpmPackageVersionInfo {
|
||||||
pub version: String,
|
pub version: String,
|
||||||
pub dist: NpmPackageVersionDistInfo,
|
pub dist: NpmPackageVersionDistInfo,
|
||||||
|
@ -89,7 +91,7 @@ impl NpmPackageVersionInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
|
||||||
pub struct NpmPackageVersionDistInfo {
|
pub struct NpmPackageVersionDistInfo {
|
||||||
/// URL to the tarball.
|
/// URL to the tarball.
|
||||||
pub tarball: String,
|
pub tarball: String,
|
||||||
|
@ -231,7 +233,20 @@ impl NpmRegistryApi {
|
||||||
Err(err) if err.kind() == ErrorKind::NotFound => return Ok(None),
|
Err(err) if err.kind() == ErrorKind::NotFound => return Ok(None),
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
};
|
};
|
||||||
Ok(serde_json::from_str(&file_text)?)
|
match serde_json::from_str(&file_text) {
|
||||||
|
Ok(package_info) => Ok(Some(package_info)),
|
||||||
|
Err(err) => {
|
||||||
|
// This scenario might mean we need to load more data from the
|
||||||
|
// npm registry than before. So, just debug log while in debug
|
||||||
|
// rather than panic.
|
||||||
|
log::debug!(
|
||||||
|
"error deserializing registry.json for '{}'. Reloading. {:?}",
|
||||||
|
name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_package_info_to_file_cache(
|
fn save_package_info_to_file_cache(
|
||||||
|
|
|
@ -19,9 +19,10 @@ use super::semver::NpmVersion;
|
||||||
use super::semver::SpecifierVersionReq;
|
use super::semver::SpecifierVersionReq;
|
||||||
|
|
||||||
/// The version matcher used for npm schemed urls is more strict than
|
/// The version matcher used for npm schemed urls is more strict than
|
||||||
/// the one used by npm packages.
|
/// the one used by npm packages and so we represent either via a trait.
|
||||||
pub trait NpmVersionMatcher {
|
pub trait NpmVersionMatcher {
|
||||||
fn matches(&self, version: &NpmVersion) -> bool;
|
fn matches(&self, version: &NpmVersion) -> bool;
|
||||||
|
fn is_latest(&self) -> bool;
|
||||||
fn version_text(&self) -> String;
|
fn version_text(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +113,10 @@ impl NpmVersionMatcher for NpmPackageReq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_latest(&self) -> bool {
|
||||||
|
self.version_req.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
fn version_text(&self) -> String {
|
fn version_text(&self) -> String {
|
||||||
self
|
self
|
||||||
.version_req
|
.version_req
|
||||||
|
@ -484,6 +489,25 @@ fn get_resolved_package_version_and_info(
|
||||||
parent: Option<&NpmPackageId>,
|
parent: Option<&NpmPackageId>,
|
||||||
) -> Result<VersionAndInfo, AnyError> {
|
) -> Result<VersionAndInfo, AnyError> {
|
||||||
let mut maybe_best_version: Option<VersionAndInfo> = None;
|
let mut maybe_best_version: Option<VersionAndInfo> = None;
|
||||||
|
if version_matcher.is_latest() {
|
||||||
|
if let Some(version) = info.dist_tags.get("latest") {
|
||||||
|
match info.versions.get(version) {
|
||||||
|
Some(info) => {
|
||||||
|
return Ok(VersionAndInfo {
|
||||||
|
version: NpmVersion::parse(version)?,
|
||||||
|
info: info.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
bail!(
|
||||||
|
"Could not find version '{}' referenced in dist-tag 'latest'.",
|
||||||
|
version,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (_, version_info) in info.versions.into_iter() {
|
for (_, version_info) in info.versions.into_iter() {
|
||||||
let version = NpmVersion::parse(&version_info.version)?;
|
let version = NpmVersion::parse(&version_info.version)?;
|
||||||
if version_matcher.matches(&version) {
|
if version_matcher.matches(&version) {
|
||||||
|
@ -651,4 +675,53 @@ mod tests {
|
||||||
assert_eq!(name_without_path("@foo/bar/baz"), "@foo/bar");
|
assert_eq!(name_without_path("@foo/bar/baz"), "@foo/bar");
|
||||||
assert_eq!(name_without_path("@hello"), "@hello");
|
assert_eq!(name_without_path("@hello"), "@hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_resolved_package_version_and_info() {
|
||||||
|
// dist tag where version doesn't exist
|
||||||
|
let package_ref = NpmPackageReference::from_str("npm:test").unwrap();
|
||||||
|
let result = get_resolved_package_version_and_info(
|
||||||
|
"test",
|
||||||
|
&package_ref.req,
|
||||||
|
NpmPackageInfo {
|
||||||
|
name: "test".to_string(),
|
||||||
|
versions: HashMap::new(),
|
||||||
|
dist_tags: HashMap::from([(
|
||||||
|
"latest".to_string(),
|
||||||
|
"1.0.0-alpha".to_string(),
|
||||||
|
)]),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
result.err().unwrap().to_string(),
|
||||||
|
"Could not find version '1.0.0-alpha' referenced in dist-tag 'latest'."
|
||||||
|
);
|
||||||
|
|
||||||
|
// dist tag where version is a pre-release
|
||||||
|
let package_ref = NpmPackageReference::from_str("npm:test").unwrap();
|
||||||
|
let result = get_resolved_package_version_and_info(
|
||||||
|
"test",
|
||||||
|
&package_ref.req,
|
||||||
|
NpmPackageInfo {
|
||||||
|
name: "test".to_string(),
|
||||||
|
versions: HashMap::from([
|
||||||
|
("0.1.0".to_string(), NpmPackageVersionInfo::default()),
|
||||||
|
(
|
||||||
|
"1.0.0-alpha".to_string(),
|
||||||
|
NpmPackageVersionInfo {
|
||||||
|
version: "0.1.0-alpha".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
dist_tags: HashMap::from([(
|
||||||
|
"latest".to_string(),
|
||||||
|
"1.0.0-alpha".to_string(),
|
||||||
|
)]),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
assert_eq!(result.unwrap().version.to_string(), "1.0.0-alpha");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,6 +174,10 @@ impl NpmVersionMatcher for NpmVersionReq {
|
||||||
self.satisfies(version)
|
self.satisfies(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_latest(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn version_text(&self) -> String {
|
fn version_text(&self) -> String {
|
||||||
self.raw_text.clone()
|
self.raw_text.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ regex = "1.6.0"
|
||||||
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks"] }
|
reqwest = { version = "0.11.11", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli", "socks"] }
|
||||||
ring = "0.16.20"
|
ring = "0.16.20"
|
||||||
rustls-pemfile = "1.0.0"
|
rustls-pemfile = "1.0.0"
|
||||||
|
semver = "1.0.13"
|
||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.79"
|
||||||
tar = "0.4.38"
|
tar = "0.4.38"
|
||||||
|
|
|
@ -71,6 +71,7 @@ fn get_npm_package(package_name: &str) -> Result<Option<CustomNpmPackage>> {
|
||||||
// read all the package's versions
|
// read all the package's versions
|
||||||
let mut tarballs = HashMap::new();
|
let mut tarballs = HashMap::new();
|
||||||
let mut versions = serde_json::Map::new();
|
let mut versions = serde_json::Map::new();
|
||||||
|
let mut latest_version = semver::Version::parse("0.0.0").unwrap();
|
||||||
for entry in fs::read_dir(&package_folder)? {
|
for entry in fs::read_dir(&package_folder)? {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let file_type = entry.file_type()?;
|
let file_type = entry.file_type()?;
|
||||||
|
@ -134,13 +135,21 @@ fn get_npm_package(package_name: &str) -> Result<Option<CustomNpmPackage>> {
|
||||||
let mut version_info: serde_json::Map<String, serde_json::Value> =
|
let mut version_info: serde_json::Map<String, serde_json::Value> =
|
||||||
serde_json::from_str(&package_json_text)?;
|
serde_json::from_str(&package_json_text)?;
|
||||||
version_info.insert("dist".to_string(), dist.into());
|
version_info.insert("dist".to_string(), dist.into());
|
||||||
versions.insert(version, version_info.into());
|
versions.insert(version.clone(), version_info.into());
|
||||||
|
let version = semver::Version::parse(&version)?;
|
||||||
|
if version.cmp(&latest_version).is_gt() {
|
||||||
|
latest_version = version;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut dist_tags = serde_json::Map::new();
|
||||||
|
dist_tags.insert("latest".to_string(), latest_version.to_string().into());
|
||||||
|
|
||||||
// create the registry file for this package
|
// create the registry file for this package
|
||||||
let mut registry_file = serde_json::Map::new();
|
let mut registry_file = serde_json::Map::new();
|
||||||
registry_file.insert("name".to_string(), package_name.to_string().into());
|
registry_file.insert("name".to_string(), package_name.to_string().into());
|
||||||
registry_file.insert("versions".to_string(), versions.into());
|
registry_file.insert("versions".to_string(), versions.into());
|
||||||
|
registry_file.insert("dist-tags".to_string(), dist_tags.into());
|
||||||
Ok(Some(CustomNpmPackage {
|
Ok(Some(CustomNpmPackage {
|
||||||
registry_file: serde_json::to_string(®istry_file).unwrap(),
|
registry_file: serde_json::to_string(®istry_file).unwrap(),
|
||||||
tarballs,
|
tarballs,
|
||||||
|
|
Loading…
Reference in a new issue