From dbd0e8885af96e3ae9d283fb61f53ac01335eff8 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Thu, 15 Aug 2024 17:03:48 +0200 Subject: [PATCH] fix: get metadata call --- Cargo.toml | 2 +- crates/pixi-build-python/Cargo.toml | 1 + crates/pixi-build-python/src/main.rs | 599 +++++++++++++++++++-------- pixi.lock | 144 +++---- pixi.toml | 2 +- rust-toolchain | 1 + 6 files changed, 506 insertions(+), 243 deletions(-) create mode 100644 rust-toolchain diff --git a/Cargo.toml b/Cargo.toml index dd6bc53..55b6950 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ jsonrpc-stdio-server = "18.0.0" jsonrpc-http-server = "18.0.0" jsonrpc-core = "18.0.0" -rattler-build = { git = "https://github.com/baszalmstra/rattler-build", branch = "chore/bump_rattler", default-features = false } +rattler-build = { git = "https://github.com/baszalmstra/rattler-build", branch = "refactor/no_default_build_string", default-features = false } rattler_conda_types = "0.27.1" rattler_package_streaming = "0.22.1" diff --git a/crates/pixi-build-python/Cargo.toml b/crates/pixi-build-python/Cargo.toml index ca34515..34e3314 100644 --- a/crates/pixi-build-python/Cargo.toml +++ b/crates/pixi-build-python/Cargo.toml @@ -28,3 +28,4 @@ parking_lot = { workspace = true } jsonrpc-stdio-server = { workspace = true } jsonrpc-http-server = { workspace = true } jsonrpc-core = { workspace = true } +log = "0.4.22" diff --git a/crates/pixi-build-python/src/main.rs b/crates/pixi-build-python/src/main.rs index 42c97c1..5ed17b0 100644 --- a/crates/pixi-build-python/src/main.rs +++ b/crates/pixi-build-python/src/main.rs @@ -2,6 +2,7 @@ mod consts; use std::{ collections::BTreeMap, + future::Future, io::BufWriter, net::SocketAddr, path::{Path, PathBuf}, @@ -12,13 +13,17 @@ use std::{ use chrono::Utc; use clap::{Parser, Subcommand}; use clap_verbosity_flag::{InfoLevel, Verbosity}; -use jsonrpc_core::{to_value, Error, IoHandler}; +use jsonrpc_core::{serde_json, to_value, Error, IoHandler}; use jsonrpc_http_server::jsonrpc_core::Params; -use miette::{Context, IntoDiagnostic}; +use miette::{Context, IntoDiagnostic, JSONReportHandler}; use parking_lot::Mutex; use pixi_build_types::{ - procedures::initialize::{InitializeParams, InitializeResult}, - BackendCapabilities, + procedures, + procedures::{ + conda_metadata::{CondaMetadataParams, CondaMetadataResult}, + initialize::{InitializeParams, InitializeResult}, + }, + BackendCapabilities, CondaPackageMetadata, }; use pixi_manifest::{Dependencies, Manifest, SpecType}; use pixi_spec::PixiSpec; @@ -31,6 +36,7 @@ use rattler_build::{ parser::{Build, Dependency, Package, PathSource, Requirements, ScriptContent, Source}, Recipe, }, + render::resolved_dependencies::DependencyInfo, tool_configuration::{Configuration, SkipExisting}, }; use rattler_conda_types::{ @@ -62,7 +68,7 @@ pub struct App { #[derive(Subcommand)] pub enum Commands { /// store data as key value pair - GetMetadata { + GetCondaMetadata { #[clap(env, long, env = "PIXI_PROJECT_MANIFEST", default_value = consts::PROJECT_MANIFEST)] manifest_path: PathBuf, }, @@ -80,54 +86,121 @@ pub async fn main() { } } +fn convert_error(err: miette::Report) -> jsonrpc_core::Error { + let rendered = JSONReportHandler::new(); + let mut json_str = String::new(); + rendered + .render_report(&mut json_str, err.as_ref()) + .expect("failed to convert error to json"); + let data = serde_json::from_str(&json_str).expect("failed to parse json error"); + jsonrpc_core::Error { + code: jsonrpc_core::ErrorCode::ServerError(-32000), + message: err.to_string(), + data: Some(data), + } +} + struct BuildServer { manifest: Manifest, - manifest_root: PathBuf, + logging_output_handler: LoggingOutputHandler, } impl BuildServer { - pub fn new(manifest_path: &Path) -> miette::Result { + pub fn new( + manifest_path: &Path, + logging_output_handler: LoggingOutputHandler, + ) -> miette::Result { // Load the manifest from the source directory let manifest = Manifest::from_path(&manifest_path).with_context(|| { format!("failed to parse manifest from {}", manifest_path.display()) })?; - let manifest_root = manifest_path - .parent() - .expect("the project manifest must reside in a directory") - .to_path_buf(); Ok(Self { manifest, - manifest_root, + logging_output_handler, }) } + + pub fn manifest_root(&self) -> &Path { + self.manifest + .path + .parent() + .expect("manifest should always reside in a directory") + } + + pub async fn get_conda_metadata( + &self, + params: CondaMetadataParams, + ) -> miette::Result { + let channel_config = ChannelConfig { + channel_alias: params.channel_configuration.base_url, + root_dir: self.manifest_root().to_path_buf(), + }; + let channels = params + .channel_base_urls + .unwrap_or_else(|| channels_from_manifest(&self.manifest, &channel_config)); + + get_conda_metadata_from_manifest( + &self.manifest, + &channel_config, + channels, + self.logging_output_handler.clone(), + ) + .await + } } -async fn run_server(port: Option) -> miette::Result<()> { +async fn run_server( + port: Option, + logging_output_handler: LoggingOutputHandler, +) -> miette::Result<()> { let build_server = Arc::new(Mutex::new(None)); // Construct a server let mut io = IoHandler::new(); - io.add_sync_method("initialize", move |params: Params| { - let params: InitializeParams = params.parse()?; - - let mut build_server = build_server.lock(); - if build_server.is_some() { - return Err(Error::invalid_request()); - } - *build_server = Some( - BuildServer::new(¶ms.manifest_path) - .map_err(|e| Error::invalid_params(e.to_string()))?, - ); + let initialize_build_server = build_server.clone(); + io.add_sync_method( + procedures::initialize::METHOD_NAME, + move |params: Params| { + let params: InitializeParams = params.parse()?; + + let mut build_server = initialize_build_server.lock(); + if build_server.is_some() { + return Err(Error::invalid_request()); + } + + *build_server = Some(Arc::new( + BuildServer::new(¶ms.manifest_path, logging_output_handler.clone()) + .map_err(convert_error)?, + )); + + Ok(to_value(InitializeResult { + capabilities: BackendCapabilities { + provides_conda_metadata: Some(true), + }, + }) + .expect("failed to convert to json")) + }, + ); - Ok(to_value(InitializeResult { - capabilities: BackendCapabilities { - provides_conda_metadata: Some(true), - }, - }) - .expect("failed to convert to json")) - }); + io.add_method( + procedures::conda_metadata::METHOD_NAME, + move |params: Params| { + let build_server = build_server.clone(); + let build_server = build_server.lock().as_ref().cloned(); + async move { + let params: CondaMetadataParams = params.parse()?; + + build_server + .ok_or_else(|| Error::invalid_request())? + .get_conda_metadata(params) + .await + .map(|value| to_value(value).expect("failed to convert to json")) + .map_err(convert_error) + } + }, + ); if let Some(port) = port { jsonrpc_http_server::ServerBuilder::new(io) @@ -151,40 +224,171 @@ async fn actual_main() -> miette::Result<()> { registry.with(log_handler.clone()).init(); match args.command { - None => run_server(args.http_port).await, + None => run_server(args.http_port, log_handler).await, Some(Commands::Build { manifest_path }) => build(log_handler, &manifest_path).await, - Some(Commands::GetMetadata { .. }) => unimplemented!(), + Some(Commands::GetCondaMetadata { manifest_path }) => { + let metadata = get_conda_metadata(log_handler, &manifest_path).await?; + println!("{}", serde_yaml::to_string(&metadata).unwrap()); + Ok(()) + } } } +async fn get_conda_metadata( + logging_output_handler: LoggingOutputHandler, + manifest_path: &Path, +) -> miette::Result { + let manifest = Manifest::from_path(&manifest_path) + .with_context(|| format!("failed to parse manifest from {}", manifest_path.display()))?; + let channel_config = ChannelConfig::default_with_root_dir( + manifest_path + .parent() + .expect("manifest should always reside in a directory") + .to_path_buf(), + ); + let channels = channels_from_manifest(&manifest, &channel_config); + + get_conda_metadata_from_manifest(&manifest, &channel_config, channels, logging_output_handler) + .await +} + +async fn get_conda_metadata_from_manifest( + manifest: &Manifest, + channel_config: &ChannelConfig, + channels: Vec, + logging_output_handler: LoggingOutputHandler, +) -> miette::Result { + // TODO: Determine how and if we can determine this from the manifest. + let recipe = manifest_to_recipe(&manifest, &channel_config)?; + let output = Output { + build_configuration: manifest_to_build_configuration(&manifest, &recipe, channels).await?, + recipe, + finalized_dependencies: None, + finalized_cache_dependencies: None, + finalized_sources: None, + build_summary: Arc::default(), + system_tools: Default::default(), + }; + let tool_config = get_tool_configuration(logging_output_handler, &channel_config)?; + + let temp_recipe = TemporaryRenderedRecipe::from_output(&output)?; + let output = temp_recipe + .within_context_async(move || async move { + output + .resolve_dependencies(&tool_config) + .await + .into_diagnostic() + }) + .await?; + + let finalized_deps = &output + .finalized_dependencies + .as_ref() + .expect("dependencies should be resolved at this point") + .run; + + Ok(CondaMetadataResult { + packages: vec![CondaPackageMetadata { + name: output.name().clone(), + version: output.version().clone(), + build: output.build_string().into_owned(), + build_number: output.recipe.build.number, + subdir: output.build_configuration.target_platform, + depends: Some( + finalized_deps + .depends + .iter() + .map(DependencyInfo::spec) + .cloned() + .collect(), + ), + constrains: Some( + finalized_deps + .constraints + .iter() + .map(DependencyInfo::spec) + .cloned() + .collect(), + ), + license: output.recipe.about.license.map(|l| l.to_string()), + license_family: output.recipe.about.license_family, + }], + }) +} + async fn build( logging_output_handler: LoggingOutputHandler, manifest_path: &Path, ) -> miette::Result<()> { - // Load the manifest let manifest = Manifest::from_path(&manifest_path) .with_context(|| format!("failed to parse manifest from {}", manifest_path.display()))?; - let manifest_root = manifest_path - .parent() - .expect("the project manifest must reside in a directory"); + let channel_config = ChannelConfig::default_with_root_dir( + manifest_path + .parent() + .expect("manifest should always reside in a directory") + .to_path_buf(), + ); + let channels = channels_from_manifest(&manifest, &channel_config); + + build_manifest(&manifest, &channel_config, channels, logging_output_handler).await +} + +async fn build_manifest( + manifest: &Manifest, + channel_config: &ChannelConfig, + channels: Vec, + logging_output_handler: LoggingOutputHandler, +) -> miette::Result<()> { + let recipe = manifest_to_recipe(&manifest, &channel_config)?; + let output = Output { + build_configuration: manifest_to_build_configuration(&manifest, &recipe, channels).await?, + recipe, + finalized_dependencies: None, + finalized_cache_dependencies: None, + finalized_sources: None, + build_summary: Arc::default(), + system_tools: Default::default(), + }; + let tool_config = get_tool_configuration(logging_output_handler, &channel_config)?; + + let temp_recipe = TemporaryRenderedRecipe::from_output(&output)?; + let (_output, package) = temp_recipe + .within_context_async(move || async move { run_build(output, &tool_config).await }) + .await?; + eprintln!("Successfully build '{}'", package.display()); + Ok(()) +} + +fn get_tool_configuration( + logging_output_handler: LoggingOutputHandler, + channel_config: &ChannelConfig, +) -> miette::Result { + Ok(Configuration { + fancy_log_handler: logging_output_handler, + client: reqwest_middleware::ClientWithMiddleware::from(Client::default()), + no_clean: false, + no_test: false, + use_zstd: true, + use_bz2: true, + render_only: false, + skip_existing: SkipExisting::None, + channel_config: channel_config.clone(), + compression_threads: None, + }) +} + +async fn manifest_to_build_configuration( + manifest: &Manifest, + recipe: &Recipe, + channels: Vec, +) -> miette::Result { // Parse the package name from the manifest let Some(name) = manifest.parsed.project.name.clone() else { miette::bail!("a 'name' field is required in the project manifest"); }; let name = PackageName::from_str(&name).into_diagnostic()?; - // Parse the package version from the manifest - let Some(version) = manifest.parsed.project.version.clone() else { - miette::bail!("a 'version' field is required in the project manifest"); - }; - - // TODO: Variants??? - let variants = BTreeMap::default(); - - // TODO: NoArchType??? - let noarch_type = NoArchType::python(); - // TODO: Setup defaults let output_dir = tempdir() .into_diagnostic() @@ -194,7 +398,7 @@ async fn build( .context("failed to create output directory")?; let directories = Directories::setup( name.as_normalized(), - manifest_path, + manifest.path.as_path(), output_dir.path(), false, &Utc::now(), @@ -202,133 +406,112 @@ async fn build( .into_diagnostic() .context("failed to setup build directories")?; - // TODO: Read from config / project. - let channel_config = ChannelConfig::default_with_root_dir(manifest_root.to_path_buf()); - - let requirements = requirements_from_manifest(&manifest, &channel_config); - let channels = channels_from_manifest(&manifest, &channel_config); - let host_platform = Platform::current(); let build_platform = Platform::current(); - let hash = HashInfo::from_variant(&variants, &noarch_type); - let build_number = 0; - let build_string = format!("{}_{}", &hash.hash, build_number); + let variant = BTreeMap::new(); + + Ok(BuildConfiguration { + // TODO: NoArch?? + target_platform: Platform::NoArch, + host_platform, + build_platform, + hash: HashInfo::from_variant(&variant, &recipe.build.noarch), + variant, + directories, + channels, + channel_priority: Default::default(), + solve_strategy: Default::default(), + timestamp: chrono::Utc::now(), + subpackages: Default::default(), // TODO: ??? + packaging_settings: PackagingSettings::from_args( + ArchiveType::Conda, + CompressionLevel::default(), + ), + store_recipe: true, + force_colors: true, + }) +} - let output = Output { - recipe: Recipe { - schema_version: 1, - package: Package { - version: VersionWithSource::from(version), - name, - }, - cache: None, - source: vec![Source::Path(PathSource { - // TODO: How can we use a git source? - path: manifest_root.to_path_buf(), - sha256: None, - md5: None, - patches: vec![], - target_directory: None, - file_name: None, - use_gitignore: true, - })], - build: Build { - number: build_number, - string: Some(build_string), - - // skip: Default::default(), - script: ScriptContent::Commands( - if build_platform.is_windows() { - vec![ - "%PYTHON% -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string(), - "if errorlevel 1 exit 1".to_string()] - } else { - vec!["$PYTHON -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string()] - }) - .into(), - noarch: noarch_type, - - // TODO: Python is not exposed properly - //python: Default::default(), - // dynamic_linking: Default::default(), - // always_copy_files: Default::default(), - // always_include_files: Default::default(), - // merge_build_and_host_envs: false, - // variant: Default::default(), - // prefix_detection: Default::default(), - // post_process: vec![], - // files: Default::default(), - ..Build::default() - }, - // TODO read from manifest - requirements, - tests: vec![], - about: Default::default(), - extra: Default::default(), - }, - build_configuration: BuildConfiguration { - // TODO: NoArch?? - target_platform: Platform::NoArch, - host_platform, - build_platform, - hash, - variant: Default::default(), - directories, - channels, - channel_priority: Default::default(), - solve_strategy: Default::default(), - timestamp: chrono::Utc::now(), - subpackages: Default::default(), // TODO: ??? - packaging_settings: PackagingSettings::from_args( - ArchiveType::Conda, - CompressionLevel::default(), - ), - store_recipe: true, - force_colors: true, - }, - finalized_dependencies: None, - finalized_cache_dependencies: None, - finalized_sources: None, - build_summary: Arc::default(), - system_tools: Default::default(), - }; +fn manifest_to_recipe( + manifest: &Manifest, + channel_config: &ChannelConfig, +) -> miette::Result { + let manifest_root = manifest + .path + .parent() + .expect("the project manifest must reside in a directory"); - let tool_config = Configuration { - fancy_log_handler: logging_output_handler, - client: reqwest_middleware::ClientWithMiddleware::from(Client::default()), - no_clean: false, - no_test: false, - use_zstd: true, - use_bz2: true, - render_only: false, - skip_existing: SkipExisting::None, - channel_config, - compression_threads: None, + // Parse the package name from the manifest + let Some(name) = manifest.parsed.project.name.clone() else { + miette::bail!("a 'name' field is required in the project manifest"); }; + let name = PackageName::from_str(&name).into_diagnostic()?; - let (recipe_file, recipe_path) = tempfile::Builder::new() - .prefix(".rendered-recipe") - .suffix(".yaml") - .tempfile_in(output_dir) - .into_diagnostic() - .context("failed to create temporary file for recipe")? - .into_parts(); - - // Write the recipe back to a file - serde_yaml::to_writer(BufWriter::new(recipe_file), &output.recipe) - .into_diagnostic() - .context("failed to write recipe to temporary file")?; + // Parse the package version from the manifest + let Some(version) = manifest.parsed.project.version.clone() else { + miette::bail!("a 'version' field is required in the project manifest"); + }; - let (_output, package) = run_build(output, &tool_config).await?; - eprintln!("Successfully build '{}'", package.display()); + // TODO: NoArchType??? + let noarch_type = NoArchType::python(); - // Remove the temporary recipe file. - std::fs::remove_file(recipe_path) - .into_diagnostic() - .context("failed to remove temporary recipe file")?; + // TODO: Read from config / project. + let requirements = requirements_from_manifest(&manifest, &channel_config); + let build_platform = Platform::current(); + let build_number = 0; - Ok(()) + Ok(Recipe { + schema_version: 1, + package: Package { + version: VersionWithSource::from(version), + name, + }, + cache: None, + source: vec![Source::Path(PathSource { + // TODO: How can we use a git source? + path: manifest_root.to_path_buf(), + sha256: None, + md5: None, + patches: vec![], + target_directory: None, + file_name: None, + use_gitignore: true, + })], + build: Build { + number: build_number, + string: None, + + // skip: Default::default(), + script: ScriptContent::Commands( + if build_platform.is_windows() { + vec![ + "%PYTHON% -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string(), + "if errorlevel 1 exit 1".to_string()] + } else { + vec!["$PYTHON -m pip install --ignore-installed --no-deps --no-build-isolation . -vv".to_string()] + }) + .into(), + noarch: noarch_type, + + // TODO: Python is not exposed properly + //python: Default::default(), + // dynamic_linking: Default::default(), + // always_copy_files: Default::default(), + // always_include_files: Default::default(), + // merge_build_and_host_envs: false, + // variant: Default::default(), + // prefix_detection: Default::default(), + // post_process: vec![], + // files: Default::default(), + ..Build::default() + }, + // TODO read from manifest + requirements, + tests: vec![], + about: Default::default(), + extra: Default::default(), + }) } /// Get the requirements for a default feature @@ -342,7 +525,7 @@ fn requirements_from_manifest(manifest: &Manifest, channel_config: &ChannelConfi .iter() .filter_map(|f| f.dependencies(Some(SpecType::Run), None)), ); - let host_dependencies = Dependencies::from( + let mut host_dependencies = Dependencies::from( default_features .iter() .filter_map(|f| f.dependencies(Some(SpecType::Host), None)), @@ -353,6 +536,27 @@ fn requirements_from_manifest(manifest: &Manifest, channel_config: &ChannelConfi .filter_map(|f| f.dependencies(Some(SpecType::Build), None)), ); + // Ensure python and pip are available in the host dependencies section. + for pkg_name in ["pip", "python"] { + if host_dependencies.contains_key(pkg_name) { + // If the host dependencies already contain the package, we don't need to add it + // again. + continue; + } + + if let Some(run_requirements) = run_dependencies.get(pkg_name) { + // Copy the run requirements to the host requirements. + for req in run_requirements { + host_dependencies.insert(PackageName::from_str(pkg_name).unwrap(), req.clone()); + } + } else { + host_dependencies.insert( + PackageName::from_str(pkg_name).unwrap(), + PixiSpec::default(), + ); + } + } + requirements.build = dependencies_into_matchspecs(build_dependencies, channel_config) .into_iter() .map(Dependency::Spec) @@ -366,8 +570,6 @@ fn requirements_from_manifest(manifest: &Manifest, channel_config: &ChannelConfi .map(Dependency::Spec) .collect(); - // TODO: If the host requirements don't contain pip or python add those - requirements } @@ -394,3 +596,62 @@ fn dependencies_into_matchspecs( }) .collect() } + +/// A helper struct that owns a temporary file containing a rendered recipe. +/// If `finish` is not called, the temporary file will stay on disk for +/// debugging purposes. +struct TemporaryRenderedRecipe { + file: PathBuf, +} + +impl TemporaryRenderedRecipe { + pub fn from_output(output: &Output) -> miette::Result { + // Ensure that the output directory exists + std::fs::create_dir_all(&output.build_configuration.directories.output_dir) + .into_diagnostic() + .context("failed to create output directory")?; + + let (recipe_file, recipe_path) = tempfile::Builder::new() + .prefix(".rendered-recipe") + .suffix(".yaml") + .tempfile_in(&output.build_configuration.directories.output_dir) + .into_diagnostic() + .context("failed to create temporary file for recipe")? + .into_parts(); + + // Write the recipe back to a file + serde_yaml::to_writer(BufWriter::new(recipe_file), &output.recipe) + .into_diagnostic() + .context("failed to write recipe to temporary file")?; + + Ok(Self { + file: recipe_path.keep().unwrap(), + }) + } + + pub fn within_context miette::Result>( + self, + operation: F, + ) -> miette::Result { + let result = operation()?; + std::fs::remove_file(self.file) + .into_diagnostic() + .context("failed to remove temporary recipe file")?; + Ok(result) + } + + pub async fn within_context_async< + R, + Fut: Future>, + F: FnOnce() -> Fut, + >( + self, + operation: F, + ) -> miette::Result { + let result = operation().await?; + std::fs::remove_file(self.file) + .into_diagnostic() + .context("failed to remove temporary recipe file")?; + Ok(result) + } +} diff --git a/pixi.lock b/pixi.lock index b2d6997..d9fdce0 100644 --- a/pixi.lock +++ b/pixi.lock @@ -30,8 +30,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-h4bc722e_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.4-h194c7f8_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.0-h0a17960_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.0-h2c6d0dc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.1-h0a17960_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.1-h2c6d0dc_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h4a8ded7_16.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda @@ -47,8 +47,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.1-h87427d6_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.4-h37a9e06_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.0-h6c54e5d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.0-h38e4360_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.1-h6c54e5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.1-h38e4360_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 @@ -63,8 +63,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.1-hfb2fe0b_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.4-h30c5eda_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.0-h4ff7c5d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.0-hf6ec828_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.1-h4ff7c5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.1-hf6ec828_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 @@ -77,8 +77,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.4-h889d299_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.0-hf8d6059_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.0-h17fc481_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.1-hf8d6059_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.1-h17fc481_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_0.tar.bz2 @@ -223,8 +223,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.4-h194c7f8_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.0-h0a17960_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.0-h2c6d0dc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.1-h0a17960_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.1-h2c6d0dc_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h4a8ded7_16.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 @@ -247,8 +247,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.4-h37a9e06_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.0-h6c54e5d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.0-h38e4360_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.1-h6c54e5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.1-h38e4360_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda @@ -270,8 +270,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.4-h30c5eda_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.0-h4ff7c5d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.0-hf6ec828_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.1-h4ff7c5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.1-hf6ec828_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda @@ -291,8 +291,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.4-h889d299_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.0-hf8d6059_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.0-h17fc481_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.1-hf8d6059_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.1-h17fc481_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda @@ -1632,133 +1632,133 @@ packages: timestamp: 1723150552013 - kind: conda name: rust - version: 1.80.0 + version: 1.80.1 build: h0a17960_0 subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.0-h0a17960_0.conda - sha256: 79f4530d50b61931fca032c0a1f3a3d412c18e3d5d297803a4e9211aedbd0c72 - md5: b1eaf8cac79c98a63e744828def6e9ab + url: https://conda.anaconda.org/conda-forge/linux-64/rust-1.80.1-h0a17960_0.conda + sha256: 7058519747d4b81f3cab23a0d6b4326c80879d38b2a0bf11cade52fc59980b8f + md5: dba7ad0d2f707fee5e85c6a19042fdb4 depends: - __glibc >=2.17,<3.0.a0 - gcc_impl_linux-64 - libgcc-ng >=12 - libzlib >=1.3.1,<2.0a0 - - rust-std-x86_64-unknown-linux-gnu 1.80.0 h2c6d0dc_0 + - rust-std-x86_64-unknown-linux-gnu 1.80.1 h2c6d0dc_0 - sysroot_linux-64 >=2.17 license: MIT license_family: MIT - size: 198198162 - timestamp: 1721954933202 + size: 198885602 + timestamp: 1723153698032 - kind: conda name: rust - version: 1.80.0 + version: 1.80.1 build: h4ff7c5d_0 subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.0-h4ff7c5d_0.conda - sha256: 9c81df5e27b025b6828c6114c957ac50be4c1f59efadb2f21bbae1cf8861fcf7 - md5: c25eefb2c886341060c08e777a359c66 + url: https://conda.anaconda.org/conda-forge/osx-arm64/rust-1.80.1-h4ff7c5d_0.conda + sha256: 5b296bb663be4c10bf3d07eaaa69c3c5856bd198152a775404e161f6780236bb + md5: 76d236abc95f2d77f7a3c16f1b565b3e depends: - - rust-std-aarch64-apple-darwin 1.80.0 hf6ec828_0 + - rust-std-aarch64-apple-darwin 1.80.1 hf6ec828_0 license: MIT license_family: MIT - size: 198547913 - timestamp: 1721956518569 + size: 197866703 + timestamp: 1723155024117 - kind: conda name: rust - version: 1.80.0 + version: 1.80.1 build: h6c54e5d_0 subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.0-h6c54e5d_0.conda - sha256: 537ac1262ed88d67778f20202aee00b4f7216b6629469fc9cab712d4adfcd00c - md5: 89d61005c5442171efee1c209af2e4c1 + url: https://conda.anaconda.org/conda-forge/osx-64/rust-1.80.1-h6c54e5d_0.conda + sha256: 8e799c550545a41baef23a543ffd87620cf67c0afd3494ea40b6081cbf8aabe7 + md5: ecf36b937ded5c641039161f7f5c7f64 depends: - - rust-std-x86_64-apple-darwin 1.80.0 h38e4360_0 + - rust-std-x86_64-apple-darwin 1.80.1 h38e4360_0 license: MIT license_family: MIT - size: 202608126 - timestamp: 1721956412830 + size: 202606989 + timestamp: 1723154998091 - kind: conda name: rust - version: 1.80.0 + version: 1.80.1 build: hf8d6059_0 subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.0-hf8d6059_0.conda - sha256: a3ec6eb6081d82982354e605e4dcd0cd4d0c08003738823c8aec857ffb88f4d5 - md5: 2b5fdb7d7dffa336d151bf010884f9e6 + url: https://conda.anaconda.org/conda-forge/win-64/rust-1.80.1-hf8d6059_0.conda + sha256: 3d8f926d5db03762a1e3ff723295ea18674c29960e2e501a16c9413304698654 + md5: 385a661cb1746cb6c62eb55712b412dd depends: - - rust-std-x86_64-pc-windows-msvc 1.80.0 h17fc481_0 + - rust-std-x86_64-pc-windows-msvc 1.80.1 h17fc481_0 license: MIT license_family: MIT - size: 191890852 - timestamp: 1721957869309 + size: 194534225 + timestamp: 1723155969495 - kind: conda name: rust-std-aarch64-apple-darwin - version: 1.80.0 + version: 1.80.1 build: hf6ec828_0 subdir: noarch noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.0-hf6ec828_0.conda - sha256: 42fe88db0e541ba6566447985d41292f56b8c2bd4536ff7c627862d1bb497248 - md5: 930d52e675d58d69519641b8efdc886e + url: https://conda.anaconda.org/conda-forge/noarch/rust-std-aarch64-apple-darwin-1.80.1-hf6ec828_0.conda + sha256: 6cd8c3cf93fb8348c815595eced946316bc81a0bf8c6fc8f6b9f27e270734770 + md5: b3b07764d1fa59acf5c356bbb727db20 depends: - __unix constrains: - - rust >=1.80.0,<1.80.1.0a0 + - rust >=1.80.1,<1.80.2.0a0 license: MIT license_family: MIT - size: 30915084 - timestamp: 1721954422491 + size: 30991019 + timestamp: 1723152907303 - kind: conda name: rust-std-x86_64-apple-darwin - version: 1.80.0 + version: 1.80.1 build: h38e4360_0 subdir: noarch noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.0-h38e4360_0.conda - sha256: 7b6b7f3ce1953dce2c5d5f2b876ecfdff3f937f4ddf7e5763329625e7a321fcb - md5: 3920acda7811134d546f298dce845367 + url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-apple-darwin-1.80.1-h38e4360_0.conda + sha256: 56a30b275235975ea4e37f8d703818079601163aca92195a45468b0e7d6beffb + md5: b1ce3c6d57f2cf9f5a8b2448e3b6f499 depends: - __unix constrains: - - rust >=1.80.0,<1.80.1.0a0 + - rust >=1.80.1,<1.80.2.0a0 license: MIT license_family: MIT - size: 31796378 - timestamp: 1721954358969 + size: 31988631 + timestamp: 1723152891461 - kind: conda name: rust-std-x86_64-pc-windows-msvc - version: 1.80.0 + version: 1.80.1 build: h17fc481_0 subdir: noarch noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.0-h17fc481_0.conda - sha256: 8affe6895192604d85e298a10a214fa61de54bcadd0f0ea68bc0eb2433f4d94c - md5: 3d21418182cb084e4df4f27a3a5a4091 + url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-pc-windows-msvc-1.80.1-h17fc481_0.conda + sha256: a4f118c6211f717846c094e58d3baef32215d1a2414d51c3e08b739dce75c28f + md5: f21862b6487af2fe504ca2b78dfec822 depends: - __win constrains: - - rust >=1.80.0,<1.80.1.0a0 + - rust >=1.80.1,<1.80.2.0a0 license: MIT license_family: MIT - size: 22714844 - timestamp: 1721957540806 + size: 25255952 + timestamp: 1723155705619 - kind: conda name: rust-std-x86_64-unknown-linux-gnu - version: 1.80.0 + version: 1.80.1 build: h2c6d0dc_0 subdir: noarch noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.0-h2c6d0dc_0.conda - sha256: abf78c6a6fb2165930141732bd20f9de8098eb16835ac42d0fc14e2aad119f0a - md5: 3531afd355a7a93b4c00960a8fa69304 + url: https://conda.anaconda.org/conda-forge/noarch/rust-std-x86_64-unknown-linux-gnu-1.80.1-h2c6d0dc_0.conda + sha256: 769cb83291804c9faa0de81534ceb3794cd06efd4d5164872bd5527e511f12a7 + md5: 0a5b8783d18a253b0812a5501df297af depends: - __unix constrains: - - rust >=1.80.0,<1.80.1.0a0 + - rust >=1.80.1,<1.80.2.0a0 license: MIT license_family: MIT - size: 34334852 - timestamp: 1721954797437 + size: 33938994 + timestamp: 1723153507938 - kind: conda name: sysroot_linux-64 version: '2.17' diff --git a/pixi.toml b/pixi.toml index 03bfb45..27a10da 100644 --- a/pixi.toml +++ b/pixi.toml @@ -37,7 +37,7 @@ run = { cmd = "cargo run", inputs = [ "target/debug/**", ] } [dependencies] -rust = ">=1.80.0,<2" +rust = "~=1.80.1" python = ">=3.12.4,<4" [feature.test.dependencies] diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..97e9852 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +1.80.1