Skip to content

Commit

Permalink
feat: refactoring satifisfyability
Browse files Browse the repository at this point in the history
  • Loading branch information
tdejager committed Mar 15, 2024
1 parent ae42579 commit b165d67
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 32 deletions.
1 change: 0 additions & 1 deletion src/lock_file/package_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ impl PypiPackageIdentifier {
}

pub fn satisfies(&self, requirement: &Requirement) -> bool {
dbg!(&requirement);
// Verify the name of the package
if self.name.as_normalized() != &requirement.name {
return false;
Expand Down
35 changes: 32 additions & 3 deletions src/lock_file/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use crate::{
Project,
};

use distribution_types::FileLocation;
use distribution_types::{
BuiltDist, DirectUrlSourceDist, Dist, IndexLocations, Name, PrioritizedDist, Resolution,
SourceDist,
};
use distribution_types::{DirectUrl, FileLocation};
use futures::FutureExt;
use indexmap::IndexMap;
use indicatif::ProgressBar;
Expand Down Expand Up @@ -425,8 +425,36 @@ pub async fn resolve_pypi(

(url, hash)
}
BuiltDist::DirectUrl(dist) => (dist.url.to_url(), None),
BuiltDist::Path(dist) => (dist.url.to_url(), None),
BuiltDist::DirectUrl(dist) => {
// Create the url for the lock file
// if it is a git vcs use the revision hash and
// append this to our given url
let mut url = dist
.url
.given()
.map(|url| Url::parse(url).expect("could not parse given url to path"))
// When using a direct url reference like https://foo/bla.whl we do not have a given
.unwrap_or_else(|| dist.url.to_url());
match DirectUrl::try_from(&dist.url.to_url()) {

Check failure on line 438 in src/lock_file/resolve.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
Ok(DirectUrl::Git(git_url)) => {
if let Some(sha) = git_url.url.precise() {
url.set_fragment(Some(&sha.to_string()))
}
}
_ => {}
};

(url, None)
}
BuiltDist::Path(dist) => (
dist.url
.given()
.map(|url| {
Url::from_file_path(url).expect("could not parse given url to path")
})
.unwrap_or_else(|| dist.url.to_url()),
None,
),
};

let metadata = context
Expand All @@ -444,6 +472,7 @@ pub async fn resolve_pypi(
}
}
Dist::Source(source) => {
tracing::warn!("{source:?}");
let hash = source
.file()
.and_then(|file| parse_hashes_from_hex(&file.hashes.sha256, &file.hashes.md5));
Expand Down
31 changes: 29 additions & 2 deletions src/lock_file/satisfiability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rattler_conda_types::ParseStrictness::Lenient;
use rattler_conda_types::{
GenericVirtualPackage, MatchSpec, ParseMatchSpecError, Platform, RepoDataRecord,
};
use rattler_lock::{ConversionError, Package};
use rattler_lock::{ConversionError, Package, PypiPackageData};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
Expand Down Expand Up @@ -147,6 +147,33 @@ enum Dependency {
PyPi(Requirement, Cow<'static, str>),
}

pub fn pypi_satifisfies(locked_data: &PypiPackageData, spec: &Requirement) -> bool {
// Check if the name matches
if spec.name != locked_data.name {
return false;
}

// Check if the version of the requirement matches
match &spec.version_or_url {
None => true,
Some(pep508_rs::VersionOrUrl::Url(spec_url)) => {
// Compare the given url with the locked url
// by removing the fragment from the locked url
// which should essentially remove the `#sha` part
let spec_given = spec_url
.given()
.map(|given| given.to_owned())
.unwrap_or_else(|| spec_url.to_url().to_string());
let mut locked_given = locked_data.url.clone();
locked_given.set_fragment(None);
spec_given == locked_given.as_str()
}
Some(pep508_rs::VersionOrUrl::VersionSpecifier(spec)) => {
spec.contains(&locked_data.version)
}
}
}

pub fn verify_package_platform_satisfiability(
environment: &Environment<'_>,
locked_conda_packages: &RepoDataRecordsByName,
Expand Down Expand Up @@ -299,7 +326,7 @@ pub fn verify_package_platform_satisfiability(
}
} else if let Some(idx) = locked_pypi_environment.index_by_name(&requirement.name) {
let record = &locked_pypi_environment.records[idx];
if record.0.satisfies(&requirement) {
if pypi_satifisfies(&record.0, &requirement) {
FoundPackage::PyPi(idx, requirement.extras)
} else {
// The record does not match the spec, the lock-file is inconsistent.
Expand Down
101 changes: 75 additions & 26 deletions src/project/manifest/python.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use pep440_rs::VersionSpecifiers;
use pep508_rs::VerbatimUrl;
use serde::{de, de::Error, Deserialize, Deserializer, Serialize};
use std::fmt::Write;

Check failure on line 4 in src/project/manifest/python.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

unused import: `std::fmt::Write`
use std::path::PathBuf;
use std::process::ExitStatus;
use std::{fmt, fmt::Formatter, str::FromStr};
use thiserror::Error;
use toml_edit::Item;
Expand Down Expand Up @@ -392,6 +392,64 @@ fn get_git_branch_hash(
}
}

fn create_given_url(
url: &Url,
branch: Option<&str>,
tag: Option<&str>,
rev: Option<&str>,
subdir: Option<&str>,
) -> String {
// Create the given
let mut given = format!("git+{url}");
if let Some(branch) = branch {
given = format!("{given}?branch={branch}");
} else if let Some(tag) = tag {
given = format!("{given}?tag={tag}");
} else if let Some(rev) = rev {
given = format!("{given}?rev={rev}");
}
if let Some(subdir) = subdir {
given = format!("{given}&subdirectory={subdir}");
}
given
}

fn create_uv_url(
url: &Url,
branch: Option<&str>,
tag: Option<&str>,
rev: Option<&str>,
subdir: Option<&str>,
) -> String {
// Check if we need to get the git hash of the branch
let branch_hash = if let Some(branch) = branch {

Check failure on line 425 in src/project/manifest/python.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

manual implementation of `Option::map`
// Get the git hash of the branch
Some(get_git_branch_hash(url, branch).expect("error getting git branch hash"))
} else {
None
};

// Choose revision over tag if it is specified
let tag_or_rev_or_branch = rev

Check failure on line 433 in src/project/manifest/python.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

unnecessary closure used to substitute value for `Option::None`
.as_ref()
.or_else(|| tag.as_ref())
.cloned()
.or(branch_hash.as_deref());

// Create the url.
let url = format!("git+{url}");
// Add the subdirectory if it exists.
let url = subdir.as_ref().map_or_else(
|| url.clone(),
|subdir| format!("{url}#subdirectory={subdir}"),
);
// Add the tag or rev if it exists.
let url = tag_or_rev_or_branch
.as_ref()
.map_or_else(|| url.clone(), |tag_or_rev| format!("{url}@{tag_or_rev}"));
url
}

impl PyPiRequirement {
/// Returns the requirements as [`pep508_rs::Requirement`]s.
pub fn as_pep508(&self, name: &PackageName) -> pep508_rs::Requirement {
Expand All @@ -406,33 +464,24 @@ impl PyPiRequirement {
rev,
subdirectory: subdir,
} => {
// Check if we need to get the git hash of the branch
let branch_hash = if let Some(branch) = branch {
// Get the git hash of the branch
Some(get_git_branch_hash(url, branch).expect("error getting git branch hash"))
} else {
None
};
// Choose revision over tag if it is specified
let tag_or_rev_or_branch = rev
.as_ref()
.or_else(|| tag.as_ref())
.cloned()
.or(branch_hash);

// Create the url.
let url = format!("git+{url}");
// Add the tag or rev if it exists.
let url = tag_or_rev_or_branch
.as_ref()
.map_or_else(|| url.clone(), |tag_or_rev| format!("{url}@{tag_or_rev}"));
// Add the subdirectory if it exists.
let url = subdir.as_ref().map_or_else(
|| url.clone(),
|subdir| format!("{url}#subdirectory={subdir}"),
let given = create_given_url(
url,
branch.as_deref(),
tag.as_deref(),
rev.as_deref(),
subdir.as_deref(),
);
let uv_url = create_uv_url(
url,
branch.as_deref(),
tag.as_deref(),
rev.as_deref(),
subdir.as_deref(),
);
Some(pep508_rs::VersionOrUrl::Url(
VerbatimUrl::parse(&url).expect("git url is invalid"),
VerbatimUrl::parse(uv_url)
.expect("git url is invalid")
.with_given(given),
))
}
PyPiRequirementType::Path { path, editable: _ } => {
Expand Down

0 comments on commit b165d67

Please sign in to comment.