mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-07 04:10:55 +01:00
feat: support adding git dependencies with the cli
This commit is contained in:
parent
876fa21bcb
commit
7267dc2300
3 changed files with 118 additions and 75 deletions
|
@ -4,10 +4,12 @@ use anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
|
||||||
|
use crate::cli::{config::read_config, NamedVersionable, VersionedPackageName};
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::target::TargetKind,
|
manifest::target::TargetKind,
|
||||||
names::PackageNames,
|
names::PackageNames,
|
||||||
source::{
|
source::{
|
||||||
|
git::{specifier::GitDependencySpecifier, GitPackageSource},
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::PackageSource,
|
traits::PackageSource,
|
||||||
|
@ -16,13 +18,11 @@ use pesde::{
|
||||||
Project, DEFAULT_INDEX_NAME,
|
Project, DEFAULT_INDEX_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::cli::{config::read_config, VersionedPackageName};
|
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct AddCommand {
|
pub struct AddCommand {
|
||||||
/// The package name to add
|
/// The package name to add
|
||||||
#[arg(index = 1)]
|
#[arg(index = 1)]
|
||||||
name: VersionedPackageName<VersionReq>,
|
name: NamedVersionable<VersionReq>,
|
||||||
|
|
||||||
/// The index in which to search for the package
|
/// The index in which to search for the package
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
@ -51,60 +51,70 @@ impl AddCommand {
|
||||||
.deser_manifest()
|
.deser_manifest()
|
||||||
.context("failed to read manifest")?;
|
.context("failed to read manifest")?;
|
||||||
|
|
||||||
let source = match &self.name.0 {
|
let (source, specifier) = match &self.name {
|
||||||
PackageNames::Pesde(_) => {
|
NamedVersionable::PackageName(versioned) => match &versioned {
|
||||||
let index = manifest
|
VersionedPackageName(PackageNames::Pesde(name), version) => {
|
||||||
.indices
|
let index = manifest
|
||||||
.get(self.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
.indices
|
||||||
.cloned();
|
.get(self.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
||||||
|
.cloned();
|
||||||
|
|
||||||
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
||||||
log::error!("index {index} not found");
|
log::error!("index {index} not found");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = index.unwrap_or(read_config()?.default_index);
|
||||||
|
|
||||||
|
let source = PackageSources::Pesde(PesdePackageSource::new(index));
|
||||||
|
let specifier = DependencySpecifiers::Pesde(PesdeDependencySpecifier {
|
||||||
|
name: name.clone(),
|
||||||
|
version: version.clone().unwrap_or(VersionReq::STAR),
|
||||||
|
index: self.index,
|
||||||
|
target: self.target,
|
||||||
|
});
|
||||||
|
|
||||||
|
(source, specifier)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "wally-compat")]
|
||||||
|
VersionedPackageName(PackageNames::Wally(name), version) => {
|
||||||
|
let index = manifest
|
||||||
|
.wally_indices
|
||||||
|
.get(self.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
||||||
|
.cloned();
|
||||||
|
|
||||||
let index = index.unwrap_or(read_config()?.default_index);
|
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
||||||
|
log::error!("wally index {index} not found");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
PackageSources::Pesde(PesdePackageSource::new(index))
|
let index = index.unwrap_or(read_config()?.default_index);
|
||||||
}
|
|
||||||
#[cfg(feature = "wally-compat")]
|
|
||||||
PackageNames::Wally(_) => {
|
|
||||||
let index = manifest
|
|
||||||
.wally_indices
|
|
||||||
.get(self.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
|
||||||
.cloned();
|
|
||||||
|
|
||||||
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
let source =
|
||||||
log::error!("wally index {index} not found");
|
PackageSources::Wally(pesde::source::wally::WallyPackageSource::new(index));
|
||||||
return Ok(());
|
let specifier = DependencySpecifiers::Wally(
|
||||||
|
pesde::source::wally::specifier::WallyDependencySpecifier {
|
||||||
|
name: name.clone(),
|
||||||
|
version: version.clone().unwrap_or(VersionReq::STAR),
|
||||||
|
index: self.index,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
(source, specifier)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
let index = index.unwrap_or(read_config()?.default_index);
|
NamedVersionable::Url((url, rev)) => (
|
||||||
|
PackageSources::Git(GitPackageSource::new(url.clone())),
|
||||||
PackageSources::Wally(pesde::source::wally::WallyPackageSource::new(index))
|
DependencySpecifiers::Git(GitDependencySpecifier {
|
||||||
}
|
repo: url.clone(),
|
||||||
|
rev: rev.to_string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
source
|
source
|
||||||
.refresh(&project)
|
.refresh(&project)
|
||||||
.context("failed to refresh package source")?;
|
.context("failed to refresh package source")?;
|
||||||
|
|
||||||
let specifier = match &self.name.0 {
|
|
||||||
PackageNames::Pesde(name) => DependencySpecifiers::Pesde(PesdeDependencySpecifier {
|
|
||||||
name: name.clone(),
|
|
||||||
version: self.name.1.unwrap_or(VersionReq::STAR),
|
|
||||||
index: self.index,
|
|
||||||
target: self.target,
|
|
||||||
}),
|
|
||||||
#[cfg(feature = "wally-compat")]
|
|
||||||
PackageNames::Wally(name) => DependencySpecifiers::Wally(
|
|
||||||
pesde::source::wally::specifier::WallyDependencySpecifier {
|
|
||||||
name: name.clone(),
|
|
||||||
version: self.name.1.unwrap_or(VersionReq::STAR),
|
|
||||||
index: self.index,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(version_id) = source
|
let Some(version_id) = source
|
||||||
.resolve(&specifier, &project, manifest.target.kind())
|
.resolve(&specifier, &project, manifest.target.kind())
|
||||||
.context("failed to resolve package")?
|
.context("failed to resolve package")?
|
||||||
|
@ -112,11 +122,7 @@ impl AddCommand {
|
||||||
.pop_last()
|
.pop_last()
|
||||||
.map(|(v_id, _)| v_id)
|
.map(|(v_id, _)| v_id)
|
||||||
else {
|
else {
|
||||||
log::error!(
|
log::error!("no versions found for package {specifier}");
|
||||||
"no versions found for package: {} (current target: {}, try a different one)",
|
|
||||||
self.name.0,
|
|
||||||
manifest.target.kind()
|
|
||||||
);
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
@ -134,25 +140,31 @@ impl AddCommand {
|
||||||
"dependencies"
|
"dependencies"
|
||||||
};
|
};
|
||||||
|
|
||||||
let alias = self
|
let alias = self.alias.unwrap_or_else(|| match self.name {
|
||||||
.alias
|
NamedVersionable::PackageName(versioned) => versioned.0.as_str().1.to_string(),
|
||||||
.as_deref()
|
NamedVersionable::Url((url, _)) => url
|
||||||
.unwrap_or_else(|| self.name.0.as_str().1);
|
.path
|
||||||
|
.to_string()
|
||||||
|
.split('/')
|
||||||
|
.last()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.unwrap_or(url.path.to_string()),
|
||||||
|
});
|
||||||
|
|
||||||
match specifier {
|
match specifier {
|
||||||
DependencySpecifiers::Pesde(spec) => {
|
DependencySpecifiers::Pesde(spec) => {
|
||||||
manifest[dependency_key][alias]["name"] =
|
manifest[dependency_key][&alias]["name"] =
|
||||||
toml_edit::value(spec.name.clone().to_string());
|
toml_edit::value(spec.name.clone().to_string());
|
||||||
manifest[dependency_key][alias]["version"] =
|
manifest[dependency_key][&alias]["version"] =
|
||||||
toml_edit::value(format!("^{}", version_id.version()));
|
toml_edit::value(format!("^{}", version_id.version()));
|
||||||
|
|
||||||
if *version_id.target() != project_target {
|
if *version_id.target() != project_target {
|
||||||
manifest[dependency_key][alias]["target"] =
|
manifest[dependency_key][&alias]["target"] =
|
||||||
toml_edit::value(version_id.target().to_string());
|
toml_edit::value(version_id.target().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
||||||
manifest[dependency_key][alias]["index"] = toml_edit::value(index);
|
manifest[dependency_key][&alias]["index"] = toml_edit::value(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
@ -165,13 +177,13 @@ impl AddCommand {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
DependencySpecifiers::Wally(spec) => {
|
DependencySpecifiers::Wally(spec) => {
|
||||||
manifest[dependency_key][alias]["wally"] =
|
manifest[dependency_key][&alias]["wally"] =
|
||||||
toml_edit::value(spec.name.clone().to_string());
|
toml_edit::value(spec.name.clone().to_string());
|
||||||
manifest[dependency_key][alias]["version"] =
|
manifest[dependency_key][&alias]["version"] =
|
||||||
toml_edit::value(format!("^{}", version_id.version()));
|
toml_edit::value(format!("^{}", version_id.version()));
|
||||||
|
|
||||||
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
||||||
manifest[dependency_key][alias]["index"] = toml_edit::value(index);
|
manifest[dependency_key][&alias]["index"] = toml_edit::value(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
@ -181,8 +193,12 @@ impl AddCommand {
|
||||||
dependency_key
|
dependency_key
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Git(_) => {
|
DependencySpecifiers::Git(spec) => {
|
||||||
unreachable!("git dependencies are not supported in the add command");
|
manifest[dependency_key][&alias]["repo"] =
|
||||||
|
toml_edit::value(spec.repo.to_bstring().to_string());
|
||||||
|
manifest[dependency_key][&alias]["rev"] = toml_edit::value(spec.rev.clone());
|
||||||
|
|
||||||
|
println!("added git {}#{} to {}", spec.repo, spec.rev, dependency_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
use std::{collections::HashSet, fs::create_dir_all, str::FromStr};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
use pesde::{
|
||||||
|
lockfile::DownloadedGraph, names::PackageNames, source::version_id::VersionId, Project,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::cli::auth::get_token;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
@ -5,13 +15,6 @@ pub mod files;
|
||||||
pub mod scripts;
|
pub mod scripts;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
|
||||||
use crate::cli::auth::get_token;
|
|
||||||
use anyhow::Context;
|
|
||||||
use pesde::{
|
|
||||||
lockfile::DownloadedGraph, names::PackageNames, source::version_id::VersionId, Project,
|
|
||||||
};
|
|
||||||
use std::{collections::HashSet, fs::create_dir_all, str::FromStr};
|
|
||||||
|
|
||||||
pub const HOME_DIR: &str = concat!(".", env!("CARGO_PKG_NAME"));
|
pub const HOME_DIR: &str = concat!(".", env!("CARGO_PKG_NAME"));
|
||||||
|
|
||||||
pub fn home_dir() -> anyhow::Result<std::path::PathBuf> {
|
pub fn home_dir() -> anyhow::Result<std::path::PathBuf> {
|
||||||
|
@ -135,6 +138,33 @@ impl VersionedPackageName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum NamedVersionable<V: FromStr = VersionId, N: FromStr = PackageNames> {
|
||||||
|
PackageName(VersionedPackageName<V, N>),
|
||||||
|
Url((gix::Url, String)),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: FromStr<Err = E>, E: Into<anyhow::Error>, N: FromStr<Err = F>, F: Into<anyhow::Error>>
|
||||||
|
FromStr for NamedVersionable<V, N>
|
||||||
|
{
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if s.contains("gh#") {
|
||||||
|
let s = s.replacen("gh#", "https://github.com/", 1);
|
||||||
|
let (repo, rev) = s.split_once('#').unwrap();
|
||||||
|
|
||||||
|
Ok(NamedVersionable::Url((repo.try_into()?, rev.to_string())))
|
||||||
|
} else if s.contains(':') {
|
||||||
|
let (url, rev) = s.split_once('#').unwrap();
|
||||||
|
|
||||||
|
Ok(NamedVersionable::Url((url.try_into()?, rev.to_string())))
|
||||||
|
} else {
|
||||||
|
Ok(NamedVersionable::PackageName(s.parse()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_gix_url(s: &str) -> Result<gix::Url, gix::url::parse::Error> {
|
pub fn parse_gix_url(s: &str) -> Result<gix::Url, gix::url::parse::Error> {
|
||||||
s.try_into()
|
s.try_into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{manifest::target::TargetKind, source::DependencySpecifier};
|
use crate::source::DependencySpecifier;
|
||||||
|
|
||||||
/// The specifier for a Git dependency
|
/// The specifier for a Git dependency
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -15,9 +15,6 @@ 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 target to use for the package
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub target: Option<TargetKind>,
|
|
||||||
}
|
}
|
||||||
impl DependencySpecifier for GitDependencySpecifier {}
|
impl DependencySpecifier for GitDependencySpecifier {}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue