Skip to content

Commit

Permalink
refactor: python API for lock files
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Nov 15, 2024
1 parent 4cafa0c commit 60069f8
Show file tree
Hide file tree
Showing 25 changed files with 172 additions and 147 deletions.
11 changes: 4 additions & 7 deletions crates/rattler-bin/src/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ pub async fn create(opt: Opt) -> anyhow::Result<()> {
if transaction.operations.is_empty() {
println!("No operations necessary");
} else {
print_transaction(&transaction, &channel_config);
print_transaction(&transaction);
}

return Ok(());
Expand Down Expand Up @@ -304,20 +304,17 @@ pub async fn create(opt: Opt) -> anyhow::Result<()> {
console::style(console::Emoji("✔", "")).green(),
install_start.elapsed()
);
print_transaction(&result.transaction, &channel_config);
print_transaction(&result.transaction);
}

Ok(())
}

/// Prints the operations of the transaction to the console.
fn print_transaction(
transaction: &Transaction<PrefixRecord, RepoDataRecord>,
channel_config: &ChannelConfig,
) {
fn print_transaction(transaction: &Transaction<PrefixRecord, RepoDataRecord>) {
let format_record = |r: &RepoDataRecord| {
let direct_url_print = if let Some(channel) = &r.channel {
channel_config.canonical_name(channel.as_ref())
channel.clone()
} else {
String::new()
};
Expand Down
2 changes: 1 addition & 1 deletion crates/rattler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ pub(crate) fn get_repodata_record(package_path: impl AsRef<std::path::Path>) ->
.unwrap()
.to_string(),
url: url::Url::from_file_path(package_path).unwrap(),
channel: "test".to_string(),
channel: Some(String::from("test")),
}
}
2 changes: 1 addition & 1 deletion crates/rattler_conda_types/src/match_spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ mod tests {
),
file_name: String::from("mamba-1.0-py37_0"),
url: url::Url::parse("https://mamba.io/mamba-1.0-py37_0.conda").unwrap(),
channel: String::from("mamba"),
channel: Some(String::from("mamba")),
};
let package_record = repodata_record.clone().package_record;

Expand Down
2 changes: 1 addition & 1 deletion crates/rattler_conda_types/src/repo_data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ impl RepoData {
base_url.as_deref(),
&filename,
),
channel: Some(channel.base_url.clone()),
channel: Some(channel.base_url.as_str().to_string()),
package_record,
file_name: filename,
});
Expand Down
16 changes: 8 additions & 8 deletions crates/rattler_conda_types/src/repo_data_record.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
//! Defines the `[RepoDataRecord]` struct.

use crate::PackageRecord;
use serde::{Deserialize, Serialize};
use url::Url;

use crate::{ChannelUrl, PackageRecord};

/// Information about a package from repodata. It includes a
/// [`crate::PackageRecord`] but it also stores the source of the data (like the
/// url and the channel).
/// Information about a package from repodata. It includes a [`crate::PackageRecord`] but it also stores
/// the source of the data (like the url and the channel).
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone, Hash)]
pub struct RepoDataRecord {
/// The data stored in the repodata.json.
Expand All @@ -21,9 +19,11 @@ pub struct RepoDataRecord {
/// The canonical URL from where to get this package.
pub url: Url,

/// The channel that contains the package. This might be `None` for a
/// package that does not come from a channel.
pub channel: Option<ChannelUrl>,
/// String representation of the channel where the package comes from. This could be a URL but
/// it could also be a channel name. Personally I would always add the complete URL here to be
/// explicit about where the package came from.
/// TODO: Refactor this into `Source` which can be a "name", "channelurl", or "direct url".
pub channel: Option<String>,
}

impl AsRef<PackageRecord> for RepoDataRecord {
Expand Down
1 change: 1 addition & 0 deletions crates/rattler_lock/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{

/// Information about a single locked package in an environment.
#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum LockedPackage {
/// A conda package
Conda(CondaPackageData),
Expand Down
8 changes: 6 additions & 2 deletions crates/rattler_lock/src/conda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{cmp::Ordering, hash::Hash};

use rattler_conda_types::{ChannelUrl, PackageRecord, RepoDataRecord};
use rattler_digest::Sha256Hash;
use url::Url;

use crate::UrlOrPath;

Expand Down Expand Up @@ -148,7 +149,10 @@ impl From<RepoDataRecord> for CondaPackageData {
Self::Binary(CondaBinaryData {
package_record: value.package_record,
file_name: value.file_name,
channel: value.channel,
channel: value
.channel
.and_then(|channel| Url::parse(&channel).ok())
.map(Into::into),
location,
})
}
Expand All @@ -170,7 +174,7 @@ impl TryFrom<CondaBinaryData> for RepoDataRecord {
package_record: value.package_record,
file_name: value.file_name,
url: value.location.try_into_url()?,
channel: value.channel,
channel: value.channel.map(|channel| channel.to_string()),
})
}
}
Expand Down
36 changes: 35 additions & 1 deletion crates/rattler_lock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl LockFile {
/// Information about a specific environment in the lock-file.
#[derive(Clone, Copy)]
pub struct Environment<'lock> {
inner: &'lock LockFileInner,
inner: &'lock Arc<LockFileInner>,
index: usize,
}

