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 add;
|
||||||
mod auth;
|
mod auth;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod execute;
|
||||||
mod init;
|
mod init;
|
||||||
mod install;
|
mod install;
|
||||||
mod outdated;
|
mod outdated;
|
||||||
|
@ -60,6 +61,10 @@ pub enum Subcommand {
|
||||||
|
|
||||||
/// Checks for outdated dependencies
|
/// Checks for outdated dependencies
|
||||||
Outdated(outdated::OutdatedCommand),
|
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 {
|
impl Subcommand {
|
||||||
|
@ -88,6 +93,7 @@ impl Subcommand {
|
||||||
update.run(project, multi, reqwest)
|
update.run(project, multi, reqwest)
|
||||||
}
|
}
|
||||||
Subcommand::Outdated(outdated) => outdated.run(project),
|
Subcommand::Outdated(outdated) => outdated.run(project),
|
||||||
|
Subcommand::Execute(execute) => execute.run(project, reqwest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use tempfile::tempfile;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::target::Target,
|
manifest::target::Target,
|
||||||
scripts::ScriptName,
|
scripts::ScriptName,
|
||||||
source::{pesde::PesdePackageSource, traits::PackageSource},
|
source::{pesde::PesdePackageSource, specifiers::DependencySpecifiers, traits::PackageSource},
|
||||||
Project, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
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 {
|
if self.dry_run {
|
||||||
std::fs::write("package.tar.gz", archive)?;
|
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 anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
use pesde::{
|
use pesde::{
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
scripts::execute_script,
|
|
||||||
Project, PACKAGES_CONTAINER_NAME,
|
Project, PACKAGES_CONTAINER_NAME,
|
||||||
};
|
};
|
||||||
use relative_path::RelativePathBuf;
|
|
||||||
|
use crate::cli::IsUpToDate;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct RunCommand {
|
pub struct RunCommand {
|
||||||
|
@ -16,11 +19,24 @@ pub struct RunCommand {
|
||||||
|
|
||||||
/// Arguments to pass to the script
|
/// Arguments to pass to the script
|
||||||
#[arg(index = 2, last = true)]
|
#[arg(index = 2, last = true)]
|
||||||
args: Vec<String>,
|
args: Vec<OsString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunCommand {
|
impl RunCommand {
|
||||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
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>() {
|
if let Ok(pkg_name) = self.package_or_script.parse::<PackageName>() {
|
||||||
let graph = if project.is_up_to_date(true)? {
|
let graph = if project.is_up_to_date(true)? {
|
||||||
project.deser_lockfile()?.graph
|
project.deser_lockfile()?.graph
|
||||||
|
@ -51,31 +67,13 @@ impl RunCommand {
|
||||||
version_id.version(),
|
version_id.version(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let path = bin_path.to_path(&container_folder);
|
run(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")?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(manifest) = project.deser_manifest() {
|
if let Ok(manifest) = project.deser_manifest() {
|
||||||
if let Some(script_path) = manifest.scripts.get(&self.package_or_script) {
|
if let Some(script_path) = manifest.scripts.get(&self.package_or_script) {
|
||||||
execute_script(
|
run(script_path.to_path(project.path()))
|
||||||
Some(&self.package_or_script),
|
|
||||||
&script_path.to_path(project.path()),
|
|
||||||
&self.args,
|
|
||||||
project.path(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.context("failed to execute script")?;
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,8 +84,7 @@ impl RunCommand {
|
||||||
anyhow::bail!("path does not exist: {}", path.display());
|
anyhow::bail!("path does not exist: {}", path.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_script(None, &path, &self.args, project.path(), false)
|
run(path);
|
||||||
.context("failed to execute script")?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,11 @@ impl IsUpToDate for Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[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;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
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()
|
.transpose()
|
||||||
.map_err(Into::into)?;
|
.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(
|
execute_script(
|
||||||
Some(&script_name),
|
ScriptName::RobloxSyncConfigGenerator,
|
||||||
&script_path.to_path(self.path()),
|
&script_path.to_path(self.path()),
|
||||||
build_files,
|
build_files,
|
||||||
&container_folder,
|
&container_folder,
|
||||||
|
|
|
@ -29,9 +29,8 @@ impl Display for ScriptName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a script with the given arguments
|
pub(crate) fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
||||||
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
script_name: ScriptName,
|
||||||
script_name: Option<&str>,
|
|
||||||
script_path: &Path,
|
script_path: &Path,
|
||||||
args: A,
|
args: A,
|
||||||
cwd: P,
|
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 stdout = BufReader::new(child.stdout.take().unwrap());
|
||||||
let stderr = BufReader::new(child.stderr.take().unwrap());
|
let stderr = BufReader::new(child.stderr.take().unwrap());
|
||||||
|
|
||||||
let script = match script_name {
|
let script = script_name.to_string();
|
||||||
Some(script) => script.to_string(),
|
|
||||||
None => script_path.to_string_lossy().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let script_2 = script.to_string();
|
let script_2 = script.to_string();
|
||||||
|
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) fn find_lib_path(
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = execute_script(
|
let result = execute_script(
|
||||||
Some(&ScriptName::SourcemapGenerator.to_string()),
|
ScriptName::SourcemapGenerator,
|
||||||
&script_path.to_path(&project.path),
|
&script_path.to_path(&project.path),
|
||||||
["--wally"],
|
["--wally"],
|
||||||
cwd,
|
cwd,
|
||||||
|
|
Loading…
Reference in a new issue