mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: implement git dependency support
This commit is contained in:
parent
d8db84a751
commit
79bbe11cab
23 changed files with 647 additions and 46 deletions
|
@ -72,7 +72,7 @@ pub async fn get_package_version(
|
||||||
let versions: IndexFile = {
|
let versions: IndexFile = {
|
||||||
let source = app_state.source.lock().unwrap();
|
let source = app_state.source.lock().unwrap();
|
||||||
|
|
||||||
match source.read_file([scope, name_part], &app_state.project)? {
|
match source.read_file([scope, name_part], &app_state.project, None)? {
|
||||||
Some(versions) => toml::de::from_str(&versions)?,
|
Some(versions) => toml::de::from_str(&versions)?,
|
||||||
None => return Ok(HttpResponse::NotFound().finish()),
|
None => return Ok(HttpResponse::NotFound().finish()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ pub async fn get_package_versions(
|
||||||
let (scope, name_part) = name.as_str();
|
let (scope, name_part) = name.as_str();
|
||||||
|
|
||||||
let source = app_state.source.lock().unwrap();
|
let source = app_state.source.lock().unwrap();
|
||||||
let versions: IndexFile = match source.read_file([scope, name_part], &app_state.project)? {
|
let versions: IndexFile =
|
||||||
|
match source.read_file([scope, name_part], &app_state.project, None)? {
|
||||||
Some(versions) => toml::de::from_str(&versions)?,
|
Some(versions) => toml::de::from_str(&versions)?,
|
||||||
None => return Ok(HttpResponse::NotFound().finish()),
|
None => return Ok(HttpResponse::NotFound().finish()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub async fn publish_package(
|
||||||
|
|
||||||
let (dep_scope, dep_name) = specifier.name.as_str();
|
let (dep_scope, dep_name) = specifier.name.as_str();
|
||||||
if source
|
if source
|
||||||
.read_file([dep_scope, dep_name], &app_state.project)?
|
.read_file([dep_scope, dep_name], &app_state.project, None)?
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
return Err(Error::InvalidArchive);
|
return Err(Error::InvalidArchive);
|
||||||
|
@ -153,6 +153,11 @@ pub async fn publish_package(
|
||||||
return Err(Error::InvalidArchive);
|
return Err(Error::InvalidArchive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DependencySpecifiers::Git(_) => {
|
||||||
|
if !config.git_allowed {
|
||||||
|
return Err(Error::InvalidArchive);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +166,7 @@ pub async fn publish_package(
|
||||||
let (scope, name) = manifest.name.as_str();
|
let (scope, name) = manifest.name.as_str();
|
||||||
let mut oids = vec![];
|
let mut oids = vec![];
|
||||||
|
|
||||||
match source.read_file([scope, SCOPE_INFO_FILE], &app_state.project)? {
|
match source.read_file([scope, SCOPE_INFO_FILE], &app_state.project, None)? {
|
||||||
Some(info) => {
|
Some(info) => {
|
||||||
let info: ScopeInfo = toml::de::from_str(&info)?;
|
let info: ScopeInfo = toml::de::from_str(&info)?;
|
||||||
if !info.owners.contains(&user_id.0) {
|
if !info.owners.contains(&user_id.0) {
|
||||||
|
@ -181,7 +186,7 @@ pub async fn publish_package(
|
||||||
|
|
||||||
let mut entries: IndexFile = toml::de::from_str(
|
let mut entries: IndexFile = toml::de::from_str(
|
||||||
&source
|
&source
|
||||||
.read_file([scope, name], &app_state.project)?
|
.read_file([scope, name], &app_state.project, None)?
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub async fn search_packages(
|
||||||
|
|
||||||
let mut versions: IndexFile = toml::de::from_str(
|
let mut versions: IndexFile = toml::de::from_str(
|
||||||
&source
|
&source
|
||||||
.read_file([scope, name], &app_state.project)
|
.read_file([scope, name], &app_state.project, None)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -181,6 +181,9 @@ impl AddCommand {
|
||||||
dependency_key
|
dependency_key
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
DependencySpecifiers::Git(_) => {
|
||||||
|
unreachable!("git dependencies are not supported in the add command");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
project
|
project
|
||||||
|
|
|
@ -35,6 +35,10 @@ impl OutdatedCommand {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if matches!(specifier, DependencySpecifiers::Git(_)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let source = node.node.pkg_ref.source();
|
let source = node.node.pkg_ref.source();
|
||||||
|
|
||||||
if refreshed_sources.insert(source.clone()) {
|
if refreshed_sources.insert(source.clone()) {
|
||||||
|
@ -50,6 +54,7 @@ impl OutdatedCommand {
|
||||||
DependencySpecifiers::Wally(ref mut spec) => {
|
DependencySpecifiers::Wally(ref mut spec) => {
|
||||||
spec.version = VersionReq::STAR;
|
spec.version = VersionReq::STAR;
|
||||||
}
|
}
|
||||||
|
DependencySpecifiers::Git(_) => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ impl Project {
|
||||||
let (fs, target) = match source.download(&node.pkg_ref, &project, &reqwest) {
|
let (fs, target) = match source.download(&node.pkg_ref, &project, &reqwest) {
|
||||||
Ok(target) => target,
|
Ok(target) => target,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tx.send(Err(e.into())).unwrap();
|
tx.send(Err(Box::new(e).into())).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -124,7 +124,7 @@ pub mod errors {
|
||||||
|
|
||||||
/// Error downloading a package
|
/// Error downloading a package
|
||||||
#[error("failed to download package")]
|
#[error("failed to download package")]
|
||||||
DownloadFailed(#[from] crate::source::errors::DownloadError),
|
DownloadFailed(#[from] Box<crate::source::errors::DownloadError>),
|
||||||
|
|
||||||
/// Error writing package contents
|
/// Error writing package contents
|
||||||
#[error("failed to write package contents")]
|
#[error("failed to write package contents")]
|
||||||
|
|
|
@ -88,7 +88,7 @@ impl Project {
|
||||||
|
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
if let Some(Target::Roblox { build_files, .. }) =
|
if let Some(Target::Roblox { build_files, .. }) =
|
||||||
Some(&node.target).filter(|_| !node.node.pkg_ref.is_wally())
|
Some(&node.target).filter(|_| !node.node.pkg_ref.like_wally())
|
||||||
{
|
{
|
||||||
let script_name = ScriptName::RobloxSyncConfigGenerator.to_string();
|
let script_name = ScriptName::RobloxSyncConfigGenerator.to_string();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
names::PackageNames,
|
names::PackageNames,
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
|
refs::PackageRefs,
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{PackageRef, PackageSource},
|
traits::{PackageRef, PackageSource},
|
||||||
version_id::VersionId,
|
version_id::VersionId,
|
||||||
|
@ -176,6 +177,9 @@ impl Project {
|
||||||
|
|
||||||
PackageSources::Wally(crate::source::wally::WallyPackageSource::new(index_url))
|
PackageSources::Wally(crate::source::wally::WallyPackageSource::new(index_url))
|
||||||
}
|
}
|
||||||
|
DependencySpecifiers::Git(specifier) => PackageSources::Git(
|
||||||
|
crate::source::git::GitPackageSource::new(specifier.repo.clone()),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
if refreshed_sources.insert(source.clone()) {
|
if refreshed_sources.insert(source.clone()) {
|
||||||
|
@ -219,6 +223,8 @@ impl Project {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pkg_ref = &resolved[&target_version_id];
|
||||||
|
|
||||||
if let Some(already_resolved) = graph
|
if let Some(already_resolved) = graph
|
||||||
.get_mut(&name)
|
.get_mut(&name)
|
||||||
.and_then(|versions| versions.get_mut(&target_version_id))
|
.and_then(|versions| versions.get_mut(&target_version_id))
|
||||||
|
@ -230,6 +236,14 @@ impl Project {
|
||||||
target_version_id
|
target_version_id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if matches!(already_resolved.pkg_ref, PackageRefs::Git(_))
|
||||||
|
!= matches!(pkg_ref, PackageRefs::Git(_))
|
||||||
|
{
|
||||||
|
log::warn!(
|
||||||
|
"resolved package {name}@{target_version_id} has a different source than the previously resolved one, this may cause issues",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if already_resolved.ty == DependencyType::Peer && ty == DependencyType::Standard {
|
if already_resolved.ty == DependencyType::Peer && ty == DependencyType::Standard {
|
||||||
already_resolved.ty = ty;
|
already_resolved.ty = ty;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +251,6 @@ impl Project {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pkg_ref = &resolved[&target_version_id];
|
|
||||||
let node = DependencyGraphNode {
|
let node = DependencyGraphNode {
|
||||||
direct: if depth == 0 {
|
direct: if depth == 0 {
|
||||||
Some((alias.clone(), specifier.clone()))
|
Some((alias.clone(), specifier.clone()))
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>
|
||||||
.arg("--")
|
.arg("--")
|
||||||
.args(args)
|
.args(args)
|
||||||
.current_dir(cwd)
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::inherit())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
|
466
src/source/git/mod.rs
Normal file
466
src/source/git/mod.rs
Normal file
|
@ -0,0 +1,466 @@
|
||||||
|
use std::{collections::BTreeMap, fmt::Debug, hash::Hash, path::PathBuf};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
manifest::{
|
||||||
|
target::{Target, TargetKind},
|
||||||
|
Manifest,
|
||||||
|
},
|
||||||
|
names::PackageNames,
|
||||||
|
source::{
|
||||||
|
fs::{store_in_cas, FSEntry, PackageFS},
|
||||||
|
git::{pkg_ref::GitPackageRef, specifier::GitDependencySpecifier},
|
||||||
|
git_index::GitBasedSource,
|
||||||
|
PackageSource, ResolveResult, VersionId,
|
||||||
|
},
|
||||||
|
util::hash,
|
||||||
|
Project, MANIFEST_FILE_NAME,
|
||||||
|
};
|
||||||
|
use gix::{bstr::BStr, traverse::tree::Recorder, Url};
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
|
/// The Git package reference
|
||||||
|
pub mod pkg_ref;
|
||||||
|
/// The Git dependency specifier
|
||||||
|
pub mod specifier;
|
||||||
|
|
||||||
|
/// The Git package source
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
|
pub struct GitPackageSource {
|
||||||
|
repo_url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GitBasedSource for GitPackageSource {
|
||||||
|
fn path(&self, project: &Project) -> PathBuf {
|
||||||
|
project
|
||||||
|
.data_dir
|
||||||
|
.join("git_repos")
|
||||||
|
.join(hash(self.as_bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repo_url(&self) -> &Url {
|
||||||
|
&self.repo_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GitPackageSource {
|
||||||
|
/// Creates a new Git package source
|
||||||
|
pub fn new(repo_url: Url) -> Self {
|
||||||
|
Self { repo_url }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_bytes(&self) -> Vec<u8> {
|
||||||
|
self.repo_url.to_bstring().to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PackageSource for GitPackageSource {
|
||||||
|
type Specifier = GitDependencySpecifier;
|
||||||
|
type Ref = GitPackageRef;
|
||||||
|
type RefreshError = crate::source::git_index::errors::RefreshError;
|
||||||
|
type ResolveError = errors::ResolveError;
|
||||||
|
type DownloadError = errors::DownloadError;
|
||||||
|
|
||||||
|
fn refresh(&self, project: &Project) -> Result<(), Self::RefreshError> {
|
||||||
|
GitBasedSource::refresh(self, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(
|
||||||
|
&self,
|
||||||
|
specifier: &Self::Specifier,
|
||||||
|
project: &Project,
|
||||||
|
_project_target: TargetKind,
|
||||||
|
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError> {
|
||||||
|
let repo = gix::open(self.path(project))
|
||||||
|
.map_err(|e| errors::ResolveError::OpenRepo(Box::new(self.repo_url.clone()), e))?;
|
||||||
|
let rev = repo
|
||||||
|
.rev_parse_single(BStr::new(&specifier.rev))
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::ResolveError::ParseRev(
|
||||||
|
specifier.rev.clone(),
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let tree = rev
|
||||||
|
.object()
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::ResolveError::ParseRevToObject(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?
|
||||||
|
.peel_to_tree()
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::ResolveError::ParseObjectToTree(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let manifest = match self
|
||||||
|
.read_file([MANIFEST_FILE_NAME], project, Some(tree.clone()))
|
||||||
|
.map_err(|e| errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e))?
|
||||||
|
{
|
||||||
|
Some(m) => match toml::from_str::<Manifest>(&m) {
|
||||||
|
Ok(m) => Some(m),
|
||||||
|
Err(e) => {
|
||||||
|
return Err(errors::ResolveError::DeserManifest(
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (name, version_id, dependencies) = match manifest {
|
||||||
|
Some(manifest) => {
|
||||||
|
let dependencies = manifest.all_dependencies().map_err(|e| {
|
||||||
|
errors::ResolveError::CollectDependencies(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?;
|
||||||
|
let name = PackageNames::Pesde(manifest.name);
|
||||||
|
let version_id = VersionId(manifest.version, manifest.target.kind());
|
||||||
|
|
||||||
|
(name, version_id, dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wally-compat")]
|
||||||
|
None => {
|
||||||
|
match self
|
||||||
|
.read_file(["wally.toml"], project, Some(tree))
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e)
|
||||||
|
})? {
|
||||||
|
Some(m) => {
|
||||||
|
match toml::from_str::<crate::source::wally::manifest::WallyManifest>(&m) {
|
||||||
|
Ok(manifest) => {
|
||||||
|
let dependencies = manifest.all_dependencies().map_err(|e| {
|
||||||
|
errors::ResolveError::CollectDependencies(
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let name = PackageNames::Wally(manifest.package.name);
|
||||||
|
let version_id =
|
||||||
|
VersionId(manifest.package.version, TargetKind::Roblox);
|
||||||
|
|
||||||
|
(name, version_id, dependencies)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(errors::ResolveError::DeserManifest(
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(errors::ResolveError::NoManifest(Box::new(
|
||||||
|
self.repo_url.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "wally-compat"))]
|
||||||
|
None => {
|
||||||
|
return Err(errors::ResolveError::NoManifest(Box::new(
|
||||||
|
self.repo_url.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = *version_id.target();
|
||||||
|
let new_structure = matches!(name, PackageNames::Pesde(_));
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
name,
|
||||||
|
BTreeMap::from([(
|
||||||
|
version_id,
|
||||||
|
GitPackageRef {
|
||||||
|
repo: self.repo_url.clone(),
|
||||||
|
rev: rev.to_string(),
|
||||||
|
target,
|
||||||
|
new_structure,
|
||||||
|
dependencies,
|
||||||
|
},
|
||||||
|
)]),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download(
|
||||||
|
&self,
|
||||||
|
pkg_ref: &Self::Ref,
|
||||||
|
project: &Project,
|
||||||
|
_reqwest: &reqwest::blocking::Client,
|
||||||
|
) -> Result<(PackageFS, Target), Self::DownloadError> {
|
||||||
|
let index_file = project
|
||||||
|
.cas_dir
|
||||||
|
.join("git_index")
|
||||||
|
.join(hash(self.as_bytes()))
|
||||||
|
.join(&pkg_ref.rev)
|
||||||
|
.join(pkg_ref.target.to_string());
|
||||||
|
|
||||||
|
match std::fs::read_to_string(&index_file) {
|
||||||
|
Ok(s) => {
|
||||||
|
log::debug!(
|
||||||
|
"using cached index file for package {}#{} {}",
|
||||||
|
pkg_ref.repo,
|
||||||
|
pkg_ref.rev,
|
||||||
|
pkg_ref.target
|
||||||
|
);
|
||||||
|
|
||||||
|
let fs = toml::from_str::<PackageFS>(&s).map_err(|e| {
|
||||||
|
errors::DownloadError::DeserializeFile(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let manifest = match fs.0.get(&RelativePathBuf::from(MANIFEST_FILE_NAME)) {
|
||||||
|
Some(FSEntry::File(hash)) => match fs
|
||||||
|
.read_file(hash, project.cas_dir())
|
||||||
|
.map(|m| toml::de::from_str::<Manifest>(&m))
|
||||||
|
{
|
||||||
|
Some(Ok(m)) => Some(m),
|
||||||
|
Some(Err(e)) => {
|
||||||
|
return Err(errors::DownloadError::DeserializeFile(
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = match manifest {
|
||||||
|
Some(manifest) => manifest.target,
|
||||||
|
#[cfg(feature = "wally-compat")]
|
||||||
|
None if !pkg_ref.new_structure => {
|
||||||
|
let tempdir = tempfile::tempdir()?;
|
||||||
|
fs.write_to(tempdir.path(), project.cas_dir(), false)?;
|
||||||
|
|
||||||
|
crate::source::wally::compat_util::get_target(project, &tempdir)?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(errors::DownloadError::NoManifest(Box::new(
|
||||||
|
self.repo_url.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok((fs, target));
|
||||||
|
}
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
|
||||||
|
Err(e) => return Err(errors::DownloadError::Io(e)),
|
||||||
|
}
|
||||||
|
|
||||||
|
let repo = gix::open(self.path(project))
|
||||||
|
.map_err(|e| errors::DownloadError::OpenRepo(Box::new(self.repo_url.clone()), e))?;
|
||||||
|
let rev = repo
|
||||||
|
.rev_parse_single(BStr::new(&pkg_ref.rev))
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::DownloadError::ParseRev(
|
||||||
|
pkg_ref.rev.clone(),
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let tree = rev
|
||||||
|
.object()
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::DownloadError::ParseEntryToObject(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?
|
||||||
|
.peel_to_tree()
|
||||||
|
.map_err(|e| {
|
||||||
|
errors::DownloadError::ParseObjectToTree(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut recorder = Recorder::default();
|
||||||
|
tree.traverse()
|
||||||
|
.breadthfirst(&mut recorder)
|
||||||
|
.map_err(|e| errors::DownloadError::TraverseTree(Box::new(self.repo_url.clone()), e))?;
|
||||||
|
|
||||||
|
let mut entries = BTreeMap::new();
|
||||||
|
let mut manifest = None;
|
||||||
|
|
||||||
|
for entry in recorder.records {
|
||||||
|
let path = RelativePathBuf::from(entry.filepath.to_string());
|
||||||
|
let object = repo.find_object(entry.oid).map_err(|e| {
|
||||||
|
errors::DownloadError::ParseEntryToObject(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if matches!(object.kind, gix::object::Kind::Tree) {
|
||||||
|
entries.insert(path, FSEntry::Directory);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = object.into_blob().data.clone();
|
||||||
|
let hash = store_in_cas(project.cas_dir(), &data)?.0;
|
||||||
|
|
||||||
|
if path == MANIFEST_FILE_NAME {
|
||||||
|
manifest = Some(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.insert(path, FSEntry::File(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
let manifest = match manifest {
|
||||||
|
Some(data) => match String::from_utf8(data.to_vec()) {
|
||||||
|
Ok(s) => match toml::from_str::<Manifest>(&s) {
|
||||||
|
Ok(m) => Some(m),
|
||||||
|
Err(e) => {
|
||||||
|
return Err(errors::DownloadError::DeserializeFile(
|
||||||
|
Box::new(self.repo_url.clone()),
|
||||||
|
e,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => return Err(errors::DownloadError::ParseManifest(e)),
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let fs = PackageFS(entries);
|
||||||
|
|
||||||
|
let target = match manifest {
|
||||||
|
Some(manifest) => manifest.target,
|
||||||
|
#[cfg(feature = "wally-compat")]
|
||||||
|
None if !pkg_ref.new_structure => {
|
||||||
|
let tempdir = tempfile::tempdir()?;
|
||||||
|
fs.write_to(tempdir.path(), project.cas_dir(), false)?;
|
||||||
|
|
||||||
|
crate::source::wally::compat_util::get_target(project, &tempdir)?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(errors::DownloadError::NoManifest(Box::new(
|
||||||
|
self.repo_url.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(parent) = index_file.parent() {
|
||||||
|
std::fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::write(
|
||||||
|
&index_file,
|
||||||
|
toml::to_string(&fs).map_err(|e| {
|
||||||
|
errors::DownloadError::SerializeIndex(Box::new(self.repo_url.clone()), e)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.map_err(errors::DownloadError::Io)?;
|
||||||
|
|
||||||
|
Ok((fs, target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when interacting with the Git package source
|
||||||
|
pub mod errors {
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when resolving a package from a Git package source
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum ResolveError {
|
||||||
|
/// An error occurred opening the Git repository
|
||||||
|
#[error("error opening Git repository for url {0}")]
|
||||||
|
OpenRepo(Box<gix::Url>, #[source] gix::open::Error),
|
||||||
|
|
||||||
|
/// An error occurred parsing rev
|
||||||
|
#[error("error parsing rev {0} for repository {1}")]
|
||||||
|
ParseRev(
|
||||||
|
String,
|
||||||
|
Box<gix::Url>,
|
||||||
|
#[source] gix::revision::spec::parse::single::Error,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// An error occurred parsing rev to object
|
||||||
|
#[error("error parsing rev to object for repository {0}")]
|
||||||
|
ParseRevToObject(Box<gix::Url>, #[source] gix::object::find::existing::Error),
|
||||||
|
|
||||||
|
/// An error occurred parsing object to tree
|
||||||
|
#[error("error parsing object to tree for repository {0}")]
|
||||||
|
ParseObjectToTree(Box<gix::Url>, #[source] gix::object::peel::to_kind::Error),
|
||||||
|
|
||||||
|
/// An error occurred reading repository file
|
||||||
|
#[error("error reading repository {0} file")]
|
||||||
|
ReadManifest(
|
||||||
|
Box<gix::Url>,
|
||||||
|
#[source] crate::source::git_index::errors::ReadFile,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// An error occurred collecting all manifest dependencies
|
||||||
|
#[error("error collecting all manifest dependencies for repository {0}")]
|
||||||
|
CollectDependencies(
|
||||||
|
Box<gix::Url>,
|
||||||
|
#[source] crate::manifest::errors::AllDependenciesError,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// An error occurred deserializing a manifest
|
||||||
|
#[error("error deserializing manifest for repository {0}")]
|
||||||
|
DeserManifest(Box<gix::Url>, #[source] toml::de::Error),
|
||||||
|
|
||||||
|
/// No manifest was found
|
||||||
|
#[error("no manifest found in repository {0}")]
|
||||||
|
NoManifest(Box<gix::Url>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when downloading a package from a Git package source
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum DownloadError {
|
||||||
|
/// An error occurred deserializing a file
|
||||||
|
#[error("error deserializing file in repository {0}")]
|
||||||
|
DeserializeFile(Box<gix::Url>, #[source] toml::de::Error),
|
||||||
|
|
||||||
|
/// An error occurred interacting with the file system
|
||||||
|
#[error("error interacting with the file system")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// An error occurred while searching for a Wally lib export
|
||||||
|
#[cfg(feature = "wally-compat")]
|
||||||
|
#[error("error searching for Wally lib export")]
|
||||||
|
FindLibPath(#[from] crate::source::wally::compat_util::errors::FindLibPathError),
|
||||||
|
|
||||||
|
/// No manifest was found
|
||||||
|
#[error("no manifest found in repository {0}")]
|
||||||
|
NoManifest(Box<gix::Url>),
|
||||||
|
|
||||||
|
/// An error occurred opening the Git repository
|
||||||
|
#[error("error opening Git repository for url {0}")]
|
||||||
|
OpenRepo(Box<gix::Url>, #[source] gix::open::Error),
|
||||||
|
|
||||||
|
/// An error occurred parsing rev
|
||||||
|
#[error("error parsing rev {0} for repository {1}")]
|
||||||
|
ParseRev(
|
||||||
|
String,
|
||||||
|
Box<gix::Url>,
|
||||||
|
#[source] gix::revision::spec::parse::single::Error,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// An error occurred while traversing the tree
|
||||||
|
#[error("error traversing tree for repository {0}")]
|
||||||
|
TraverseTree(
|
||||||
|
Box<gix::Url>,
|
||||||
|
#[source] gix::traverse::tree::breadthfirst::Error,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// 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 parsing object to tree
|
||||||
|
#[error("error parsing object to tree for repository {0}")]
|
||||||
|
ParseObjectToTree(Box<gix::Url>, #[source] gix::object::peel::to_kind::Error),
|
||||||
|
|
||||||
|
/// An error occurred reading a tree entry
|
||||||
|
#[error("error reading tree entry for repository {0} at {1}")]
|
||||||
|
ReadTreeEntry(
|
||||||
|
Box<gix::Url>,
|
||||||
|
RelativePathBuf,
|
||||||
|
#[source] gix::objs::decode::Error,
|
||||||
|
),
|
||||||
|
|
||||||
|
/// An error occurred parsing the pesde manifest to UTF-8
|
||||||
|
#[error("error parsing the manifest for repository {0} to UTF-8")]
|
||||||
|
ParseManifest(#[source] std::string::FromUtf8Error),
|
||||||
|
|
||||||
|
/// An error occurred while serializing the index file
|
||||||
|
#[error("error serializing the index file for repository {0}")]
|
||||||
|
SerializeIndex(Box<gix::Url>, #[source] toml::ser::Error),
|
||||||
|
}
|
||||||
|
}
|
45
src/source/git/pkg_ref.rs
Normal file
45
src/source/git/pkg_ref.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
manifest::{target::TargetKind, DependencyType},
|
||||||
|
source::{git::GitPackageSource, DependencySpecifiers, PackageRef, PackageSources},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A Git package reference
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||||
|
pub struct GitPackageRef {
|
||||||
|
/// The repository of the package
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "crate::util::serialize_gix_url",
|
||||||
|
deserialize_with = "crate::util::deserialize_gix_url"
|
||||||
|
)]
|
||||||
|
pub repo: gix::Url,
|
||||||
|
/// The revision of the package
|
||||||
|
pub rev: String,
|
||||||
|
/// The dependencies of the package
|
||||||
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
|
pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,
|
||||||
|
/// Whether this package uses the new structure
|
||||||
|
pub new_structure: bool,
|
||||||
|
/// The target of the package
|
||||||
|
pub target: TargetKind,
|
||||||
|
}
|
||||||
|
impl PackageRef for GitPackageRef {
|
||||||
|
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)> {
|
||||||
|
&self.dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_new_structure(&self) -> bool {
|
||||||
|
self.new_structure
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_kind(&self) -> TargetKind {
|
||||||
|
self.target
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> PackageSources {
|
||||||
|
PackageSources::Git(GitPackageSource::new(self.repo.clone()))
|
||||||
|
}
|
||||||
|
}
|
28
src/source/git/specifier.rs
Normal file
28
src/source/git/specifier.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{manifest::target::TargetKind, source::DependencySpecifier};
|
||||||
|
|
||||||
|
/// The specifier for a Git dependency
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct GitDependencySpecifier {
|
||||||
|
/// The repository of the package
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "crate::util::serialize_gix_url",
|
||||||
|
deserialize_with = "crate::util::deserialize_git_like_url"
|
||||||
|
)]
|
||||||
|
pub repo: gix::Url,
|
||||||
|
/// The revision of the package
|
||||||
|
pub rev: String,
|
||||||
|
/// The target to use for the package
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub target: Option<TargetKind>,
|
||||||
|
}
|
||||||
|
impl DependencySpecifier for GitDependencySpecifier {}
|
||||||
|
|
||||||
|
impl Display for GitDependencySpecifier {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}#{}", self.repo, self.rev)
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,6 +64,7 @@ pub trait GitBasedSource {
|
||||||
&self,
|
&self,
|
||||||
file_path: I,
|
file_path: I,
|
||||||
project: &Project,
|
project: &Project,
|
||||||
|
tree: Option<gix::Tree>,
|
||||||
) -> Result<Option<String>, errors::ReadFile> {
|
) -> Result<Option<String>, errors::ReadFile> {
|
||||||
let path = self.path(project);
|
let path = self.path(project);
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ pub trait GitBasedSource {
|
||||||
Err(e) => return Err(errors::ReadFile::Open(path, Box::new(e))),
|
Err(e) => return Err(errors::ReadFile::Open(path, Box::new(e))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tree = match self.tree(&repo) {
|
let tree = match tree.map_or_else(|| self.tree(&repo), Ok) {
|
||||||
Ok(tree) => tree,
|
Ok(tree) => tree,
|
||||||
Err(e) => return Err(errors::ReadFile::Tree(path, Box::new(e))),
|
Err(e) => return Err(errors::ReadFile::Tree(path, Box::new(e))),
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
|
|
||||||
/// Packages' filesystems
|
/// Packages' filesystems
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
/// The Git package source
|
||||||
|
pub mod git;
|
||||||
/// Git index-based package source utilities
|
/// Git index-based package source utilities
|
||||||
pub mod git_index;
|
pub mod git_index;
|
||||||
/// The pesde package source
|
/// The pesde package source
|
||||||
|
@ -39,6 +41,8 @@ pub enum PackageSources {
|
||||||
/// A Wally package source
|
/// A Wally package source
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
Wally(wally::WallyPackageSource),
|
Wally(wally::WallyPackageSource),
|
||||||
|
/// A Git package source
|
||||||
|
Git(git::GitPackageSource),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageSource for PackageSources {
|
impl PackageSource for PackageSources {
|
||||||
|
@ -53,6 +57,7 @@ impl PackageSource for PackageSources {
|
||||||
PackageSources::Pesde(source) => source.refresh(project).map_err(Into::into),
|
PackageSources::Pesde(source) => source.refresh(project).map_err(Into::into),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageSources::Wally(source) => source.refresh(project).map_err(Into::into),
|
PackageSources::Wally(source) => source.refresh(project).map_err(Into::into),
|
||||||
|
PackageSources::Git(source) => source.refresh(project).map_err(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +95,19 @@ impl PackageSource for PackageSources {
|
||||||
})
|
})
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
|
|
||||||
|
(PackageSources::Git(source), DependencySpecifiers::Git(specifier)) => source
|
||||||
|
.resolve(specifier, project, project_target)
|
||||||
|
.map(|(name, results)| {
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
results
|
||||||
|
.into_iter()
|
||||||
|
.map(|(version, pkg_ref)| (version, PackageRefs::Git(pkg_ref)))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(Into::into),
|
||||||
|
|
||||||
_ => Err(errors::ResolveError::Mismatch),
|
_ => Err(errors::ResolveError::Mismatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +128,10 @@ impl PackageSource for PackageSources {
|
||||||
.download(pkg_ref, project, reqwest)
|
.download(pkg_ref, project, reqwest)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
|
|
||||||
|
(PackageSources::Git(source), PackageRefs::Git(pkg_ref)) => source
|
||||||
|
.download(pkg_ref, project, reqwest)
|
||||||
|
.map_err(Into::into),
|
||||||
|
|
||||||
_ => Err(errors::DownloadError::Mismatch),
|
_ => Err(errors::DownloadError::Mismatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,6 +166,10 @@ pub mod errors {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
#[error("error resolving wally package")]
|
#[error("error resolving wally package")]
|
||||||
Wally(#[from] crate::source::wally::errors::ResolveError),
|
Wally(#[from] crate::source::wally::errors::ResolveError),
|
||||||
|
|
||||||
|
/// A Git package source failed to resolve
|
||||||
|
#[error("error resolving git package")]
|
||||||
|
Git(#[from] crate::source::git::errors::ResolveError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur when downloading a package
|
/// Errors that can occur when downloading a package
|
||||||
|
@ -162,5 +188,9 @@ pub mod errors {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
#[error("error downloading wally package")]
|
#[error("error downloading wally package")]
|
||||||
Wally(#[from] crate::source::wally::errors::DownloadError),
|
Wally(#[from] crate::source::wally::errors::DownloadError),
|
||||||
|
|
||||||
|
/// A Git package source failed to download
|
||||||
|
#[error("error downloading git package")]
|
||||||
|
Git(#[from] crate::source::git::errors::DownloadError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,9 @@ impl PesdePackageSource {
|
||||||
|
|
||||||
/// Reads the config file
|
/// Reads the config file
|
||||||
pub fn config(&self, project: &Project) -> Result<IndexConfig, errors::ConfigError> {
|
pub fn config(&self, project: &Project) -> Result<IndexConfig, errors::ConfigError> {
|
||||||
let file = self.read_file(["config.toml"], project).map_err(Box::new)?;
|
let file = self
|
||||||
|
.read_file(["config.toml"], project, None)
|
||||||
|
.map_err(Box::new)?;
|
||||||
|
|
||||||
let string = match file {
|
let string = match file {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
@ -192,7 +194,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
project_target: TargetKind,
|
project_target: TargetKind,
|
||||||
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError> {
|
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError> {
|
||||||
let (scope, name) = specifier.name.as_str();
|
let (scope, name) = specifier.name.as_str();
|
||||||
let string = match self.read_file([scope, name], project) {
|
let string = match self.read_file([scope, name], project, None) {
|
||||||
Ok(Some(s)) => s,
|
Ok(Some(s)) => s,
|
||||||
Ok(None) => return Err(Self::ResolveError::NotFound(specifier.name.to_string())),
|
Ok(None) => return Err(Self::ResolveError::NotFound(specifier.name.to_string())),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
@ -48,15 +48,3 @@ impl PackageRef for PesdePackageRef {
|
||||||
PackageSources::Pesde(PesdePackageSource::new(self.index_url.clone()))
|
PackageSources::Pesde(PesdePackageSource::new(self.index_url.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for PesdePackageRef {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.version.cmp(&other.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for PesdePackageRef {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,14 +14,17 @@ pub enum PackageRefs {
|
||||||
/// A Wally package reference
|
/// A Wally package reference
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
Wally(crate::source::wally::pkg_ref::WallyPackageRef),
|
Wally(crate::source::wally::pkg_ref::WallyPackageRef),
|
||||||
|
/// A Git package reference
|
||||||
|
Git(crate::source::git::pkg_ref::GitPackageRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageRefs {
|
impl PackageRefs {
|
||||||
/// Returns whether this package reference is a Wally package reference
|
/// Returns whether this package reference should be treated as a Wally package
|
||||||
pub fn is_wally(&self) -> bool {
|
pub fn like_wally(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageRefs::Wally(_) => true,
|
PackageRefs::Wally(_) => true,
|
||||||
|
PackageRefs::Git(git) => !git.use_new_structure(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +36,7 @@ impl PackageRef for PackageRefs {
|
||||||
PackageRefs::Pesde(pkg_ref) => pkg_ref.dependencies(),
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.dependencies(),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageRefs::Wally(pkg_ref) => pkg_ref.dependencies(),
|
PackageRefs::Wally(pkg_ref) => pkg_ref.dependencies(),
|
||||||
|
PackageRefs::Git(pkg_ref) => pkg_ref.dependencies(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +45,7 @@ impl PackageRef for PackageRefs {
|
||||||
PackageRefs::Pesde(pkg_ref) => pkg_ref.use_new_structure(),
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.use_new_structure(),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageRefs::Wally(pkg_ref) => pkg_ref.use_new_structure(),
|
PackageRefs::Wally(pkg_ref) => pkg_ref.use_new_structure(),
|
||||||
|
PackageRefs::Git(pkg_ref) => pkg_ref.use_new_structure(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +54,7 @@ impl PackageRef for PackageRefs {
|
||||||
PackageRefs::Pesde(pkg_ref) => pkg_ref.target_kind(),
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.target_kind(),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageRefs::Wally(pkg_ref) => pkg_ref.target_kind(),
|
PackageRefs::Wally(pkg_ref) => pkg_ref.target_kind(),
|
||||||
|
PackageRefs::Git(pkg_ref) => pkg_ref.target_kind(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +63,7 @@ impl PackageRef for PackageRefs {
|
||||||
PackageRefs::Pesde(pkg_ref) => pkg_ref.source(),
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.source(),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
PackageRefs::Wally(pkg_ref) => pkg_ref.source(),
|
PackageRefs::Wally(pkg_ref) => pkg_ref.source(),
|
||||||
|
PackageRefs::Git(pkg_ref) => pkg_ref.source(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ pub enum DependencySpecifiers {
|
||||||
/// A Wally dependency specifier
|
/// A Wally dependency specifier
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
Wally(crate::source::wally::specifier::WallyDependencySpecifier),
|
Wally(crate::source::wally::specifier::WallyDependencySpecifier),
|
||||||
|
/// A Git dependency specifier
|
||||||
|
Git(crate::source::git::specifier::GitDependencySpecifier),
|
||||||
}
|
}
|
||||||
impl DependencySpecifier for DependencySpecifiers {}
|
impl DependencySpecifier for DependencySpecifiers {}
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ impl Display for DependencySpecifiers {
|
||||||
DependencySpecifiers::Pesde(specifier) => write!(f, "{specifier}"),
|
DependencySpecifiers::Pesde(specifier) => write!(f, "{specifier}"),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
DependencySpecifiers::Wally(specifier) => write!(f, "{specifier}"),
|
DependencySpecifiers::Wally(specifier) => write!(f, "{specifier}"),
|
||||||
|
DependencySpecifiers::Git(specifier) => write!(f, "{specifier}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,14 @@ use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
manifest::{errors, DependencyType},
|
manifest::{errors, DependencyType},
|
||||||
|
names::wally::WallyPackageName,
|
||||||
source::{specifiers::DependencySpecifiers, wally::specifier::WallyDependencySpecifier},
|
source::{specifiers::DependencySpecifiers, wally::specifier::WallyDependencySpecifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct WallyPackage {
|
pub struct WallyPackage {
|
||||||
|
pub name: WallyPackageName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod compat_util;
|
pub(crate) mod compat_util;
|
||||||
pub(crate) mod manifest;
|
pub(crate) mod manifest;
|
||||||
/// The Wally package reference
|
/// The Wally package reference
|
||||||
pub mod pkg_ref;
|
pub mod pkg_ref;
|
||||||
|
@ -60,7 +60,9 @@ impl WallyPackageSource {
|
||||||
|
|
||||||
/// Reads the config file
|
/// Reads the config file
|
||||||
pub fn config(&self, project: &Project) -> Result<WallyIndexConfig, errors::ConfigError> {
|
pub fn config(&self, project: &Project) -> Result<WallyIndexConfig, errors::ConfigError> {
|
||||||
let file = self.read_file(["config.json"], project).map_err(Box::new)?;
|
let file = self
|
||||||
|
.read_file(["config.json"], project, None)
|
||||||
|
.map_err(Box::new)?;
|
||||||
|
|
||||||
let string = match file {
|
let string = match file {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
@ -93,7 +95,7 @@ impl PackageSource for WallyPackageSource {
|
||||||
_project_target: TargetKind,
|
_project_target: TargetKind,
|
||||||
) -> Result<crate::source::ResolveResult<Self::Ref>, Self::ResolveError> {
|
) -> Result<crate::source::ResolveResult<Self::Ref>, Self::ResolveError> {
|
||||||
let (scope, name) = specifier.name.as_str();
|
let (scope, name) = specifier.name.as_str();
|
||||||
let string = match self.read_file([scope, name], project) {
|
let string = match self.read_file([scope, name], project, None) {
|
||||||
Ok(Some(s)) => s,
|
Ok(Some(s)) => s,
|
||||||
Ok(None) => return Err(Self::ResolveError::NotFound(specifier.name.to_string())),
|
Ok(None) => return Err(Self::ResolveError::NotFound(specifier.name.to_string())),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
@ -44,15 +44,3 @@ impl PackageRef for WallyPackageRef {
|
||||||
PackageSources::Wally(WallyPackageSource::new(self.index_url.clone()))
|
PackageSources::Wally(WallyPackageSource::new(self.index_url.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for WallyPackageRef {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.version.cmp(&other.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for WallyPackageRef {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
12
src/util.rs
12
src/util.rs
|
@ -61,6 +61,18 @@ pub fn deserialize_gix_url_map<'de, D: Deserializer<'de>>(
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_git_like_url<'de, D: Deserializer<'de>>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<gix::Url, D::Error> {
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
if s.contains(':') {
|
||||||
|
gix::Url::from_bytes(BStr::new(&s)).map_err(serde::de::Error::custom)
|
||||||
|
} else {
|
||||||
|
gix::Url::from_bytes(BStr::new(format!("https://github.com/{s}").as_bytes()))
|
||||||
|
.map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hash<S: AsRef<[u8]>>(struc: S) -> String {
|
pub fn hash<S: AsRef<[u8]>>(struc: S) -> String {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(struc.as_ref());
|
hasher.update(struc.as_ref());
|
||||||
|
|
Loading…
Reference in a new issue