Expand Down Expand Up @@ -415,6 +415,40 @@ impl<'lock> Environment<'lock> {
self.packages(platform)
.map(|pkgs| pkgs.filter_map(LockedPackageRef::as_pypi))
}

/// Creates a [`OwnedEnvironment`] from this environment.
pub fn to_owned(self) -> OwnedEnvironment {
OwnedEnvironment {
inner: self.inner.clone(),
index: self.index,
}
}
}

/// An owned version of an [`Environment`].
///
/// Use [`OwnedEnvironment::as_ref`] to get a reference to the environment data.
#[derive(Clone)]
pub struct OwnedEnvironment {
inner: Arc<LockFileInner>,
index: usize,
}

impl OwnedEnvironment {
/// Returns a reference to the environment data.
pub fn as_ref(&self) -> Environment<'_> {
Environment {
inner: &self.inner,
index: self.index,
}
}

/// Returns the lock-file this environment is part of.
pub fn lock_file(&self) -> LockFile {
LockFile {
inner: self.inner.clone(),
}
}
}

/// Data related to a single locked package in an [`Environment`].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub(crate) struct CondaPackageDataModel<'a> {
pub platform: Cow<'a, Option<String>>,

#[serde(default, skip_serializing_if = "Option::is_none")]
pub channel: Cow<'a, Option<ChannelUrl>>,
pub channel: Cow<'a, Option<Url>>,

