Skip to content

Commit

Permalink
fix: add purls for packages if adding pypi (#1148)
Browse files Browse the repository at this point in the history
Co-authored-by: Ruben Arts <[email protected]>
  • Loading branch information
nichmor and ruben-arts authored Apr 10, 2024
1 parent cb4bcbc commit 68033a3
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/lock_file/satisfiability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ pub enum PlatformUnsat {
#[error("there are more conda packages in the lock-file than are used by the environment")]
TooManyCondaPackages,

#[error("missing purls")]
MissingPurls,

#[error("corrupted lock-file entry for '{0}'")]
CorruptedEntry(String, ConversionError),

Expand Down Expand Up @@ -167,6 +170,20 @@ pub fn verify_platform_satisfiability(
}
}

// to reflect new purls for pypi packages
// we need to invalidate the locked environment
// if all conda packages have empty purls
if environment.has_pypi_dependencies()
&& pypi_packages.is_empty()
&& !conda_packages
.iter()
.any(|record| !record.package_record.purls.is_empty())
{
{
return Err(PlatformUnsat::MissingPurls);
}
}

// Create a lookup table from package name to package record. Returns an error if we find a
// duplicate entry for a record
let repodata_records_by_name = match RepoDataRecordsByName::from_unique_iter(conda_packages) {
Expand Down
15 changes: 14 additions & 1 deletion src/lock_file/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,19 @@ async fn spawn_solve_pypi_task(
tokio::join!(repodata_records, prefix, semaphore.acquire_owned());

let environment_name = environment.name().clone();

let pypi_name_mapping_location = environment.project().pypi_name_mapping_source();

let mut conda_records = repodata_records.records.clone();

pypi_mapping::amend_pypi_purls(
environment.project().client().clone(),
pypi_name_mapping_location,
&mut conda_records,
None,
)
.await?;

// let (pypi_packages, duration) = tokio::spawn(
let (pypi_packages, duration) = async move {
let pb = SolveProgressBar::new(
Expand All @@ -1493,7 +1506,7 @@ async fn spawn_solve_pypi_task(
.map(|(name, requirement)| (name.as_normalized().clone(), requirement))
.collect(),
system_requirements,
&repodata_records.records,
&conda_records,
platform,
&pb.pb,
&python_path,
Expand Down
5 changes: 5 additions & 0 deletions src/pypi_mapping/prefix_pypi_name_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ pub async fn conda_pypi_name_mapping(
) -> miette::Result<HashMap<Sha256Hash, Package>> {
let filtered_packages = conda_packages
.iter()
// because we later skip adding purls for packages
// that have purls
// here we only filter packages that don't them
// to save some requests
.filter(|package| package.package_record.purls.is_empty())
.filter_map(|package| {
package
.package_record
Expand Down
67 changes: 66 additions & 1 deletion tests/solve_group_tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::str::FromStr;

use crate::common::{
package_database::{Package, PackageDatabase},
LockFileExt, PixiControl,
};
use rattler_conda_types::Platform;
use rattler_conda_types::{PackageName, Platform};
use rattler_lock::DEFAULT_ENVIRONMENT_NAME;
use serial_test::serial;
use tempfile::TempDir;
use url::Url;

Expand Down Expand Up @@ -83,3 +87,64 @@ async fn conda_solve_group_functionality() {
"test should contain bar"
);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
#[serial]
// #[cfg_attr(not(feature = "slow_integration_tests"), ignore)]
async fn test_purl_are_added_for_pypi() {
let pixi = PixiControl::new().unwrap();
pixi.init().await.unwrap();
// Add and update lockfile with this version of python
pixi.add("boltons").with_install(true).await.unwrap();

let lock_file = pixi.up_to_date_lock_file().await.unwrap();

// Check if boltons has a purl
lock_file
.default_environment()
.unwrap()
.packages(Platform::current())
.unwrap()
.for_each(|dep| {
if dep.as_conda().unwrap().package_record().name
== PackageName::from_str("boltons").unwrap()
{
assert!(dep.as_conda().unwrap().package_record().purls.is_empty());
}
});

// Add boltons from pypi
pixi.add("boltons")
.with_install(true)
.set_type(pixi::DependencyType::PypiDependency)
.await
.unwrap();

let lock_file = pixi.up_to_date_lock_file().await.unwrap();

// Check if boltons has a purl
lock_file
.default_environment()
.unwrap()
.packages(Platform::current())
.unwrap()
.for_each(|dep| {
if dep.as_conda().unwrap().package_record().name
== PackageName::from_str("boltons").unwrap()
{
assert!(!dep.as_conda().unwrap().package_record().purls.is_empty());
}
});

// Check if boltons exists only as conda dependency
assert!(lock_file.contains_match_spec(
DEFAULT_ENVIRONMENT_NAME,
Platform::current(),
"boltons"
));
assert!(!lock_file.contains_pypi_package(
DEFAULT_ENVIRONMENT_NAME,
Platform::current(),
"boltons"
));
}

0 comments on commit 68033a3

Please sign in to comment.