feat: add override by alias support

This commit is contained in:
daimond113 2024-12-29 22:31:06 +01:00
parent 2936f88a99
commit 2aeee9de34
No known key found for this signature in database
GPG key ID: 3A8ECE51328B513C
6 changed files with 86 additions and 13 deletions

View file

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- Improve installation experience by @lukadev-0 - Improve installation experience by @lukadev-0
- Support using aliases of own dependencies for overrides by @daimond113
### Performance ### Performance
- Use `Arc` for more efficient cloning of multiple structs by @daimond113 - Use `Arc` for more efficient cloning of multiple structs by @daimond113

View file

@ -20,7 +20,7 @@ use tokio::task::JoinSet;
use crate::cli::{ use crate::cli::{
bin_dir, bin_dir,
reporters::{self, CliReporter}, 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; use super::files::make_executable;
@ -198,7 +198,7 @@ pub async fn install(
} else { } else {
match project.deser_lockfile().await { match project.deser_lockfile().await {
Ok(lockfile) => { Ok(lockfile) => {
if lockfile.overrides != manifest.overrides { if lockfile.overrides != resolve_overrides(&manifest)? {
tracing::debug!("overrides are different"); tracing::debug!("overrides are different");
None None
} else if lockfile.target != manifest.target.kind() { } 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) = let (new_lockfile, old_graph) =
reporters::run_with_reporter(|_, root_progress, reporter| async { reporters::run_with_reporter(|_, root_progress, reporter| async {
let root_progress = root_progress; let root_progress = root_progress;
@ -323,7 +325,7 @@ pub async fn install(
name: manifest.name.clone(), name: manifest.name.clone(),
version: manifest.version, version: manifest.version,
target: manifest.target.kind(), target: manifest.target.kind(),
overrides: manifest.overrides, overrides,
graph: downloaded_graph, graph: downloaded_graph,

View file

@ -4,9 +4,16 @@ use fs_err::tokio as fs;
use futures::StreamExt; use futures::StreamExt;
use pesde::{ use pesde::{
lockfile::Lockfile, lockfile::Lockfile,
manifest::target::TargetKind, manifest::{
overrides::{OverrideKey, OverrideSpecifier},
target::TargetKind,
Manifest,
},
names::{PackageName, PackageNames}, names::{PackageName, PackageNames},
source::{version_id::VersionId, workspace::specifier::VersionTypeOrReq}, source::{
specifiers::DependencySpecifiers, version_id::VersionId,
workspace::specifier::VersionTypeOrReq,
},
Project, Project,
}; };
use relative_path::RelativePathBuf; use relative_path::RelativePathBuf;
@ -44,6 +51,40 @@ pub async fn bin_dir() -> anyhow::Result<PathBuf> {
Ok(bin_dir) Ok(bin_dir)
} }
pub fn resolve_overrides(
manifest: &Manifest,
) -> anyhow::Result<BTreeMap<OverrideKey, DependencySpecifiers>> {
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")] #[instrument(skip(project), ret(level = "trace"), level = "debug")]
pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result<Option<Lockfile>> { pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result<Option<Lockfile>> {
let manifest = project.deser_manifest().await?; let manifest = project.deser_manifest().await?;
@ -57,7 +98,7 @@ pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result<Option<Loc
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };
if manifest.overrides != lockfile.overrides { if resolve_overrides(&manifest)? != lockfile.overrides {
tracing::debug!("overrides are different"); tracing::debug!("overrides are different");
return Ok(None); return Ok(None);
} }

View file

@ -1,5 +1,8 @@
use crate::{ use crate::{
manifest::{overrides::OverrideKey, target::Target}, manifest::{
overrides::{OverrideKey, OverrideSpecifier},
target::Target,
},
names::PackageName, names::PackageName,
source::specifiers::DependencySpecifiers, source::specifiers::DependencySpecifiers,
}; };
@ -58,7 +61,7 @@ pub struct Manifest {
pub wally_indices: BTreeMap<String, gix::Url>, pub wally_indices: BTreeMap<String, gix::Url>,
/// The overrides this package has /// The overrides this package has
#[serde(default, skip_serializing)] #[serde(default, skip_serializing)]
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>, pub overrides: BTreeMap<OverrideKey, OverrideSpecifier>,
/// The files to include in the package /// The files to include in the package
#[serde(default)] #[serde(default)]
pub includes: Vec<String>, pub includes: Vec<String>,

View file

@ -1,3 +1,5 @@
use crate::source::specifiers::DependencySpecifiers;
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay}; use serde_with::{DeserializeFromStr, SerializeDisplay};
use std::{ use std::{
fmt::{Display, Formatter}, 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 /// Errors that can occur when interacting with override keys
pub mod errors { pub mod errors {
use thiserror::Error; use thiserror::Error;

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
lockfile::{DependencyGraph, DependencyGraphNode}, lockfile::{DependencyGraph, DependencyGraphNode},
manifest::DependencyType, manifest::{overrides::OverrideSpecifier, DependencyType},
names::PackageNames, names::PackageNames,
source::{ source::{
pesde::PesdePackageSource, pesde::PesdePackageSource,
@ -72,9 +72,12 @@ impl Project {
.await .await
.map_err(|e| Box::new(e.into()))?; .map_err(|e| Box::new(e.into()))?;
let mut all_specifiers = manifest let all_current_dependencies = manifest
.all_dependencies() .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() .into_iter()
.map(|(alias, (spec, ty))| ((spec, ty), alias)) .map(|(alias, (spec, ty))| ((spec, ty), alias))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
@ -171,7 +174,7 @@ impl Project {
spec, spec,
ty, ty,
None::<(PackageNames, VersionId)>, None::<(PackageNames, VersionId)>,
vec![alias.to_string()], vec![alias],
false, false,
manifest.target.kind(), manifest.target.kind(),
) )
@ -384,7 +387,14 @@ impl Project {
} }
queue.push_back(( 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, dependency_ty,
Some((name.clone(), target_version_id.clone())), Some((name.clone(), target_version_id.clone())),
path.iter() path.iter()
@ -454,5 +464,9 @@ pub mod errors {
/// No matching version was found for a specifier /// No matching version was found for a specifier
#[error("no matching version found for {0}")] #[error("no matching version found for {0}")]
NoMatchingVersion(String), NoMatchingVersion(String),
/// An alias for an override was not found in the manifest
#[error("alias `{0}` not found in manifest")]
AliasNotFound(String),
} }
} }