From 2aeee9de340abf5cc4c8a86e73f7e243056f429c Mon Sep 17 00:00:00 2001 From: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Sun, 29 Dec 2024 22:31:06 +0100 Subject: [PATCH] feat: add override by alias support --- CHANGELOG.md | 1 + src/cli/install.rs | 8 ++++--- src/cli/mod.rs | 47 ++++++++++++++++++++++++++++++++++++--- src/manifest/mod.rs | 7 ++++-- src/manifest/overrides.rs | 12 ++++++++++ src/resolver.rs | 24 +++++++++++++++----- 6 files changed, 86 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d9c95..ffe3705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - Improve installation experience by @lukadev-0 +- Support using aliases of own dependencies for overrides by @daimond113 ### Performance - Use `Arc` for more efficient cloning of multiple structs by @daimond113 diff --git a/src/cli/install.rs b/src/cli/install.rs index 69403ca..7e84452 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -20,7 +20,7 @@ use tokio::task::JoinSet; use crate::cli::{ bin_dir, reporters::{self, CliReporter}, - run_on_workspace_members, up_to_date_lockfile, + resolve_overrides, run_on_workspace_members, up_to_date_lockfile, }; use super::files::make_executable; @@ -198,7 +198,7 @@ pub async fn install( } else { match project.deser_lockfile().await { Ok(lockfile) => { - if lockfile.overrides != manifest.overrides { + if lockfile.overrides != resolve_overrides(&manifest)? { tracing::debug!("overrides are different"); None } else if lockfile.target != manifest.target.kind() { @@ -217,6 +217,8 @@ pub async fn install( } }; + let overrides = resolve_overrides(&manifest)?; + let (new_lockfile, old_graph) = reporters::run_with_reporter(|_, root_progress, reporter| async { let root_progress = root_progress; @@ -323,7 +325,7 @@ pub async fn install( name: manifest.name.clone(), version: manifest.version, target: manifest.target.kind(), - overrides: manifest.overrides, + overrides, graph: downloaded_graph, diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 8e27e6a..4faf068 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -4,9 +4,16 @@ use fs_err::tokio as fs; use futures::StreamExt; use pesde::{ lockfile::Lockfile, - manifest::target::TargetKind, + manifest::{ + overrides::{OverrideKey, OverrideSpecifier}, + target::TargetKind, + Manifest, + }, names::{PackageName, PackageNames}, - source::{version_id::VersionId, workspace::specifier::VersionTypeOrReq}, + source::{ + specifiers::DependencySpecifiers, version_id::VersionId, + workspace::specifier::VersionTypeOrReq, + }, Project, }; use relative_path::RelativePathBuf; @@ -44,6 +51,40 @@ pub async fn bin_dir() -> anyhow::Result { Ok(bin_dir) } +pub fn resolve_overrides( + manifest: &Manifest, +) -> anyhow::Result> { + let mut dependencies = None; + let mut overrides = BTreeMap::new(); + + for (key, spec) in &manifest.overrides { + overrides.insert( + key.clone(), + match spec { + OverrideSpecifier::Specifier(spec) => spec, + OverrideSpecifier::Alias(alias) => { + if dependencies.is_none() { + dependencies = Some( + manifest + .all_dependencies() + .context("failed to get all dependencies")?, + ); + } + + &dependencies + .as_ref() + .and_then(|deps| deps.get(alias)) + .with_context(|| format!("alias `{alias}` not found in manifest"))? + .0 + } + } + .clone(), + ); + } + + Ok(overrides) +} + #[instrument(skip(project), ret(level = "trace"), level = "debug")] pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result> { let manifest = project.deser_manifest().await?; @@ -57,7 +98,7 @@ pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result return Err(e.into()), }; - if manifest.overrides != lockfile.overrides { + if resolve_overrides(&manifest)? != lockfile.overrides { tracing::debug!("overrides are different"); return Ok(None); } diff --git a/src/manifest/mod.rs b/src/manifest/mod.rs index 638c008..d801e4a 100644 --- a/src/manifest/mod.rs +++ b/src/manifest/mod.rs @@ -1,5 +1,8 @@ use crate::{ - manifest::{overrides::OverrideKey, target::Target}, + manifest::{ + overrides::{OverrideKey, OverrideSpecifier}, + target::Target, + }, names::PackageName, source::specifiers::DependencySpecifiers, }; @@ -58,7 +61,7 @@ pub struct Manifest { pub wally_indices: BTreeMap, /// The overrides this package has #[serde(default, skip_serializing)] - pub overrides: BTreeMap, + pub overrides: BTreeMap, /// The files to include in the package #[serde(default)] pub includes: Vec, diff --git a/src/manifest/overrides.rs b/src/manifest/overrides.rs index 8f8c1e4..23798f1 100644 --- a/src/manifest/overrides.rs +++ b/src/manifest/overrides.rs @@ -1,3 +1,5 @@ +use crate::source::specifiers::DependencySpecifiers; +use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; use std::{ fmt::{Display, Formatter}, @@ -47,6 +49,16 @@ impl Display for OverrideKey { } } +/// A specifier for an override +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum OverrideSpecifier { + /// A specifier for a dependency + Specifier(DependencySpecifiers), + /// An alias for a dependency the current project depends on + Alias(String), +} + /// Errors that can occur when interacting with override keys pub mod errors { use thiserror::Error; diff --git a/src/resolver.rs b/src/resolver.rs index d9f447f..441d3ae 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -1,6 +1,6 @@ use crate::{ lockfile::{DependencyGraph, DependencyGraphNode}, - manifest::DependencyType, + manifest::{overrides::OverrideSpecifier, DependencyType}, names::PackageNames, source::{ pesde::PesdePackageSource, @@ -72,9 +72,12 @@ impl Project { .await .map_err(|e| Box::new(e.into()))?; - let mut all_specifiers = manifest + let all_current_dependencies = manifest .all_dependencies() - .map_err(|e| Box::new(e.into()))? + .map_err(|e| Box::new(e.into()))?; + + let mut all_specifiers = all_current_dependencies + .clone() .into_iter() .map(|(alias, (spec, ty))| ((spec, ty), alias)) .collect::>(); @@ -171,7 +174,7 @@ impl Project { spec, ty, None::<(PackageNames, VersionId)>, - vec![alias.to_string()], + vec![alias], false, manifest.target.kind(), ) @@ -384,7 +387,14 @@ impl Project { } queue.push_back(( - overridden.cloned().unwrap_or(dependency_spec), + match overridden { + Some(OverrideSpecifier::Specifier(spec)) => spec.clone(), + Some(OverrideSpecifier::Alias(alias)) => all_current_dependencies.get(alias) + .map(|(spec, _)| spec) + .ok_or_else(|| errors::DependencyGraphError::AliasNotFound(alias.clone()))? + .clone(), + None => dependency_spec, + }, dependency_ty, Some((name.clone(), target_version_id.clone())), path.iter() @@ -454,5 +464,9 @@ pub mod errors { /// No matching version was found for a specifier #[error("no matching version found for {0}")] NoMatchingVersion(String), + + /// An alias for an override was not found in the manifest + #[error("alias `{0}` not found in manifest")] + AliasNotFound(String), } }