mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-07 20:30:54 +01:00
Squashed commit of the following: commit5767042964
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Thu Jan 16 18:28:52 2025 +0100 fix(engines): correct engine detection on unix The `current_exe` function doesn't return the symlinked path on Unix, so the engine detection was failing there. This commit fixes that by using the 0th argument of the program to get the path of the executable on Unix. commitb51c9d9571
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Wed Jan 15 22:43:50 2025 +0100 refactor: print deprecated warning on CLI side Prints the deprecated warning on the CLI side which means it'll have a more consistent look with the rest of the CLI output. commit5ace844035
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Wed Jan 15 22:21:36 2025 +0100 feat: add alias validation Ensures aliases don't contain characters which could cause issues. They are now also forbidden from being the same as an engine name to avoid issues. commita33302aff9
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Wed Jan 15 21:23:40 2025 +0100 refactor: apply clippy lints commit2d534a534d
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Wed Jan 15 21:22:14 2025 +0100 feat(engines): print incompatibility warning for dependencies Adds a warning message when a dependency depends on an incompatible engine. commit4946a19f8b
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Wed Jan 15 18:33:38 2025 +0100 feat(engines): create linkers at install time Additionally fixes engines being executed as scripts, and fixes downloading pesde from GitHub. commite3177eeb75
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Tue Jan 14 14:33:26 2025 +0100 fix(engines): store & link engines correctly Fixes issues with how engines were stored which resulted in errors. Also makes outdated linkers get updated. commit037ead66bb
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Mon Jan 13 12:26:19 2025 +0100 docs: remove prerequisites commitddb496ff7d
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Mon Jan 13 12:25:53 2025 +0100 ci: remove tar builds commite9f0c25554
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Mon Jan 13 12:25:11 2025 +0100 chore(docs): update astro and starlight commitfc349e6f21
Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Sun Jan 12 23:12:27 2025 +0100 feat: add engines Adds the initial implementation of the engines feature. Not tested yet. Requires documentation and more work for non-pesde engines to be usable.
276 lines
7.8 KiB
Rust
276 lines
7.8 KiB
Rust
use std::str::FromStr;
|
|
|
|
use anyhow::Context;
|
|
use clap::Args;
|
|
use colored::Colorize;
|
|
use semver::VersionReq;
|
|
|
|
use crate::cli::{config::read_config, AnyPackageIdentifier, VersionedPackageName};
|
|
use pesde::{
|
|
manifest::{target::TargetKind, Alias},
|
|
names::PackageNames,
|
|
source::{
|
|
git::{specifier::GitDependencySpecifier, GitPackageSource},
|
|
path::{specifier::PathDependencySpecifier, PathPackageSource},
|
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
|
specifiers::DependencySpecifiers,
|
|
traits::{PackageSource, RefreshOptions, ResolveOptions},
|
|
workspace::{specifier::WorkspaceDependencySpecifier, WorkspacePackageSource},
|
|
PackageSources,
|
|
},
|
|
Project, RefreshedSources, DEFAULT_INDEX_NAME,
|
|
};
|
|
|
|
#[derive(Debug, Args)]
|
|
pub struct AddCommand {
|
|
/// The package name to add
|
|
#[arg(index = 1)]
|
|
name: AnyPackageIdentifier<VersionReq>,
|
|
|
|
/// The index in which to search for the package
|
|
#[arg(short, long)]
|
|
index: Option<String>,
|
|
|
|
/// The target environment of the package
|
|
#[arg(short, long)]
|
|
target: Option<TargetKind>,
|
|
|
|
/// The alias to use for the package
|
|
#[arg(short, long)]
|
|
alias: Option<Alias>,
|
|
|
|
/// Whether to add the package as a peer dependency
|
|
#[arg(short, long)]
|
|
peer: bool,
|
|
|
|
/// Whether to add the package as a dev dependency
|
|
#[arg(short, long, conflicts_with = "peer")]
|
|
dev: bool,
|
|
}
|
|
|
|
impl AddCommand {
|
|
pub async fn run(self, project: Project) -> anyhow::Result<()> {
|
|
let manifest = project
|
|
.deser_manifest()
|
|
.await
|
|
.context("failed to read manifest")?;
|
|
|
|
let (source, specifier) = match &self.name {
|
|
AnyPackageIdentifier::PackageName(versioned) => match &versioned {
|
|
VersionedPackageName(PackageNames::Pesde(name), version) => {
|
|
let index = manifest
|
|
.indices
|
|
.get(self.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
|
.cloned();
|
|
|
|
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
|
println!("{}: index {index} not found", "error".red().bold());
|
|
return Ok(());
|
|
}
|
|
|
|
let index = match index {
|
|
Some(index) => index,
|
|
None => read_config().await?.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();
|
|
|
|
if let Some(index) = self.index.as_ref().filter(|_| index.is_none()) {
|
|
println!("{}: wally index {index} not found", "error".red().bold());
|
|
return Ok(());
|
|
}
|
|
|
|
let index = index.context("no wally index found")?;
|
|
|
|
let source =
|
|
PackageSources::Wally(pesde::source::wally::WallyPackageSource::new(index));
|
|
let specifier = DependencySpecifiers::Wally(
|
|
pesde::source::wally::specifier::WallyDependencySpecifier {
|
|
name: name.clone(),
|
|
version: version.clone().unwrap_or(VersionReq::STAR),
|
|
index: self.index,
|
|
},
|
|
);
|
|
|
|
(source, specifier)
|
|
}
|
|
},
|
|
AnyPackageIdentifier::Url((url, rev)) => (
|
|
PackageSources::Git(GitPackageSource::new(url.clone())),
|
|
DependencySpecifiers::Git(GitDependencySpecifier {
|
|
repo: url.clone(),
|
|
rev: rev.to_string(),
|
|
path: None,
|
|
}),
|
|
),
|
|
AnyPackageIdentifier::Workspace(VersionedPackageName(name, version)) => (
|
|
PackageSources::Workspace(WorkspacePackageSource),
|
|
DependencySpecifiers::Workspace(WorkspaceDependencySpecifier {
|
|
name: name.clone(),
|
|
version: version.clone().unwrap_or_default(),
|
|
target: self.target,
|
|
}),
|
|
),
|
|
AnyPackageIdentifier::Path(path) => (
|
|
PackageSources::Path(PathPackageSource),
|
|
DependencySpecifiers::Path(PathDependencySpecifier { path: path.clone() }),
|
|
),
|
|
};
|
|
|
|
let refreshed_sources = RefreshedSources::new();
|
|
|
|
refreshed_sources
|
|
.refresh(
|
|
&source,
|
|
&RefreshOptions {
|
|
project: project.clone(),
|
|
},
|
|
)
|
|
.await
|
|
.context("failed to refresh package source")?;
|
|
|
|
let Some(version_id) = source
|
|
.resolve(
|
|
&specifier,
|
|
&ResolveOptions {
|
|
project: project.clone(),
|
|
target: manifest.target.kind(),
|
|
refreshed_sources,
|
|
},
|
|
)
|
|
.await
|
|
.context("failed to resolve package")?
|
|
.1
|
|
.pop_last()
|
|
.map(|(v_id, _)| v_id)
|
|
else {
|
|
println!("{}: no versions found for package", "error".red().bold());
|
|
|
|
return Ok(());
|
|
};
|
|
|
|
let project_target = manifest.target.kind();
|
|
let mut manifest = toml_edit::DocumentMut::from_str(
|
|
&project
|
|
.read_manifest()
|
|
.await
|
|
.context("failed to read manifest")?,
|
|
)
|
|
.context("failed to parse manifest")?;
|
|
let dependency_key = if self.peer {
|
|
"peer_dependencies"
|
|
} else if self.dev {
|
|
"dev_dependencies"
|
|
} else {
|
|
"dependencies"
|
|
};
|
|
|
|
let alias = match self.alias {
|
|
Some(alias) => alias,
|
|
None => match &self.name {
|
|
AnyPackageIdentifier::PackageName(versioned) => versioned.0.name().to_string(),
|
|
AnyPackageIdentifier::Url((url, _)) => url
|
|
.path
|
|
.to_string()
|
|
.split('/')
|
|
.next_back()
|
|
.map(|s| s.to_string())
|
|
.unwrap_or(url.path.to_string()),
|
|
AnyPackageIdentifier::Workspace(versioned) => versioned.0.name().to_string(),
|
|
AnyPackageIdentifier::Path(path) => path
|
|
.file_name()
|
|
.map(|s| s.to_string_lossy().to_string())
|
|
.expect("path has no file name"),
|
|
}
|
|
.parse()
|
|
.context("auto-generated alias is invalid. use --alias to specify one")?,
|
|
};
|
|
|
|
let field = &mut manifest[dependency_key]
|
|
.or_insert(toml_edit::Item::Table(toml_edit::Table::new()))[alias.as_str()];
|
|
|
|
match specifier {
|
|
DependencySpecifiers::Pesde(spec) => {
|
|
field["name"] = toml_edit::value(spec.name.clone().to_string());
|
|
field["version"] = toml_edit::value(format!("^{}", version_id.version()));
|
|
|
|
if *version_id.target() != project_target {
|
|
field["target"] = toml_edit::value(version_id.target().to_string());
|
|
}
|
|
|
|
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
|
field["index"] = toml_edit::value(index);
|
|
}
|
|
|
|
println!(
|
|
"added {}@{} {} to {dependency_key}",
|
|
spec.name,
|
|
version_id.version(),
|
|
version_id.target()
|
|
);
|
|
}
|
|
#[cfg(feature = "wally-compat")]
|
|
DependencySpecifiers::Wally(spec) => {
|
|
let name_str = spec.name.to_string();
|
|
let name_str = name_str.trim_start_matches("wally#");
|
|
field["wally"] = toml_edit::value(name_str);
|
|
field["version"] = toml_edit::value(format!("^{}", version_id.version()));
|
|
|
|
if let Some(index) = spec.index.filter(|i| i != DEFAULT_INDEX_NAME) {
|
|
field["index"] = toml_edit::value(index);
|
|
}
|
|
|
|
println!(
|
|
"added wally {name_str}@{} to {dependency_key}",
|
|
version_id.version()
|
|
);
|
|
}
|
|
DependencySpecifiers::Git(spec) => {
|
|
field["repo"] = toml_edit::value(spec.repo.to_bstring().to_string());
|
|
field["rev"] = toml_edit::value(spec.rev.clone());
|
|
|
|
println!("added git {}#{} to {dependency_key}", spec.repo, spec.rev);
|
|
}
|
|
DependencySpecifiers::Workspace(spec) => {
|
|
field["workspace"] = toml_edit::value(spec.name.clone().to_string());
|
|
if let AnyPackageIdentifier::Workspace(versioned) = self.name {
|
|
if let Some(version) = versioned.1 {
|
|
field["version"] = toml_edit::value(version.to_string());
|
|
}
|
|
}
|
|
|
|
println!(
|
|
"added workspace {}@{} to {dependency_key}",
|
|
spec.name, spec.version
|
|
);
|
|
}
|
|
DependencySpecifiers::Path(spec) => {
|
|
field["path"] = toml_edit::value(spec.path.to_string_lossy().to_string());
|
|
|
|
println!("added path {} to {dependency_key}", spec.path.display());
|
|
}
|
|
}
|
|
|
|
project
|
|
.write_manifest(manifest.to_string())
|
|
.await
|
|
.context("failed to write manifest")?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|