feat: add path param in git specifiers

This commit is contained in:
daimond113 2024-09-03 16:47:38 +02:00
parent f1ce6283d8
commit 5236be53fd
No known key found for this signature in database
GPG key ID: 3A8ECE51328B513C
4 changed files with 135 additions and 18 deletions

View file

@ -108,6 +108,7 @@ impl AddCommand {
DependencySpecifiers::Git(GitDependencySpecifier { DependencySpecifiers::Git(GitDependencySpecifier {
repo: url.clone(), repo: url.clone(),
rev: rev.to_string(), rev: rev.to_string(),
path: None,
}), }),
), ),
}; };

View file

@ -17,7 +17,7 @@ use crate::{
PackageSource, ResolveResult, VersionId, IGNORED_DIRS, IGNORED_FILES, PackageSource, ResolveResult, VersionId, IGNORED_DIRS, IGNORED_FILES,
}, },
util::hash, util::hash,
Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME, Project, DEFAULT_INDEX_NAME, LOCKFILE_FILE_NAME, MANIFEST_FILE_NAME,
}; };
/// The Git package reference /// The Git package reference
@ -83,7 +83,10 @@ impl PackageSource for GitPackageSource {
e, e,
) )
})?; })?;
let tree = rev
// TODO: possibly use the search algorithm from src/main.rs to find the workspace root
let root_tree = rev
.object() .object()
.map_err(|e| { .map_err(|e| {
errors::ResolveError::ParseRevToObject(Box::new(self.repo_url.clone()), e) errors::ResolveError::ParseRevToObject(Box::new(self.repo_url.clone()), e)
@ -93,6 +96,36 @@ impl PackageSource for GitPackageSource {
errors::ResolveError::ParseObjectToTree(Box::new(self.repo_url.clone()), e) errors::ResolveError::ParseObjectToTree(Box::new(self.repo_url.clone()), e)
})?; })?;
let tree = if let Some(path) = &specifier.path {
let mut buf = vec![];
root_tree
.lookup_entry_by_path(path.as_str(), &mut buf)
.map_err(|e| {
errors::ResolveError::ReadTreeEntry(
Box::new(self.repo_url.clone()),
path.clone(),
e,
)
})?
.ok_or_else(|| {
errors::ResolveError::NoEntryAtPath(
Box::new(self.repo_url.clone()),
path.clone(),
)
})?
.object()
.map_err(|e| {
errors::ResolveError::ParseEntryToObject(Box::new(self.repo_url.clone()), e)
})?
.peel_to_tree()
.map_err(|e| {
errors::ResolveError::ParseObjectToTree(Box::new(self.repo_url.clone()), e)
})?
} else {
root_tree.clone()
};
let manifest = match self let manifest = match self
.read_file([MANIFEST_FILE_NAME], project, Some(tree.clone())) .read_file([MANIFEST_FILE_NAME], project, Some(tree.clone()))
.map_err(|e| errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e))? .map_err(|e| errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e))?
@ -162,7 +195,54 @@ impl PackageSource for GitPackageSource {
); );
} }
DependencySpecifiers::Git(_) => {} DependencySpecifiers::Git(_) => {}
DependencySpecifiers::Workspace(_) => todo!(), DependencySpecifiers::Workspace(specifier) => {
let lockfile = self
.read_file(
[LOCKFILE_FILE_NAME],
project,
Some(root_tree.clone()),
)
.map_err(|e| {
errors::ResolveError::ReadLockfile(
Box::new(self.repo_url.clone()),
e,
)
})?;
let lockfile = match lockfile {
Some(l) => match toml::from_str::<crate::Lockfile>(&l) {
Ok(l) => l,
Err(e) => {
return Err(errors::ResolveError::DeserLockfile(
Box::new(self.repo_url.clone()),
e,
))
}
},
None => {
return Err(errors::ResolveError::NoLockfile(Box::new(
self.repo_url.clone(),
)))
}
};
let path = lockfile
.workspace
.get(&specifier.name)
.ok_or_else(|| {
errors::ResolveError::NoPathForWorkspaceMember(
specifier.name.to_string(),
Box::new(self.repo_url.clone()),
)
})?
.clone();
spec = DependencySpecifiers::Git(GitDependencySpecifier {
repo: self.repo_url.clone(),
rev: rev.to_string(),
path: Some(path),
})
}
} }
Ok((alias, (spec, ty))) Ok((alias, (spec, ty)))
@ -177,7 +257,7 @@ impl PackageSource for GitPackageSource {
#[cfg(feature = "wally-compat")] #[cfg(feature = "wally-compat")]
None => { None => {
match self match self
.read_file(["wally.toml"], project, Some(tree)) .read_file(["wally.toml"], project, Some(tree.clone()))
.map_err(|e| { .map_err(|e| {
errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e) errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e)
})? { })? {
@ -228,7 +308,7 @@ impl PackageSource for GitPackageSource {
version_id, version_id,
GitPackageRef { GitPackageRef {
repo: self.repo_url.clone(), repo: self.repo_url.clone(),
rev: rev.to_string(), tree_id: tree.id.to_string(),
target, target,
new_structure, new_structure,
dependencies, dependencies,
@ -247,15 +327,14 @@ impl PackageSource for GitPackageSource {
.cas_dir .cas_dir
.join("git_index") .join("git_index")
.join(hash(self.as_bytes())) .join(hash(self.as_bytes()))
.join(&pkg_ref.rev) .join(&pkg_ref.tree_id);
.join(pkg_ref.target.to_string());
match std::fs::read_to_string(&index_file) { match std::fs::read_to_string(&index_file) {
Ok(s) => { Ok(s) => {
log::debug!( log::debug!(
"using cached index file for package {}#{} {}", "using cached index file for package {}#{} {}",
pkg_ref.repo, pkg_ref.repo,
pkg_ref.rev, pkg_ref.tree_id,
pkg_ref.target pkg_ref.target
); );
@ -310,10 +389,10 @@ impl PackageSource for GitPackageSource {
let repo = gix::open(self.path(project)) let repo = gix::open(self.path(project))
.map_err(|e| errors::DownloadError::OpenRepo(Box::new(self.repo_url.clone()), e))?; .map_err(|e| errors::DownloadError::OpenRepo(Box::new(self.repo_url.clone()), e))?;
let rev = repo let rev = repo
.rev_parse_single(BStr::new(&pkg_ref.rev)) .rev_parse_single(BStr::new(&pkg_ref.tree_id))
.map_err(|e| { .map_err(|e| {
errors::DownloadError::ParseRev( errors::DownloadError::ParseRev(
pkg_ref.rev.clone(), pkg_ref.tree_id.clone(),
Box::new(self.repo_url.clone()), Box::new(self.repo_url.clone()),
e, e,
) )
@ -449,8 +528,8 @@ pub mod errors {
#[error("error parsing object to tree for repository {0}")] #[error("error parsing object to tree for repository {0}")]
ParseObjectToTree(Box<gix::Url>, #[source] gix::object::peel::to_kind::Error), ParseObjectToTree(Box<gix::Url>, #[source] gix::object::peel::to_kind::Error),
/// An error occurred reading repository file /// An error occurred reading the manifest
#[error("error reading repository {0} file")] #[error("error reading manifest of repository {0}")]
ReadManifest( ReadManifest(
Box<gix::Url>, Box<gix::Url>,
#[source] crate::source::git_index::errors::ReadFile, #[source] crate::source::git_index::errors::ReadFile,
@ -478,6 +557,41 @@ pub mod errors {
/// A Wally index was not found in the manifest /// A Wally index was not found in the manifest
#[error("wally index {0} not found in manifest for repository {1}")] #[error("wally index {0} not found in manifest for repository {1}")]
WallyIndexNotFound(String, Box<gix::Url>), WallyIndexNotFound(String, Box<gix::Url>),
/// An error occurred reading a tree entry
#[error("error reading tree entry for repository {0} at {1}")]
ReadTreeEntry(
Box<gix::Url>,
RelativePathBuf,
#[source] gix::object::find::existing::Error,
),
/// No entry was found at the specified path
#[error("no entry found at path {1} in repository {0}")]
NoEntryAtPath(Box<gix::Url>, RelativePathBuf),
/// An error occurred parsing an entry to object
#[error("error parsing an entry to object for repository {0}")]
ParseEntryToObject(Box<gix::Url>, #[source] gix::object::find::existing::Error),
/// An error occurred reading the lockfile
#[error("error reading lockfile for repository {0}")]
ReadLockfile(
Box<gix::Url>,
#[source] crate::source::git_index::errors::ReadFile,
),
/// An error occurred while deserializing the lockfile
#[error("error deserializing lockfile for repository {0}")]
DeserLockfile(Box<gix::Url>, #[source] toml::de::Error),
/// The repository is missing a lockfile
#[error("no lockfile found in repository {0}")]
NoLockfile(Box<gix::Url>),
/// No path for a workspace member was found in the lockfile
#[error("no path found for workspace member {0} in lockfile for repository {1}")]
NoPathForWorkspaceMember(String, Box<gix::Url>),
} }
/// Errors that can occur when downloading a package from a Git package source /// Errors that can occur when downloading a package from a Git package source

View file

@ -1,6 +1,5 @@
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::{ use crate::{
manifest::{target::TargetKind, DependencyType}, manifest::{target::TargetKind, DependencyType},
@ -16,8 +15,8 @@ pub struct GitPackageRef {
deserialize_with = "crate::util::deserialize_gix_url" deserialize_with = "crate::util::deserialize_gix_url"
)] )]
pub repo: gix::Url, pub repo: gix::Url,
/// The revision of the package /// The id of the package's tree
pub rev: String, pub tree_id: String,
/// The dependencies of the package /// The dependencies of the package
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")] #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>, pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,

View file

@ -1,6 +1,6 @@
use std::fmt::Display; use relative_path::RelativePathBuf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Display;
use crate::source::DependencySpecifier; use crate::source::DependencySpecifier;
@ -15,6 +15,9 @@ pub struct GitDependencySpecifier {
pub repo: gix::Url, pub repo: gix::Url,
/// The revision of the package /// The revision of the package
pub rev: String, pub rev: String,
/// The path of the package in the repository
#[serde(default, skip_serializing_if = "Option::is_none")]
pub path: Option<RelativePathBuf>,
} }
impl DependencySpecifier for GitDependencySpecifier {} impl DependencySpecifier for GitDependencySpecifier {}