#[serde(default, skip_serializing_if = "Option::is_none")]
pub features: Cow<'a, Option<String>>,
Expand Down Expand Up @@ -141,6 +141,7 @@ impl<'a> From<CondaPackageDataModel<'a>> for CondaPackageData {
channel: value
.channel
.into_owned()
.map(ChannelUrl::from)
.or_else(|| derive_channel_from_location(&location)),
file_name,
location,
Expand Down
5 changes: 2 additions & 3 deletions crates/rattler_lock/src/parse/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ use url::Url;
use crate::{
file_format_version::FileFormatVersion,
parse::{models::v6, V6},
Channel, CondaPackageData, EnvironmentData, EnvironmentPackageData, LockFile,
LockFileInner, PypiIndexes, PypiPackageData, PypiPackageEnvironmentData,
UrlOrPath,
Channel, CondaPackageData, EnvironmentData, EnvironmentPackageData, LockFile, LockFileInner,
PypiIndexes, PypiPackageData, PypiPackageEnvironmentData, UrlOrPath,
};

#[serde_as]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use std::{borrow::Cow, io::Write, path::PathBuf, sync::Arc};

use crate::{
fetch::{CacheAction, FetchRepoDataError},
gateway::{error::SubdirNotFoundError, subdir::SubdirClient},
reporter::ResponseReporterExt,
GatewayError, Reporter,
};
use http::{header::CACHE_CONTROL, HeaderValue, StatusCode};
use rattler_conda_types::{
Channel, ChannelUrl, PackageName, RepoDataRecord, Shard, ShardedRepodata,
};
use rattler_redaction::Redact;
use reqwest_middleware::ClientWithMiddleware;
use simple_spawn_blocking::tokio::run_blocking_task;
use url::Url;

use crate::{
fetch::{CacheAction, FetchRepoDataError},
gateway::{error::SubdirNotFoundError, subdir::SubdirClient},
reporter::ResponseReporterExt,
GatewayError, Reporter,
};

mod index;

pub struct ShardedSubdir {
Expand Down Expand Up @@ -293,7 +293,7 @@ async fn parse_records<R: AsRef<[u8]> + Send + 'static>(
url: base_url
.join(&file_name)
.expect("filename is not a valid url"),
channel: Some(channel_base_url.clone()),
channel: Some(channel_base_url.url().clone().redact().to_string()),
package_record,
file_name,
})
Expand Down
3 changes: 2 additions & 1 deletion crates/rattler_repodata_gateway/src/sparse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use itertools::Itertools;
use rattler_conda_types::{
compute_package_url, Channel, ChannelInfo, PackageName, PackageRecord, RepoDataRecord,
};
use rattler_redaction::Redact;
use serde::{
de::{Error, MapAccess, Visitor},
Deserialize, Deserializer,
Expand Down Expand Up @@ -315,7 +316,7 @@ fn parse_records<'i>(
base_url,
key.filename,
),
channel: Some(channel_name.clone()),
channel: Some(channel_name.url().clone().redact().to_string()),
package_record,
file_name: key.filename.to_owned(),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/rattler_shell/src/activation.rs
assertion_line: 764
expression: env_diff
snapshot_kind: text
---
PKG1: "Hello, world!"
PKG2: "Hello, world!"
STATE: "Hello, world!"
4 changes: 2 additions & 2 deletions crates/rattler_solve/src/libsolv_c/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use input::cache_repodata;
use input::{add_repodata_records, add_solv_file, add_virtual_packages};
pub use libc_byte_slice::LibcByteSlice;
use output::get_required_packages;
use rattler_conda_types::{ChannelUrl, MatchSpec, NamelessMatchSpec, RepoDataRecord};
use rattler_conda_types::{MatchSpec, NamelessMatchSpec, RepoDataRecord};
use wrapper::{
flags::SolverFlag,
pool::{Pool, Verbosity},
Expand Down Expand Up @@ -179,7 +179,7 @@ impl super::SolverImpl for Solver {
};
let repo = ManuallyDrop::new(Repo::new(
&pool,
channel_name.as_ref().map_or("<direct>", ChannelUrl::as_str),
channel_name.as_ref().map_or("<direct>", String::as_str),
priority,
));

Expand Down
6 changes: 3 additions & 3 deletions crates/rattler_solve/src/resolvo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use chrono::{DateTime, Utc};
use conda_sorting::SolvableSorter;
use itertools::Itertools;
use rattler_conda_types::{
package::ArchiveType, ChannelUrl, GenericVirtualPackage, MatchSpec, Matches, NamelessMatchSpec,
package::ArchiveType, GenericVirtualPackage, MatchSpec, Matches, NamelessMatchSpec,
PackageName, PackageRecord, ParseMatchSpecError, ParseStrictness, RepoDataRecord,
};
use resolvo::{
Expand Down Expand Up @@ -221,7 +221,7 @@ impl<'a> CondaDependencyProvider<'a> {
.collect::<Vec<_>>();

// Hashmap that maps the package name to the channel it was first found in.
let mut package_name_found_in_channel = HashMap::<String, &Option<ChannelUrl>>::new();
let mut package_name_found_in_channel = HashMap::<String, &Option<String>>::new();

// Add additional records
for repo_data in repodata {
Expand Down Expand Up @@ -324,7 +324,7 @@ impl<'a> CondaDependencyProvider<'a> {
}) {
// Check if the spec has a channel, and compare it to the repodata channel
if let Some(spec_channel) = &spec.channel {
if record.channel.as_ref() != Some(&spec_channel.base_url) {
if record.channel.as_ref() != Some(&spec_channel.canonical_name()) {
tracing::debug!("Ignoring {} {} because it was not requested from that channel.", &record.package_record.name.as_normalized(), match &record.channel {
Some(channel) => format!("from {}", &channel),
None => "without a channel".to_string(),
Expand Down
10 changes: 5 additions & 5 deletions crates/rattler_solve/tests/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn installed_package(
) -> RepoDataRecord {
RepoDataRecord {
url: Url::from_str("http://example.com").unwrap(),
channel: channel.to_string(),
channel: Some(channel.to_string()),
file_name: "dummy-filename".to_string(),
package_record: PackageRecord {
name: name.parse().unwrap(),
Expand Down Expand Up @@ -352,7 +352,7 @@ macro_rules! solver_backend_tests {
"https://conda.anaconda.org/conda-forge/linux-64/foo-3.0.2-py36h1af98f8_3.conda",
info.url.to_string()
);
assert_eq!("https://conda.anaconda.org/conda-forge/", info.channel);
assert_eq!(Some("https://conda.anaconda.org/conda-forge/"), info.channel.as_deref());
assert_eq!("foo", info.package_record.name.as_normalized());
assert_eq!("linux-64", info.package_record.subdir);
assert_eq!("3.0.2", info.package_record.version.to_string());
Expand Down Expand Up @@ -867,7 +867,7 @@ mod resolvo {
// Mocking the rest of the fields
file_name: url_str.to_string(),
url: url.clone(),
channel: "".to_string(),
channel: None,
}];

// Completely clean solver task, except for the specs and RepoData
Expand Down Expand Up @@ -900,7 +900,7 @@ mod resolvo {
package_record,
file_name: url_str.to_string(),
url: Url::from_str("https://false.dont").unwrap(),
channel: "".to_string(),
channel: None,
}];

// Completely clean solver task, except for the specs and RepoData
Expand Down Expand Up @@ -1155,7 +1155,7 @@ fn solve_to_get_channel_of_spec<T: SolverImpl + Default>(
let record = result.iter().find(|record| {
record.package_record.name.as_normalized() == spec.name.as_ref().unwrap().as_normalized()
});
assert_eq!(record.unwrap().channel, expected_channel.to_string());
assert_eq!(record.unwrap().channel, Some(expected_channel.to_string()));
}

#[test]
Expand Down
7 changes: 0 additions & 7 deletions py-rattler/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions py-rattler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ anyhow = "1.0.92"
chrono = { version = "0.4" }
futures = "0.3.31"

self_cell = "1.0.4"

rattler = { path = "../crates/rattler", default-features = false, features = ["indicatif"] }
rattler_repodata_gateway = { path = "../crates/rattler_repodata_gateway", default-features = false, features = [
"sparse",
Expand Down
Loading

0 comments on commit 60069f8

Please sign in to comment.