Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add purls for packages if adding pypi #1148

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
));
}
Loading