mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: implement execute command
This commit is contained in:
parent
79bbe11cab
commit
09307276b0
8 changed files with 151 additions and 40 deletions
88
src/cli/commands/execute.rs
Normal file
88
src/cli/commands/execute.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use std::{ffi::OsString, process::Command};
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use semver::VersionReq;
|
||||
|
||||
use crate::cli::{config::read_config, VersionedPackageName};
|
||||
use pesde::{
|
||||
manifest::target::TargetKind,
|
||||
names::PackageName,
|
||||
source::{
|
||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||
traits::PackageSource,
|
||||
},
|
||||
Project,
|
||||
};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ExecuteCommand {
|
||||
/// The package name, script name, or path to a script to run
|
||||
#[arg(index = 1)]
|
||||
package: VersionedPackageName<VersionReq, PackageName>,
|
||||
|
||||
/// The index URL to use for the package
|
||||
#[arg(short, long, value_parser = crate::cli::parse_gix_url)]
|
||||
index: Option<gix::Url>,
|
||||
|
||||
/// Arguments to pass to the script
|
||||
#[arg(index = 2, last = true)]
|
||||
args: Vec<OsString>,
|
||||
}
|
||||
|
||||
impl ExecuteCommand {
|
||||
pub fn run(self, project: Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> {
|
||||
let index = self
|
||||
.index
|
||||
.or_else(|| read_config().ok().map(|c| c.default_index))
|
||||
.context("no index specified")?;
|
||||
let source = PesdePackageSource::new(index);
|
||||
source
|
||||
.refresh(&project)
|
||||
.context("failed to refresh source")?;
|
||||
|
||||
let mut results = source
|
||||
.resolve(
|
||||
&PesdeDependencySpecifier {
|
||||
name: self.package.0,
|
||||
version: self.package.1.unwrap_or(VersionReq::STAR),
|
||||
index: None,
|
||||
target: None,
|
||||
},
|
||||
&project,
|
||||
TargetKind::Lune,
|
||||
)
|
||||
.context("failed to resolve package")?;
|
||||
|
||||
let (version, pkg_ref) = results.1.pop_last().context("no package found")?;
|
||||
|
||||
log::info!("found package {}@{version}", pkg_ref.name);
|
||||
|
||||
let (fs, target) = source
|
||||
.download(&pkg_ref, &project, &reqwest)
|
||||
.context("failed to download package")?;
|
||||
let bin_path = target.bin_path().context("package has no binary export")?;
|
||||
|
||||
let tmp_dir = project.cas_dir().join(".tmp");
|
||||
std::fs::create_dir_all(&tmp_dir).context("failed to create temporary directory")?;
|
||||
|
||||
let tempdir =
|
||||
tempfile::tempdir_in(tmp_dir).context("failed to create temporary directory")?;
|
||||
|
||||
fs.write_to(tempdir.path(), project.cas_dir(), true)
|
||||
.context("failed to write package contents")?;
|
||||
|
||||
let status = Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(bin_path.to_path(tempdir.path()))
|
||||
.arg("--")
|
||||
.args(&self.args)
|
||||
.current_dir(project.path())
|
||||
.status()
|
||||
.context("failed to run script")?;
|
||||
|
||||
drop(tempdir);
|
||||
|
||||
std::process::exit(status.code().unwrap_or(1))
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ use pesde::Project;
|
|||
mod add;
|
||||
mod auth;
|
||||
mod config;
|
||||
mod execute;
|
||||
mod init;
|
||||
mod install;
|
||||
mod outdated;
|
||||
|
@ -60,6 +61,10 @@ pub enum Subcommand {
|
|||
|
||||
/// Checks for outdated dependencies
|
||||
Outdated(outdated::OutdatedCommand),
|
||||
|
||||
/// Executes a binary package without needing to be run in a project directory
|
||||
#[clap(name = "x", visible_alias = "execute", visible_alias = "exec")]
|
||||
Execute(execute::ExecuteCommand),
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
|
@ -88,6 +93,7 @@ impl Subcommand {
|
|||
update.run(project, multi, reqwest)
|
||||
}
|
||||
Subcommand::Outdated(outdated) => outdated.run(project),
|
||||
Subcommand::Execute(execute) => execute.run(project, reqwest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use tempfile::tempfile;
|
|||
use pesde::{
|
||||
manifest::target::Target,
|
||||
scripts::ScriptName,
|
||||
source::{pesde::PesdePackageSource, traits::PackageSource},
|
||||
source::{pesde::PesdePackageSource, specifiers::DependencySpecifiers, traits::PackageSource},
|
||||
Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
||||
};
|
||||
|
||||
|
@ -318,6 +318,26 @@ impl PublishCommand {
|
|||
);
|
||||
}
|
||||
|
||||
let dependencies = manifest
|
||||
.all_dependencies()
|
||||
.context("failed to get dependencies")?;
|
||||
if !config.git_allowed
|
||||
&& dependencies
|
||||
.iter()
|
||||
.any(|(_, (spec, _))| matches!(spec, DependencySpecifiers::Git(_)))
|
||||
{
|
||||
anyhow::bail!("git dependencies are not allowed on this index");
|
||||
}
|
||||
|
||||
#[cfg(feature = "wally-compat")]
|
||||
if !config.wally_allowed
|
||||
&& dependencies
|
||||
.iter()
|
||||
.any(|(_, (spec, _))| matches!(spec, DependencySpecifiers::Wally(_)))
|
||||
{
|
||||
anyhow::bail!("wally dependencies are not allowed on this index");
|
||||
}
|
||||
|
||||
if self.dry_run {
|
||||
std::fs::write("package.tar.gz", archive)?;
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use crate::cli::IsUpToDate;
|
||||
use std::{ffi::OsString, path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use relative_path::RelativePathBuf;
|
||||
|
||||
use pesde::{
|
||||
names::{PackageName, PackageNames},
|
||||
scripts::execute_script,
|
||||
Project, PACKAGES_CONTAINER_NAME,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
|
||||
use crate::cli::IsUpToDate;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct RunCommand {
|
||||
|
@ -16,11 +19,24 @@ pub struct RunCommand {
|
|||
|
||||
/// Arguments to pass to the script
|
||||
#[arg(index = 2, last = true)]
|
||||
args: Vec<String>,
|
||||
args: Vec<OsString>,
|
||||
}
|
||||
|
||||
impl RunCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
let run = |path: PathBuf| {
|
||||
let status = Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(path)
|
||||
.arg("--")
|
||||
.args(&self.args)
|
||||
.current_dir(project.path())
|
||||
.status()
|
||||
.expect("failed to run script");
|
||||
|
||||
std::process::exit(status.code().unwrap_or(1))
|
||||
};
|
||||
|
||||
if let Ok(pkg_name) = self.package_or_script.parse::<PackageName>() {
|
||||
let graph = if project.is_up_to_date(true)? {
|
||||
project.deser_lockfile()?.graph
|
||||
|
@ -51,31 +67,13 @@ impl RunCommand {
|
|||
version_id.version(),
|
||||
);
|
||||
|
||||
let path = bin_path.to_path(&container_folder);
|
||||
|
||||
execute_script(
|
||||
Some(pkg_name.as_str().1),
|
||||
&path,
|
||||
&self.args,
|
||||
project.path(),
|
||||
false,
|
||||
)
|
||||
.context("failed to execute script")?;
|
||||
run(bin_path.to_path(&container_folder))
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(manifest) = project.deser_manifest() {
|
||||
if let Some(script_path) = manifest.scripts.get(&self.package_or_script) {
|
||||
execute_script(
|
||||
Some(&self.package_or_script),
|
||||
&script_path.to_path(project.path()),
|
||||
&self.args,
|
||||
project.path(),
|
||||
false,
|
||||
)
|
||||
.context("failed to execute script")?;
|
||||
|
||||
return Ok(());
|
||||
run(script_path.to_path(project.path()))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -86,8 +84,7 @@ impl RunCommand {
|
|||
anyhow::bail!("path does not exist: {}", path.display());
|
||||
}
|
||||
|
||||
execute_script(None, &path, &self.args, project.path(), false)
|
||||
.context("failed to execute script")?;
|
||||
run(path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -85,9 +85,11 @@ impl IsUpToDate for Project {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct VersionedPackageName<T: FromStr = VersionId>(PackageNames, Option<T>);
|
||||
struct VersionedPackageName<V: FromStr = VersionId, N: FromStr = PackageNames>(N, Option<V>);
|
||||
|
||||
impl<T: FromStr<Err = E>, E: Into<anyhow::Error>> FromStr for VersionedPackageName<T> {
|
||||
impl<V: FromStr<Err = E>, E: Into<anyhow::Error>, N: FromStr<Err = F>, F: Into<anyhow::Error>>
|
||||
FromStr for VersionedPackageName<V, N>
|
||||
{
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
@ -99,7 +101,10 @@ impl<T: FromStr<Err = E>, E: Into<anyhow::Error>> FromStr for VersionedPackageNa
|
|||
.transpose()
|
||||
.map_err(Into::into)?;
|
||||
|
||||
Ok(VersionedPackageName(name.parse()?, version))
|
||||
Ok(VersionedPackageName(
|
||||
name.parse().map_err(Into::into)?,
|
||||
version,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ impl Project {
|
|||
};
|
||||
|
||||
execute_script(
|
||||
Some(&script_name),
|
||||
ScriptName::RobloxSyncConfigGenerator,
|
||||
&script_path.to_path(self.path()),
|
||||
build_files,
|
||||
&container_folder,
|
||||
|
|
|
@ -29,9 +29,8 @@ impl Display for ScriptName {
|
|||
}
|
||||
}
|
||||
|
||||
/// Executes a script with the given arguments
|
||||
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
||||
script_name: Option<&str>,
|
||||
pub(crate) fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
||||
script_name: ScriptName,
|
||||
script_path: &Path,
|
||||
args: A,
|
||||
cwd: P,
|
||||
|
@ -52,11 +51,7 @@ pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>
|
|||
let stdout = BufReader::new(child.stdout.take().unwrap());
|
||||
let stderr = BufReader::new(child.stderr.take().unwrap());
|
||||
|
||||
let script = match script_name {
|
||||
Some(script) => script.to_string(),
|
||||
None => script_path.to_string_lossy().to_string(),
|
||||
};
|
||||
|
||||
let script = script_name.to_string();
|
||||
let script_2 = script.to_string();
|
||||
|
||||
spawn(move || {
|
||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) fn find_lib_path(
|
|||
};
|
||||
|
||||
let result = execute_script(
|
||||
Some(&ScriptName::SourcemapGenerator.to_string()),
|
||||
ScriptName::SourcemapGenerator,
|
||||
&script_path.to_path(&project.path),
|
||||
["--wally"],
|
||||
cwd,
|
||||
|
|
Loading…
Reference in a new issue