mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-05-04 10:33:47 +01:00
feat: add cross runtime script execution
Adds a new mechanism which simplifies executing scripts for different runtimes. Additionally, supports Lune's 0.9.0 change of removing "--" from the args.
This commit is contained in:
parent
6aeedd8602
commit
5c74a3762b
19 changed files with 434 additions and 147 deletions
|
@ -1,5 +1,7 @@
|
|||
use crate::cli::{
|
||||
compatible_runtime,
|
||||
config::read_config,
|
||||
get_project_engines,
|
||||
reporters::{self, CliReporter},
|
||||
VersionedPackageName,
|
||||
};
|
||||
|
@ -28,7 +30,6 @@ use std::{
|
|||
env::current_dir,
|
||||
ffi::OsString,
|
||||
io::{Stderr, Write as _},
|
||||
process::Command,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -57,7 +58,7 @@ impl ExecuteCommand {
|
|||
|
||||
let refreshed_sources = RefreshedSources::new();
|
||||
|
||||
let (tempdir, bin_path) = reporters::run_with_reporter_and_writer(
|
||||
let (tempdir, runtime, bin_path) = reporters::run_with_reporter_and_writer(
|
||||
std::io::stderr(),
|
||||
|multi_progress, root_progress, reporter| async {
|
||||
let multi_progress = multi_progress;
|
||||
|
@ -152,6 +153,8 @@ impl ExecuteCommand {
|
|||
project: project.clone(),
|
||||
path: tempdir.path().into(),
|
||||
id: id.clone(),
|
||||
// HACK: the pesde package source doesn't use the engines, so we can just use an empty map
|
||||
engines: Default::default(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
@ -175,7 +178,7 @@ impl ExecuteCommand {
|
|||
project
|
||||
.download_and_link(
|
||||
&graph,
|
||||
DownloadAndLinkOptions::<CliReporter<Stderr>, ()>::new(reqwest)
|
||||
DownloadAndLinkOptions::<CliReporter<Stderr>, ()>::new(reqwest.clone())
|
||||
.reporter(reporter)
|
||||
.refreshed_sources(refreshed_sources)
|
||||
.install_dependencies_mode(InstallDependenciesMode::Prod),
|
||||
|
@ -183,7 +186,18 @@ impl ExecuteCommand {
|
|||
.await
|
||||
.context("failed to download and link dependencies")?;
|
||||
|
||||
anyhow::Ok((tempdir, bin_path.to_relative_path_buf()))
|
||||
let manifest = project
|
||||
.deser_manifest()
|
||||
.await
|
||||
.context("failed to deserialize manifest")?;
|
||||
|
||||
let engines = get_project_engines(&manifest, &reqwest).await?;
|
||||
|
||||
anyhow::Ok((
|
||||
tempdir,
|
||||
compatible_runtime(target.kind(), &engines)?,
|
||||
bin_path.to_relative_path_buf(),
|
||||
))
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -200,13 +214,11 @@ impl ExecuteCommand {
|
|||
)
|
||||
.context("failed to write to tempfile")?;
|
||||
|
||||
let status = Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(caller.path())
|
||||
.arg("--")
|
||||
.args(&self.args)
|
||||
let status = runtime
|
||||
.prepare_command(caller.path().as_os_str(), self.args)
|
||||
.current_dir(current_dir().context("failed to get current directory")?)
|
||||
.status()
|
||||
.await
|
||||
.context("failed to run script")?;
|
||||
|
||||
drop(caller);
|
||||
|
|
|
@ -225,6 +225,8 @@ impl InitCommand {
|
|||
// HACK: the pesde package source doesn't use the path, so we can just use an empty one
|
||||
path: Path::new("").into(),
|
||||
id: id.clone(),
|
||||
// HACK: the pesde package source doesn't use the engines, so we can just use an empty map
|
||||
engines: Default::default(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -268,6 +270,8 @@ impl InitCommand {
|
|||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: add engines
|
||||
} else {
|
||||
println!(
|
||||
"{ERROR_PREFIX}: no scripts package configured, this can cause issues with Roblox compatibility"
|
||||
|
|
|
@ -105,7 +105,7 @@ impl Subcommand {
|
|||
Subcommand::Update(update) => update.run(project, reqwest).await,
|
||||
Subcommand::Outdated(outdated) => outdated.run(project).await,
|
||||
Subcommand::List(list) => list.run(project).await,
|
||||
Subcommand::Run(run) => run.run(project).await,
|
||||
Subcommand::Run(run) => run.run(project, reqwest).await,
|
||||
Subcommand::Publish(publish) => publish.run(project, reqwest).await,
|
||||
Subcommand::Yank(yank) => yank.run(project, reqwest).await,
|
||||
Subcommand::Deprecate(deprecate) => deprecate.run(project, reqwest).await,
|
||||
|
|
|
@ -127,6 +127,9 @@ impl PublishCommand {
|
|||
|
||||
match up_to_date_lockfile(project).await? {
|
||||
Some(lockfile) => {
|
||||
let engines =
|
||||
Arc::new(crate::cli::get_project_engines(&manifest, &reqwest).await?);
|
||||
|
||||
let mut tasks = lockfile
|
||||
.graph
|
||||
.iter()
|
||||
|
@ -142,6 +145,7 @@ impl PublishCommand {
|
|||
let id = Arc::new(id.clone());
|
||||
let node = node.clone();
|
||||
let refreshed_sources = refreshed_sources.clone();
|
||||
let engines = engines.clone();
|
||||
|
||||
async move {
|
||||
let source = node.pkg_ref.source();
|
||||
|
@ -161,6 +165,7 @@ impl PublishCommand {
|
|||
project,
|
||||
path: container_folder.into(),
|
||||
id,
|
||||
engines,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
use crate::cli::{style::WARN_STYLE, up_to_date_lockfile};
|
||||
use crate::cli::{compatible_runtime, get_project_engines, style::WARN_STYLE, up_to_date_lockfile};
|
||||
use anyhow::Context as _;
|
||||
use clap::Args;
|
||||
use fs_err::tokio as fs;
|
||||
use futures::{StreamExt as _, TryStreamExt as _};
|
||||
use pesde::{
|
||||
engine::runtime::Runtime,
|
||||
errors::{ManifestReadError, WorkspaceMembersError},
|
||||
linking::generator::generate_bin_linking_module,
|
||||
manifest::Alias,
|
||||
manifest::{Alias, Manifest},
|
||||
names::{PackageName, PackageNames},
|
||||
scripts::parse_script,
|
||||
source::traits::{GetTargetOptions, PackageRef as _, PackageSource as _, RefreshOptions},
|
||||
Project, MANIFEST_FILE_NAME,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
use std::{
|
||||
collections::HashSet, env::current_dir, ffi::OsString, io::Write as _, path::Path,
|
||||
process::Command,
|
||||
collections::HashSet, env::current_dir, ffi::OsString, io::Write as _, path::Path, sync::Arc,
|
||||
};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
|
@ -29,8 +30,15 @@ pub struct RunCommand {
|
|||
}
|
||||
|
||||
impl RunCommand {
|
||||
pub async fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
let run = |root: &Path, file_path: &Path| -> ! {
|
||||
pub async fn run(self, project: Project, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
||||
let manifest = project
|
||||
.deser_manifest()
|
||||
.await
|
||||
.context("failed to deserialize manifest")?;
|
||||
|
||||
let engines = Arc::new(get_project_engines(&manifest, &reqwest).await?);
|
||||
|
||||
let run = async |runtime: Runtime, root: &Path, file_path: &Path| -> ! {
|
||||
let mut caller = tempfile::NamedTempFile::new().expect("failed to create tempfile");
|
||||
caller
|
||||
.write_all(
|
||||
|
@ -42,13 +50,11 @@ impl RunCommand {
|
|||
)
|
||||
.expect("failed to write to tempfile");
|
||||
|
||||
let status = Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(caller.path())
|
||||
.arg("--")
|
||||
.args(&self.args)
|
||||
let status = runtime
|
||||
.prepare_command(caller.path().as_os_str(), self.args)
|
||||
.current_dir(current_dir().expect("failed to get current directory"))
|
||||
.status()
|
||||
.await
|
||||
.expect("failed to run script");
|
||||
|
||||
drop(caller);
|
||||
|
@ -57,11 +63,13 @@ impl RunCommand {
|
|||
};
|
||||
|
||||
let Some(package_or_script) = self.package_or_script else {
|
||||
if let Some(script_path) = project.deser_manifest().await?.target.bin_path() {
|
||||
if let Some(script_path) = manifest.target.bin_path() {
|
||||
run(
|
||||
compatible_runtime(manifest.target.kind(), &engines)?,
|
||||
project.package_dir(),
|
||||
&script_path.to_path(project.package_dir()),
|
||||
);
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
anyhow::bail!("no package or script specified, and no bin path found in manifest")
|
||||
|
@ -130,6 +138,7 @@ impl RunCommand {
|
|||
project,
|
||||
path: container_folder.as_path().into(),
|
||||
id: id.into(),
|
||||
engines: engines.clone(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -140,15 +149,20 @@ impl RunCommand {
|
|||
|
||||
let path = bin_path.to_path(&container_folder);
|
||||
|
||||
run(&path, &path);
|
||||
run(compatible_runtime(target.kind(), &engines)?, &path, &path).await;
|
||||
}
|
||||
|
||||
if let Ok(manifest) = project.deser_manifest().await {
|
||||
if let Some(script_path) = manifest.scripts.get(&package_or_script) {
|
||||
if let Ok(mut manifest) = project.deser_manifest().await {
|
||||
if let Some(script) = manifest.scripts.remove(&package_or_script) {
|
||||
let (runtime, script_path) =
|
||||
parse_script(script, &engines).context("failed to get script info")?;
|
||||
|
||||
run(
|
||||
runtime,
|
||||
project.package_dir(),
|
||||
&script_path.to_path(project.package_dir()),
|
||||
);
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,6 +226,17 @@ impl RunCommand {
|
|||
project.package_dir().to_path_buf()
|
||||
};
|
||||
|
||||
run(&root, &path);
|
||||
let manifest = fs::read_to_string(root.join(MANIFEST_FILE_NAME))
|
||||
.await
|
||||
.context("failed to read manifest at root")?;
|
||||
let manifest = toml::de::from_str::<Manifest>(&manifest)
|
||||
.context("failed to deserialize manifest at root")?;
|
||||
|
||||
run(
|
||||
compatible_runtime(manifest.target.kind(), &engines)?,
|
||||
&root,
|
||||
&path,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@ pub struct SelfInstallCommand {
|
|||
|
||||
impl SelfInstallCommand {
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
let bin_dir = crate::cli::bin_dir()?;
|
||||
let bin_dir = bin_dir
|
||||
.to_str()
|
||||
.context("bin directory path contains invalid characters")?;
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if !self.skip_add_to_path {
|
||||
|
@ -24,17 +29,11 @@ impl SelfInstallCommand {
|
|||
use anyhow::Context as _;
|
||||
use windows_registry::CURRENT_USER;
|
||||
|
||||
let bin_dir = crate::cli::bin_dir()?;
|
||||
|
||||
let env = CURRENT_USER
|
||||
.create("Environment")
|
||||
.context("failed to open Environment key")?;
|
||||
let path = env.get_string("Path").context("failed to get Path value")?;
|
||||
|
||||
let bin_dir = bin_dir
|
||||
.to_str()
|
||||
.context("bin directory path contains invalid characters")?;
|
||||
|
||||
let exists = path.split(';').any(|part| part == bin_dir);
|
||||
|
||||
if !exists {
|
||||
|
@ -68,7 +67,7 @@ and then restart your shell.
|
|||
",
|
||||
CLI_STYLE.apply_to(env!("CARGO_BIN_NAME")),
|
||||
ADDED_STYLE.apply_to(env!("CARGO_PKG_VERSION")),
|
||||
style(format!(r#"export PATH="$PATH:$HOME/{HOME_DIR}/bin""#)).green(),
|
||||
style(format!(r#"export PATH="$PATH:{bin_dir}""#)).green(),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::files::make_executable;
|
||||
use crate::cli::{
|
||||
bin_dir, dep_type_to_key,
|
||||
reporters::{self, run_with_reporter, CliReporter},
|
||||
reporters::{self, CliReporter},
|
||||
resolve_overrides, run_on_workspace_members,
|
||||
style::{ADDED_STYLE, REMOVED_STYLE, WARN_PREFIX},
|
||||
up_to_date_lockfile,
|
||||
|
@ -25,7 +25,7 @@ use pesde::{
|
|||
version_matches, Project, RefreshedSources, MANIFEST_FILE_NAME,
|
||||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
num::NonZeroUsize,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
|
@ -181,49 +181,7 @@ pub async fn install(
|
|||
}
|
||||
};
|
||||
|
||||
let progress_prefix = format!("{} {}: ", manifest.name, manifest.target);
|
||||
|
||||
#[cfg(feature = "version-management")]
|
||||
let resolved_engine_versions = run_with_reporter(|_, root_progress, reporter| async {
|
||||
let root_progress = root_progress;
|
||||
let reporter = reporter;
|
||||
|
||||
root_progress.set_prefix(progress_prefix.clone());
|
||||
root_progress.reset();
|
||||
root_progress.set_message("update engines");
|
||||
|
||||
let mut tasks = manifest
|
||||
.engines
|
||||
.iter()
|
||||
.map(|(engine, req)| {
|
||||
let engine = *engine;
|
||||
let req = req.clone();
|
||||
let reqwest = reqwest.clone();
|
||||
let reporter = reporter.clone();
|
||||
|
||||
async move {
|
||||
let version = crate::cli::version::get_or_download_engine(
|
||||
&reqwest, engine, req, reporter,
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
crate::cli::version::make_linker_if_needed(engine).await?;
|
||||
|
||||
Ok::<_, anyhow::Error>((engine, version))
|
||||
}
|
||||
})
|
||||
.collect::<JoinSet<_>>();
|
||||
|
||||
let mut resolved_engine_versions = HashMap::new();
|
||||
|
||||
while let Some(task) = tasks.join_next().await {
|
||||
let (engine, version) = task.unwrap()?;
|
||||
resolved_engine_versions.insert(engine, version);
|
||||
}
|
||||
|
||||
Ok::<_, anyhow::Error>(resolved_engine_versions)
|
||||
})
|
||||
.await?;
|
||||
let resolved_engine_versions = Arc::new(super::get_project_engines(&manifest, &reqwest).await?);
|
||||
|
||||
let overrides = resolve_overrides(&manifest)?;
|
||||
|
||||
|
@ -232,7 +190,7 @@ pub async fn install(
|
|||
let multi = multi;
|
||||
let root_progress = root_progress;
|
||||
|
||||
root_progress.set_prefix(progress_prefix);
|
||||
root_progress.set_prefix(format!("{} {}: ", manifest.name, manifest.target));
|
||||
root_progress.reset();
|
||||
root_progress.set_message("resolve");
|
||||
|
||||
|
@ -318,7 +276,8 @@ pub async fn install(
|
|||
.refreshed_sources(refreshed_sources.clone())
|
||||
.install_dependencies_mode(options.install_dependencies_mode)
|
||||
.network_concurrency(options.network_concurrency)
|
||||
.force(options.force || has_irrecoverable_changes),
|
||||
.force(options.force || has_irrecoverable_changes)
|
||||
.engines(resolved_engine_versions.clone()),
|
||||
)
|
||||
.await
|
||||
.context("failed to download and link dependencies")?;
|
||||
|
|
|
@ -5,6 +5,10 @@ use crate::cli::{
|
|||
use anyhow::Context as _;
|
||||
use futures::StreamExt as _;
|
||||
use pesde::{
|
||||
engine::{
|
||||
runtime::{Runtime, RuntimeKind},
|
||||
EngineKind,
|
||||
},
|
||||
errors::ManifestReadError,
|
||||
lockfile::Lockfile,
|
||||
manifest::{
|
||||
|
@ -19,8 +23,10 @@ use pesde::{
|
|||
Project, DEFAULT_INDEX_NAME,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
use reporters::run_with_reporter;
|
||||
use semver::Version;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
future::Future,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
|
@ -361,3 +367,88 @@ pub fn dep_type_to_key(dep_type: DependencyType) -> &'static str {
|
|||
DependencyType::Peer => "peer_dependencies",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "version-management")]
|
||||
pub async fn get_project_engines(
|
||||
manifest: &Manifest,
|
||||
reqwest: &reqwest::Client,
|
||||
) -> anyhow::Result<HashMap<EngineKind, Version>> {
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
run_with_reporter(|_, root_progress, reporter| async {
|
||||
let root_progress = root_progress;
|
||||
let reporter = reporter;
|
||||
|
||||
root_progress.set_prefix(format!("{} {}: ", manifest.name, manifest.target));
|
||||
root_progress.reset();
|
||||
root_progress.set_message("update engines");
|
||||
|
||||
let mut tasks = manifest
|
||||
.engines
|
||||
.iter()
|
||||
.map(|(engine, req)| {
|
||||
let engine = *engine;
|
||||
let req = req.clone();
|
||||
let reqwest = reqwest.clone();
|
||||
let reporter = reporter.clone();
|
||||
|
||||
async move {
|
||||
let version = crate::cli::version::get_or_download_engine(
|
||||
&reqwest, engine, req, reporter,
|
||||
)
|
||||
.await
|
||||
.context("failed to install engine")?
|
||||
.1;
|
||||
|
||||
crate::cli::version::make_linker_if_needed(engine)
|
||||
.await
|
||||
.context("failed to make engine linker")?;
|
||||
|
||||
Ok::<_, anyhow::Error>((engine, version))
|
||||
}
|
||||
})
|
||||
.collect::<JoinSet<_>>();
|
||||
|
||||
let mut resolved_engine_versions = HashMap::new();
|
||||
|
||||
while let Some(task) = tasks.join_next().await {
|
||||
let (engine, version) = task.unwrap()?;
|
||||
resolved_engine_versions.insert(engine, version);
|
||||
}
|
||||
|
||||
Ok::<_, anyhow::Error>(resolved_engine_versions)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "version-management"))]
|
||||
pub async fn get_project_engines(
|
||||
_manifest: &Manifest,
|
||||
_reqwest: &reqwest::Client,
|
||||
) -> anyhow::Result<HashMap<EngineKind, Version>> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
pub fn compatible_runtime(
|
||||
target: TargetKind,
|
||||
engines: &HashMap<EngineKind, Version>,
|
||||
) -> anyhow::Result<Runtime> {
|
||||
let runtime = match target {
|
||||
TargetKind::Lune => RuntimeKind::Lune,
|
||||
TargetKind::Luau => engines
|
||||
.keys()
|
||||
.find_map(|e| e.as_runtime())
|
||||
.context("no runtime available")?,
|
||||
TargetKind::Roblox | TargetKind::RobloxServer => {
|
||||
anyhow::bail!("roblox targets cannot be ran!")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Runtime::new(
|
||||
runtime,
|
||||
engines
|
||||
.get(&runtime.into())
|
||||
.with_context(|| format!("{runtime} not available!"))?
|
||||
.clone(),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
all_packages_dirs,
|
||||
download::DownloadGraphOptions,
|
||||
engine::runtime::Engines,
|
||||
graph::{
|
||||
DependencyGraph, DependencyGraphNode, DependencyGraphNodeWithTarget,
|
||||
DependencyGraphWithTarget,
|
||||
|
@ -104,6 +105,8 @@ pub struct DownloadAndLinkOptions<Reporter = (), Hooks = ()> {
|
|||
pub network_concurrency: NonZeroUsize,
|
||||
/// Whether to re-install all dependencies even if they are already installed
|
||||
pub force: bool,
|
||||
/// The engines this project is using
|
||||
pub engines: Arc<Engines>,
|
||||
}
|
||||
|
||||
impl<Reporter, Hooks> DownloadAndLinkOptions<Reporter, Hooks>
|
||||
|
@ -122,6 +125,7 @@ where
|
|||
install_dependencies_mode: InstallDependenciesMode::All,
|
||||
network_concurrency: NonZeroUsize::new(16).unwrap(),
|
||||
force: false,
|
||||
engines: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +173,13 @@ where
|
|||
self.force = force;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the engines this project is using
|
||||
#[must_use]
|
||||
pub fn engines(mut self, engines: impl Into<Arc<Engines>>) -> Self {
|
||||
self.engines = engines.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for DownloadAndLinkOptions {
|
||||
|
@ -181,6 +192,7 @@ impl Clone for DownloadAndLinkOptions {
|
|||
install_dependencies_mode: self.install_dependencies_mode,
|
||||
network_concurrency: self.network_concurrency,
|
||||
force: self.force,
|
||||
engines: self.engines.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +221,7 @@ impl Project {
|
|||
install_dependencies_mode,
|
||||
network_concurrency,
|
||||
force,
|
||||
engines,
|
||||
} = options;
|
||||
|
||||
let reqwest = reqwest.clone();
|
||||
|
@ -346,6 +359,7 @@ impl Project {
|
|||
project: &Project,
|
||||
manifest_target_kind: TargetKind,
|
||||
downloaded_graph: HashMap<PackageId, DependencyGraphNode>,
|
||||
engines: &Arc<Engines>,
|
||||
) -> Result<(), errors::DownloadAndLinkError<Hooks::Error>> {
|
||||
let mut tasks = downloaded_graph
|
||||
.into_iter()
|
||||
|
@ -357,6 +371,7 @@ impl Project {
|
|||
.into();
|
||||
let id = Arc::new(id);
|
||||
let project = project.clone();
|
||||
let engines = engines.clone();
|
||||
|
||||
async move {
|
||||
let target = source
|
||||
|
@ -366,6 +381,7 @@ impl Project {
|
|||
project,
|
||||
path,
|
||||
id: id.clone(),
|
||||
engines,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -392,11 +408,12 @@ impl Project {
|
|||
self,
|
||||
manifest.target.kind(),
|
||||
other_graph_to_download,
|
||||
&engines,
|
||||
)
|
||||
.instrument(tracing::debug_span!("get targets (non-wally)"))
|
||||
.await?;
|
||||
|
||||
self.link_dependencies(&graph, false)
|
||||
self.link_dependencies(&graph, &engines, false)
|
||||
.instrument(tracing::debug_span!("link (non-wally)"))
|
||||
.await?;
|
||||
|
||||
|
@ -418,6 +435,7 @@ impl Project {
|
|||
self,
|
||||
manifest.target.kind(),
|
||||
wally_graph_to_download,
|
||||
&engines,
|
||||
)
|
||||
.instrument(tracing::debug_span!("get targets (wally)"))
|
||||
.await?;
|
||||
|
@ -461,7 +479,7 @@ impl Project {
|
|||
}
|
||||
|
||||
// step 4. link ALL dependencies. do so with types
|
||||
self.link_dependencies(&graph, true)
|
||||
self.link_dependencies(&graph, &engines, true)
|
||||
.instrument(tracing::debug_span!("link (all)"))
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/// Engines as runtimes
|
||||
pub mod runtime;
|
||||
/// Sources of engines
|
||||
pub mod source;
|
||||
|
||||
|
|
92
src/engine/runtime.rs
Normal file
92
src/engine/runtime.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
fmt::{Debug, Display},
|
||||
};
|
||||
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
|
||||
use super::EngineKind;
|
||||
|
||||
pub(crate) type Engines = HashMap<EngineKind, Version>;
|
||||
|
||||
/// A runtime
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(schemars::JsonSchema))]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RuntimeKind {
|
||||
/// The Lune runtime
|
||||
Lune,
|
||||
}
|
||||
|
||||
impl Display for RuntimeKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Lune => write!(f, "lune"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Supported runtimes
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Runtime {
|
||||
/// The [EngineKind::Lune] runtime
|
||||
Lune(Version),
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
/// Prepares a [Command] to execute the given script with the given arguments
|
||||
pub fn prepare_command<A: IntoIterator<Item = S> + Debug, S: AsRef<OsStr> + Debug>(
|
||||
&self,
|
||||
script_path: &OsStr,
|
||||
args: A,
|
||||
) -> Command {
|
||||
let mut command = Command::new(match self {
|
||||
Self::Lune(..) => "lune",
|
||||
});
|
||||
|
||||
match self {
|
||||
Self::Lune(version) => {
|
||||
command.arg("run");
|
||||
command.arg(script_path);
|
||||
if *version < Version::new(0, 9, 0) {
|
||||
command.arg("--");
|
||||
}
|
||||
command.args(args);
|
||||
}
|
||||
}
|
||||
|
||||
command
|
||||
}
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
/// Creates a [Runtime] from the [RuntimeKind] and [Version]
|
||||
#[must_use]
|
||||
pub fn new(kind: RuntimeKind, version: Version) -> Self {
|
||||
match kind {
|
||||
RuntimeKind::Lune => Runtime::Lune(version),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EngineKind {
|
||||
/// Returns this engine as a [RuntimeKind], if it is one
|
||||
#[must_use]
|
||||
pub fn as_runtime(self) -> Option<RuntimeKind> {
|
||||
Some(match self {
|
||||
EngineKind::Pesde => return None,
|
||||
EngineKind::Lune => RuntimeKind::Lune,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeKind> for EngineKind {
|
||||
fn from(value: RuntimeKind) -> Self {
|
||||
match value {
|
||||
RuntimeKind::Lune => EngineKind::Lune,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -377,7 +377,7 @@ impl RefreshedSources {
|
|||
|
||||
async fn deser_manifest(path: &Path) -> Result<Manifest, errors::ManifestReadError> {
|
||||
let string = fs::read_to_string(path.join(MANIFEST_FILE_NAME)).await?;
|
||||
toml::from_str(&string).map_err(|e| errors::ManifestReadError::Serde(path.to_path_buf(), e))
|
||||
toml::from_str(&string).map_err(|e| errors::ManifestReadError::Serde(path.into(), e))
|
||||
}
|
||||
|
||||
/// Find the project & workspace directory roots
|
||||
|
@ -398,7 +398,7 @@ pub async fn find_roots(
|
|||
.await
|
||||
.map_err(errors::ManifestReadError::Io)?;
|
||||
let manifest: Manifest = toml::from_str(&manifest)
|
||||
.map_err(|e| errors::ManifestReadError::Serde(path.to_path_buf(), e))?;
|
||||
.map_err(|e| errors::ManifestReadError::Serde(path.into(), e))?;
|
||||
|
||||
if manifest.workspace_members.is_empty() {
|
||||
return Ok(HashSet::new());
|
||||
|
@ -479,7 +479,7 @@ pub(crate) fn all_packages_dirs() -> HashSet<String> {
|
|||
|
||||
/// Errors that can occur when using the pesde library
|
||||
pub mod errors {
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can occur when reading the manifest file
|
||||
|
@ -492,7 +492,7 @@ pub mod errors {
|
|||
|
||||
/// An error occurred while deserializing the manifest file
|
||||
#[error("error deserializing manifest file at {0}")]
|
||||
Serde(PathBuf, #[source] toml::de::Error),
|
||||
Serde(Box<Path>, #[source] toml::de::Error),
|
||||
}
|
||||
|
||||
/// Errors that can occur when reading the lockfile
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
engine::runtime::Engines,
|
||||
graph::{DependencyGraphNodeWithTarget, DependencyGraphWithTarget},
|
||||
linking::generator::get_file_types,
|
||||
manifest::{Alias, Manifest},
|
||||
|
@ -15,6 +16,7 @@ use std::{
|
|||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::task::{spawn_blocking, JoinSet};
|
||||
use tracing::{instrument, Instrument as _};
|
||||
|
@ -64,6 +66,7 @@ impl Project {
|
|||
pub(crate) async fn link_dependencies(
|
||||
&self,
|
||||
graph: &DependencyGraphWithTarget,
|
||||
engines: &Arc<Engines>,
|
||||
with_types: bool,
|
||||
) -> Result<(), errors::LinkingError> {
|
||||
let manifest = self.deser_manifest().await?;
|
||||
|
@ -88,6 +91,7 @@ impl Project {
|
|||
let package_id = package_id.clone();
|
||||
let node = node.clone();
|
||||
let project = self.clone();
|
||||
let engines = engines.clone();
|
||||
|
||||
async move {
|
||||
let Some(lib_file) = node.target.lib_path() else {
|
||||
|
@ -131,6 +135,7 @@ impl Project {
|
|||
execute_script(
|
||||
ScriptName::RobloxSyncConfigGenerator,
|
||||
&project,
|
||||
&engines,
|
||||
LinkingExecuteScriptHooks,
|
||||
std::iter::once(container_folder.as_os_str())
|
||||
.chain(build_files.iter().map(OsStr::new)),
|
||||
|
|
75
src/main.rs
75
src/main.rs
|
@ -3,16 +3,16 @@ use crate::cli::version::{check_for_updates, current_version, get_or_download_en
|
|||
use crate::cli::{auth::get_tokens, display_err, style::ERROR_STYLE, PESDE_DIR};
|
||||
use anyhow::Context as _;
|
||||
use clap::{builder::styling::AnsiColor, Parser};
|
||||
use cli::data_dir;
|
||||
use cli::{compatible_runtime, data_dir, get_project_engines};
|
||||
use fs_err::tokio as fs;
|
||||
use indicatif::MultiProgress;
|
||||
use pesde::{
|
||||
engine::EngineKind, find_roots, manifest::target::TargetKind, version_matches, AuthConfig,
|
||||
Project,
|
||||
Project, MANIFEST_FILE_NAME,
|
||||
};
|
||||
use semver::VersionReq;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
collections::HashMap,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr as _,
|
||||
|
@ -197,6 +197,14 @@ async fn run() -> anyhow::Result<()> {
|
|||
.map_or_else(|| "none".to_string(), |p| p.display().to_string())
|
||||
);
|
||||
|
||||
let reqwest = reqwest::Client::builder()
|
||||
.user_agent(concat!(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
))
|
||||
.build()?;
|
||||
|
||||
'scripts: {
|
||||
// if we're an engine, we don't want to run any scripts
|
||||
if exe_name_engine.is_ok() {
|
||||
|
@ -212,15 +220,23 @@ async fn run() -> anyhow::Result<()> {
|
|||
|
||||
let linker_file_name = format!("{exe_name}.bin.luau");
|
||||
|
||||
let path = 'finder: {
|
||||
let (path, target) = 'finder: {
|
||||
let all_folders = TargetKind::VARIANTS
|
||||
.iter()
|
||||
.flat_map(|a| TargetKind::VARIANTS.iter().map(|b| a.packages_folder(*b)))
|
||||
.collect::<HashSet<_>>();
|
||||
.copied()
|
||||
.filter(|t| t.has_bin())
|
||||
.flat_map(|a| {
|
||||
TargetKind::VARIANTS
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|t| t.has_bin())
|
||||
.map(move |b| (a.packages_folder(b), b))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut tasks = all_folders
|
||||
.into_iter()
|
||||
.map(|folder| {
|
||||
.map(|(folder, target)| {
|
||||
let package_path = project_root_dir.join(&folder).join(&linker_file_name);
|
||||
let workspace_path = project_workspace_dir
|
||||
.as_deref()
|
||||
|
@ -228,12 +244,12 @@ async fn run() -> anyhow::Result<()> {
|
|||
|
||||
async move {
|
||||
if fs::metadata(&package_path).await.is_ok() {
|
||||
return Some((true, package_path));
|
||||
return Some((true, package_path, target));
|
||||
}
|
||||
|
||||
if let Some(workspace_path) = workspace_path {
|
||||
if fs::metadata(&workspace_path).await.is_ok() {
|
||||
return Some((false, workspace_path));
|
||||
return Some((false, workspace_path, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,12 +261,12 @@ async fn run() -> anyhow::Result<()> {
|
|||
let mut workspace_path = None;
|
||||
|
||||
while let Some(res) = tasks.join_next().await {
|
||||
if let Some((primary, path)) = res.unwrap() {
|
||||
if let Some((primary, path, target)) = res.unwrap() {
|
||||
if primary {
|
||||
break 'finder path;
|
||||
break 'finder (path, target);
|
||||
}
|
||||
|
||||
workspace_path = Some(path);
|
||||
workspace_path = Some((path, target));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,13 +283,18 @@ async fn run() -> anyhow::Result<()> {
|
|||
std::process::exit(1i32);
|
||||
};
|
||||
|
||||
let status = std::process::Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(path)
|
||||
.arg("--")
|
||||
.args(std::env::args_os().skip(1))
|
||||
let manifest = fs::read_to_string(project_root_dir.join(MANIFEST_FILE_NAME))
|
||||
.await
|
||||
.context("failed to read manifest")?;
|
||||
let manifest = toml::de::from_str(&manifest).context("failed to deserialize manifest")?;
|
||||
|
||||
let engines = get_project_engines(&manifest, &reqwest).await?;
|
||||
|
||||
let status = compatible_runtime(target, &engines)?
|
||||
.prepare_command(path.as_os_str(), std::env::args_os().skip(1))
|
||||
.current_dir(cwd)
|
||||
.status()
|
||||
.await
|
||||
.expect("failed to run lune");
|
||||
|
||||
std::process::exit(status.code().unwrap_or(1i32));
|
||||
|
@ -294,26 +315,6 @@ async fn run() -> anyhow::Result<()> {
|
|||
AuthConfig::new().with_tokens(get_tokens().await?.0),
|
||||
);
|
||||
|
||||
let reqwest = {
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
|
||||
headers.insert(
|
||||
reqwest::header::ACCEPT,
|
||||
"application/json"
|
||||
.parse()
|
||||
.context("failed to create accept header")?,
|
||||
);
|
||||
|
||||
reqwest::Client::builder()
|
||||
.user_agent(concat!(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
))
|
||||
.default_headers(headers)
|
||||
.build()?
|
||||
};
|
||||
|
||||
#[cfg(feature = "version-management")]
|
||||
'engines: {
|
||||
let Ok(engine) = exe_name_engine else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
engine::EngineKind,
|
||||
engine::{runtime::RuntimeKind, EngineKind},
|
||||
manifest::{
|
||||
overrides::{OverrideKey, OverrideSpecifier},
|
||||
target::Target,
|
||||
|
@ -51,8 +51,7 @@ pub struct Manifest {
|
|||
pub private: bool,
|
||||
/// The scripts of the package
|
||||
#[serde(default, skip_serializing)]
|
||||
#[cfg_attr(test, schemars(with = "BTreeMap<String, std::path::PathBuf>"))]
|
||||
pub scripts: BTreeMap<String, RelativePathBuf>,
|
||||
pub scripts: BTreeMap<String, Script>,
|
||||
/// The indices to use for the package
|
||||
#[serde(
|
||||
default,
|
||||
|
@ -210,6 +209,24 @@ impl Alias {
|
|||
}
|
||||
}
|
||||
|
||||
/// A script
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(untagged)]
|
||||
#[cfg_attr(test, derive(schemars::JsonSchema))]
|
||||
pub enum Script {
|
||||
/// A path only script
|
||||
#[cfg_attr(test, schemars(with = "std::path::PathBuf"))]
|
||||
Path(RelativePathBuf),
|
||||
/// A script which specifies both its path and its runtime
|
||||
RuntimePath {
|
||||
/// The runtime to execute this script with
|
||||
runtime: RuntimeKind,
|
||||
/// The path of the script to run
|
||||
#[cfg_attr(test, schemars(with = "std::path::PathBuf"))]
|
||||
path: RelativePathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
/// A dependency type
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
|
|
@ -76,6 +76,12 @@ impl TargetKind {
|
|||
pub fn is_roblox(self) -> bool {
|
||||
matches!(self, TargetKind::Roblox | TargetKind::RobloxServer)
|
||||
}
|
||||
|
||||
/// Returns whether this target supports bin exports
|
||||
#[must_use]
|
||||
pub fn has_bin(self) -> bool {
|
||||
!self.is_roblox()
|
||||
}
|
||||
}
|
||||
|
||||
/// A target of a package
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
use crate::Project;
|
||||
use crate::{
|
||||
engine::runtime::{Engines, Runtime},
|
||||
manifest::Script,
|
||||
Project,
|
||||
};
|
||||
use futures::FutureExt as _;
|
||||
use relative_path::RelativePathBuf;
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fmt::{Debug, Display, Formatter},
|
||||
path::PathBuf,
|
||||
process::Stdio,
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncBufReadExt as _, BufReader},
|
||||
process::Command,
|
||||
};
|
||||
use tokio::io::{AsyncBufReadExt as _, BufReader};
|
||||
use tracing::instrument;
|
||||
|
||||
/// Script names used by pesde
|
||||
|
@ -32,33 +34,63 @@ impl Display for ScriptName {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extracts a script and a runtime out of a [Script]
|
||||
pub fn parse_script(
|
||||
script: Script,
|
||||
engines: &Engines,
|
||||
) -> Result<(Runtime, RelativePathBuf), errors::FindScriptError> {
|
||||
Ok(match script {
|
||||
Script::Path(path) => {
|
||||
let runtime = engines
|
||||
.iter()
|
||||
.filter_map(|(engine, ver)| engine.as_runtime().map(|rt| (rt, ver)))
|
||||
.collect::<Vec<_>>();
|
||||
if runtime.len() != 1 {
|
||||
return Err(errors::FindScriptError::AmbiguousRuntime);
|
||||
}
|
||||
|
||||
let (runtime, version) = runtime[0];
|
||||
|
||||
(Runtime::new(runtime, version.clone()), path)
|
||||
}
|
||||
Script::RuntimePath { runtime, path } => {
|
||||
let Some(version) = engines.get(&runtime.into()) else {
|
||||
return Err(errors::FindScriptError::SpecifiedRuntimeUnknown(runtime));
|
||||
};
|
||||
|
||||
(Runtime::new(runtime, version.clone()), path)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Finds a script in the project, whether it be in the current package or it's workspace
|
||||
pub async fn find_script(
|
||||
project: &Project,
|
||||
engines: &Engines,
|
||||
script_name: ScriptName,
|
||||
) -> Result<Option<PathBuf>, errors::FindScriptError> {
|
||||
) -> Result<Option<(Runtime, PathBuf)>, errors::FindScriptError> {
|
||||
let script_name_str = script_name.to_string();
|
||||
|
||||
let script_path = match project
|
||||
let (script, base) = match project
|
||||
.deser_manifest()
|
||||
.await?
|
||||
.scripts
|
||||
.remove(&script_name_str)
|
||||
{
|
||||
Some(script) => script.to_path(project.package_dir()),
|
||||
Some(script) => (script, project.package_dir()),
|
||||
None => match project
|
||||
.deser_workspace_manifest()
|
||||
.await?
|
||||
.and_then(|mut manifest| manifest.scripts.remove(&script_name_str))
|
||||
{
|
||||
Some(script) => script.to_path(project.workspace_dir().unwrap()),
|
||||
Some(script) => (script, project.workspace_dir().unwrap()),
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Some(script_path))
|
||||
parse_script(script, engines).map(|(rt, path)| Some((rt, path.to_path(base))))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
@ -74,20 +106,18 @@ pub(crate) async fn execute_script<
|
|||
>(
|
||||
script_name: ScriptName,
|
||||
project: &Project,
|
||||
engines: &Engines,
|
||||
hooks: H,
|
||||
args: A,
|
||||
return_stdout: bool,
|
||||
) -> Result<Option<String>, errors::ExecuteScriptError> {
|
||||
let Some(script_path) = find_script(project, script_name).await? else {
|
||||
let Some((runtime, script_path)) = find_script(project, engines, script_name).await? else {
|
||||
hooks.not_found(script_name);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
match Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(script_path.as_os_str())
|
||||
.arg("--")
|
||||
.args(args)
|
||||
match runtime
|
||||
.prepare_command(script_path.as_os_str(), args)
|
||||
.current_dir(project.package_dir())
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::piped())
|
||||
|
@ -146,6 +176,8 @@ pub(crate) async fn execute_script<
|
|||
pub mod errors {
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::engine::runtime::RuntimeKind;
|
||||
|
||||
/// Errors that can occur when finding a script
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FindScriptError {
|
||||
|
@ -156,6 +188,14 @@ pub mod errors {
|
|||
/// An IO error occurred
|
||||
#[error("IO error")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
/// Ambiguous runtime
|
||||
#[error("don't know which runtime to use. use specific form and specify the runtime")]
|
||||
AmbiguousRuntime,
|
||||
|
||||
/// Runtime specified in script not in engines
|
||||
#[error("runtime `{0}` was specified in the script, but it is not present in engines")]
|
||||
SpecifiedRuntimeUnknown(RuntimeKind),
|
||||
}
|
||||
|
||||
/// Errors which can occur while executing a script
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
engine::runtime::Engines,
|
||||
manifest::{
|
||||
target::{Target, TargetKind},
|
||||
Alias, DependencyType,
|
||||
|
@ -71,6 +72,8 @@ pub struct GetTargetOptions {
|
|||
pub path: Arc<Path>,
|
||||
/// The package ID of the package to be downloaded
|
||||
pub id: Arc<PackageId>,
|
||||
/// The engines this project is using
|
||||
pub engines: Arc<Engines>,
|
||||
}
|
||||
|
||||
/// A source of packages
|
||||
|
|
|
@ -4,6 +4,7 @@ use relative_path::RelativePathBuf;
|
|||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
engine::runtime::Engines,
|
||||
manifest::target::Target,
|
||||
scripts::{execute_script, ExecuteScriptHooks, ScriptName},
|
||||
source::{
|
||||
|
@ -33,11 +34,13 @@ impl ExecuteScriptHooks for CompatExecuteScriptHooks {
|
|||
|
||||
async fn find_lib_path(
|
||||
project: &Project,
|
||||
engines: &Engines,
|
||||
package_dir: &Path,
|
||||
) -> Result<Option<RelativePathBuf>, errors::GetTargetError> {
|
||||
let Some(result) = execute_script(
|
||||
ScriptName::SourcemapGenerator,
|
||||
project,
|
||||
engines,
|
||||
CompatExecuteScriptHooks,
|
||||
[package_dir],
|
||||
true,
|
||||
|
@ -60,9 +63,14 @@ pub(crate) const WALLY_MANIFEST_FILE_NAME: &str = "wally.toml";
|
|||
pub(crate) async fn get_target(
|
||||
options: &GetTargetOptions,
|
||||
) -> Result<Target, errors::GetTargetError> {
|
||||
let GetTargetOptions { project, path, .. } = options;
|
||||
let GetTargetOptions {
|
||||
project,
|
||||
path,
|
||||
engines,
|
||||
..
|
||||
} = options;
|
||||
|
||||
let lib = find_lib_path(project, path)
|
||||
let lib = find_lib_path(project, engines, path)
|
||||
.await?
|
||||
.or_else(|| Some(RelativePathBuf::from(LINK_LIB_NO_FILE_FOUND)));
|
||||
let build_files = Default::default();
|
||||
|
|
Loading…
Add table
Reference in a new issue