mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-05 19:30:57 +01:00
feat: inherit pesde-managed scripts from workspace root
Some checks are pending
Debug / Get build version (push) Waiting to run
Debug / Build for linux-x86_64 (push) Blocked by required conditions
Debug / Build for macos-aarch64 (push) Blocked by required conditions
Debug / Build for macos-x86_64 (push) Blocked by required conditions
Debug / Build for windows-x86_64 (push) Blocked by required conditions
Test & Lint / lint (push) Waiting to run
Some checks are pending
Debug / Get build version (push) Waiting to run
Debug / Build for linux-x86_64 (push) Blocked by required conditions
Debug / Build for macos-aarch64 (push) Blocked by required conditions
Debug / Build for macos-x86_64 (push) Blocked by required conditions
Debug / Build for windows-x86_64 (push) Blocked by required conditions
Test & Lint / lint (push) Waiting to run
This commit is contained in:
parent
2700fe9e07
commit
7f15264f48
11 changed files with 333 additions and 188 deletions
|
@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Support using aliases of own dependencies for overrides by @daimond113
|
||||
- Support ignoring parse errors in Luau files by @daimond113
|
||||
- Add path dependencies by @daimond113
|
||||
- Inherit pesde-managed scripts from workspace root by @daimond113
|
||||
- Allow using binaries from workspace root in member packages by @daimond113
|
||||
|
||||
### Removed
|
||||
- Remove old includes format compatibility by @daimond113
|
||||
|
|
80
src/cli/bin_link.luau
Normal file
80
src/cli/bin_link.luau
Normal file
|
@ -0,0 +1,80 @@
|
|||
local process = require("@lune/process")
|
||||
local fs = require("@lune/fs")
|
||||
local stdio = require("@lune/stdio")
|
||||
local serde = require("@lune/serde")
|
||||
|
||||
local project_root = nil
|
||||
local path_components = string.split(string.gsub(process.cwd, "\\", "/"), "/")
|
||||
if path_components[#path_components] == "" then
|
||||
table.remove(path_components)
|
||||
end
|
||||
|
||||
local function in_lockfile(lockfile)
|
||||
if not lockfile.graph then
|
||||
return false
|
||||
end
|
||||
|
||||
for _, versions in lockfile.graph do
|
||||
for _, node in versions do
|
||||
if node.direct and node.direct[1] == "{alias}" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
for i = #path_components, 1, -1 do
|
||||
local path = table.concat(path_components, "/", 1, i)
|
||||
if not fs.isFile(path .. "/{MANIFEST_FILE_NAME}") then
|
||||
continue
|
||||
end
|
||||
|
||||
if project_root == nil then
|
||||
project_root = path
|
||||
end
|
||||
|
||||
if project_root and fs.isFile(path .. "/{LOCKFILE_FILE_NAME}") then
|
||||
local lockfile = serde.decode("toml", fs.readFile(path .. "/{LOCKFILE_FILE_NAME}"))
|
||||
if not lockfile.workspace then
|
||||
continue
|
||||
end
|
||||
|
||||
local search_for = string.gsub(project_root, path, "")
|
||||
if string.sub(search_for, 1, 1) == "/" then
|
||||
search_for = string.sub(search_for, 2)
|
||||
end
|
||||
|
||||
if search_for == "" then
|
||||
if in_lockfile(lockfile) then
|
||||
break
|
||||
end
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
for _, targets in lockfile.workspace do
|
||||
for _, member_path in targets do
|
||||
local path_normalized = string.gsub(member_path, "\\", "/")
|
||||
if path_normalized == search_for and in_lockfile(lockfile) then
|
||||
project_root = path
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if project_root ~= nil then
|
||||
for _, packages_folder in {{ {all_folders} }} do
|
||||
local path = `{{project_root}}/{{packages_folder}}/{alias}.bin.luau`
|
||||
|
||||
if fs.isFile(path) then
|
||||
require(path)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
stdio.ewrite(stdio.color("red") .. "binary `{alias}` not found. are you in the right directory?" .. stdio.color("reset") .. "\n")
|
|
@ -13,7 +13,7 @@ use pesde::{
|
|||
download_and_link::{filter_graph, DownloadAndLinkHooks, DownloadAndLinkOptions},
|
||||
lockfile::{DependencyGraph, DownloadedGraph, Lockfile},
|
||||
manifest::{target::TargetKind, DependencyType},
|
||||
Project, RefreshedSources, MANIFEST_FILE_NAME,
|
||||
Project, RefreshedSources, LOCKFILE_FILE_NAME, MANIFEST_FILE_NAME,
|
||||
};
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
|
@ -43,32 +43,11 @@ fn bin_link_file(alias: &str) -> String {
|
|||
.join(", ");
|
||||
|
||||
format!(
|
||||
r#"local process = require("@lune/process")
|
||||
local fs = require("@lune/fs")
|
||||
local stdio = require("@lune/stdio")
|
||||
|
||||
local project_root = process.cwd
|
||||
local path_components = string.split(string.gsub(project_root, "\\", "/"), "/")
|
||||
|
||||
for i = #path_components, 1, -1 do
|
||||
local path = table.concat(path_components, "/", 1, i)
|
||||
if fs.isFile(path .. "/{MANIFEST_FILE_NAME}") then
|
||||
project_root = path
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
for _, packages_folder in {{ {all_folders} }} do
|
||||
local path = `{{project_root}}/{{packages_folder}}/{alias}.bin.luau`
|
||||
|
||||
if fs.isFile(path) then
|
||||
require(path)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
stdio.ewrite(stdio.color("red") .. "binary `{alias}` not found. are you in the right directory?" .. stdio.color("reset") .. "\n")
|
||||
"#,
|
||||
include_str!("bin_link.luau"),
|
||||
alias = alias,
|
||||
all_folders = all_folders,
|
||||
MANIFEST_FILE_NAME = MANIFEST_FILE_NAME,
|
||||
LOCKFILE_FILE_NAME = LOCKFILE_FILE_NAME
|
||||
)
|
||||
}
|
||||
|
||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -1,4 +1,4 @@
|
|||
#![deny(missing_docs)]
|
||||
#![warn(missing_docs, clippy::redundant_closure_for_method_calls)]
|
||||
//! A package manager for the Luau programming language, supporting multiple runtimes including Roblox and Lune.
|
||||
//! pesde has its own registry, however it can also use Wally, and Git repositories as package sources.
|
||||
//! It has been designed with multiple targets in mind, namely Roblox, Lune, and Luau.
|
||||
|
@ -185,6 +185,18 @@ impl Project {
|
|||
deser_manifest(self.package_dir()).await
|
||||
}
|
||||
|
||||
/// Deserialize the manifest file of the workspace root
|
||||
#[instrument(skip(self), ret(level = "trace"), level = "debug")]
|
||||
pub async fn deser_workspace_manifest(
|
||||
&self,
|
||||
) -> Result<Option<Manifest>, errors::ManifestReadError> {
|
||||
let Some(workspace_dir) = self.workspace_dir() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
deser_manifest(workspace_dir).await.map(Some)
|
||||
}
|
||||
|
||||
/// Write the manifest file
|
||||
#[instrument(skip(self, manifest), level = "debug")]
|
||||
pub async fn write_manifest<S: AsRef<[u8]>>(&self, manifest: S) -> Result<(), std::io::Error> {
|
||||
|
@ -227,7 +239,7 @@ impl Project {
|
|||
|
||||
let members = matching_globs(
|
||||
dir,
|
||||
manifest.workspace_members.iter().map(|s| s.as_str()),
|
||||
manifest.workspace_members.iter().map(String::as_str),
|
||||
false,
|
||||
can_ref_self,
|
||||
)
|
||||
|
@ -356,7 +368,7 @@ pub async fn find_roots(
|
|||
|
||||
matching_globs(
|
||||
path,
|
||||
manifest.workspace_members.iter().map(|s| s.as_str()),
|
||||
manifest.workspace_members.iter().map(String::as_str),
|
||||
false,
|
||||
false,
|
||||
)
|
||||
|
@ -365,7 +377,7 @@ pub async fn find_roots(
|
|||
}
|
||||
|
||||
while let Some(path) = current_path {
|
||||
current_path = path.parent().map(|p| p.to_path_buf());
|
||||
current_path = path.parent().map(Path::to_path_buf);
|
||||
|
||||
if !path.join(MANIFEST_FILE_NAME).exists() {
|
||||
continue;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
lockfile::{DownloadedDependencyGraphNode, DownloadedGraph},
|
||||
manifest::Manifest,
|
||||
names::PackageNames,
|
||||
scripts::{execute_script, ScriptName},
|
||||
scripts::{execute_script, ExecuteScriptHooks, ScriptName},
|
||||
source::{
|
||||
fs::{cas_path, store_in_cas},
|
||||
traits::PackageRef,
|
||||
|
@ -43,6 +43,17 @@ async fn write_cas(destination: PathBuf, cas_dir: &Path, contents: &str) -> std:
|
|||
fs::hard_link(cas_path(&hash, cas_dir), destination).await
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct LinkingExecuteScriptHooks;
|
||||
|
||||
impl ExecuteScriptHooks for LinkingExecuteScriptHooks {
|
||||
fn not_found(&self, script: ScriptName) {
|
||||
tracing::warn!(
|
||||
"not having a `{script}` script in the manifest might cause issues with linking"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Project {
|
||||
/// Links the dependencies of the project
|
||||
#[instrument(skip(self, graph), level = "debug")]
|
||||
|
@ -65,86 +76,80 @@ impl Project {
|
|||
}
|
||||
|
||||
// step 2. extract the types from libraries, prepare Roblox packages for syncing
|
||||
let roblox_sync_config_gen_script = manifest
|
||||
.scripts
|
||||
.get(&ScriptName::RobloxSyncConfigGenerator.to_string());
|
||||
|
||||
let package_types = try_join_all(graph.iter().map(|(name, versions)| async move {
|
||||
Ok::<_, errors::LinkingError>((
|
||||
name,
|
||||
try_join_all(versions.iter().map(|(version_id, node)| async move {
|
||||
let Some(lib_file) = node.target.lib_path() else {
|
||||
return Ok((version_id, vec![]));
|
||||
};
|
||||
|
||||
let container_folder = node.node.container_folder(
|
||||
&self
|
||||
.package_dir()
|
||||
.join(manifest_target_kind.packages_folder(version_id.target()))
|
||||
.join(PACKAGES_CONTAINER_NAME),
|
||||
name,
|
||||
version_id.version(),
|
||||
);
|
||||
|
||||
let types = if lib_file.as_str() != LINK_LIB_NO_FILE_FOUND {
|
||||
let lib_file = lib_file.to_path(&container_folder);
|
||||
|
||||
let contents = match fs::read_to_string(&lib_file).await {
|
||||
Ok(contents) => contents,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
return Err(errors::LinkingError::LibFileNotFound(
|
||||
lib_file.display().to_string(),
|
||||
));
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
try_join_all(versions.iter().map(|(version_id, node)| {
|
||||
async move {
|
||||
let Some(lib_file) = node.target.lib_path() else {
|
||||
return Ok((version_id, vec![]));
|
||||
};
|
||||
|
||||
let types = spawn_blocking(move || get_file_types(&contents))
|
||||
let container_folder = node.node.container_folder(
|
||||
&self
|
||||
.package_dir()
|
||||
.join(manifest_target_kind.packages_folder(version_id.target()))
|
||||
.join(PACKAGES_CONTAINER_NAME),
|
||||
name,
|
||||
version_id.version(),
|
||||
);
|
||||
|
||||
let types = if lib_file.as_str() != LINK_LIB_NO_FILE_FOUND {
|
||||
let lib_file = lib_file.to_path(&container_folder);
|
||||
|
||||
let contents = match fs::read_to_string(&lib_file).await {
|
||||
Ok(contents) => contents,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
return Err(errors::LinkingError::LibFileNotFound(
|
||||
lib_file.display().to_string(),
|
||||
));
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
let types = spawn_blocking(move || get_file_types(&contents))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tracing::debug!("contains {} exported types", types.len());
|
||||
|
||||
types
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
if let Some(build_files) = Some(&node.target)
|
||||
.filter(|_| !node.node.pkg_ref.like_wally())
|
||||
.and_then(|t| t.build_files())
|
||||
{
|
||||
execute_script(
|
||||
ScriptName::RobloxSyncConfigGenerator,
|
||||
self,
|
||||
LinkingExecuteScriptHooks,
|
||||
std::iter::once(container_folder.as_os_str())
|
||||
.chain(build_files.iter().map(OsStr::new)),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.map_err(errors::LinkingError::ExecuteScript)?;
|
||||
}
|
||||
|
||||
tracing::debug!("contains {} exported types", types.len());
|
||||
|
||||
types
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
if let Some(build_files) = Some(&node.target)
|
||||
.filter(|_| !node.node.pkg_ref.like_wally())
|
||||
.and_then(|t| t.build_files())
|
||||
{
|
||||
let Some(script_path) = roblox_sync_config_gen_script else {
|
||||
tracing::warn!("not having a `{}` script in the manifest might cause issues with Roblox linking", ScriptName::RobloxSyncConfigGenerator);
|
||||
return Ok((version_id, types));
|
||||
};
|
||||
|
||||
execute_script(
|
||||
ScriptName::RobloxSyncConfigGenerator,
|
||||
&script_path.to_path(self.package_dir()),
|
||||
std::iter::once(container_folder.as_os_str())
|
||||
.chain(build_files.iter().map(OsStr::new)),
|
||||
self,
|
||||
false,
|
||||
).await
|
||||
.map_err(|e| {
|
||||
errors::LinkingError::GenerateRobloxSyncConfig(
|
||||
container_folder.display().to_string(),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
Ok((version_id, types))
|
||||
}
|
||||
|
||||
Ok((version_id, types))
|
||||
}.instrument(tracing::info_span!("extract types", name = name.to_string(), version_id = version_id.to_string()))))
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>(),
|
||||
.instrument(tracing::info_span!(
|
||||
"extract types",
|
||||
name = name.to_string(),
|
||||
version_id = version_id.to_string()
|
||||
))
|
||||
}))
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>(),
|
||||
))
|
||||
}))
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// step 3. link all packages (and their dependencies), this time with types
|
||||
self.link(graph, &manifest, &Arc::new(package_types), true)
|
||||
|
@ -375,9 +380,9 @@ pub mod errors {
|
|||
#[error("library file at {0} not found")]
|
||||
LibFileNotFound(String),
|
||||
|
||||
/// An error occurred while generating a Roblox sync config
|
||||
#[error("error generating roblox sync config for {0}")]
|
||||
GenerateRobloxSyncConfig(String, #[source] std::io::Error),
|
||||
/// Executing a script failed
|
||||
#[error("error executing script")]
|
||||
ExecuteScript(#[from] crate::scripts::errors::ExecuteScriptError),
|
||||
|
||||
/// An error occurred while getting the require path for a library
|
||||
#[error("error getting require path for library")]
|
||||
|
|
|
@ -18,7 +18,7 @@ impl FromStr for OverrideKey {
|
|||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let overrides = s
|
||||
.split(',')
|
||||
.map(|overrides| overrides.split('>').map(|s| s.to_string()).collect())
|
||||
.map(|overrides| overrides.split('>').map(ToString::to_string).collect())
|
||||
.collect::<Vec<Vec<String>>>();
|
||||
|
||||
if overrides.is_empty() {
|
||||
|
@ -39,7 +39,7 @@ impl Display for OverrideKey {
|
|||
.map(|overrides| {
|
||||
overrides
|
||||
.iter()
|
||||
.map(|o| o.as_str())
|
||||
.map(String::as_str)
|
||||
.collect::<Vec<_>>()
|
||||
.join(">")
|
||||
})
|
||||
|
|
|
@ -382,7 +382,7 @@ impl Project {
|
|||
tracing::debug!(
|
||||
"overridden specifier found for {} ({dependency_spec})",
|
||||
path.iter()
|
||||
.map(|s| s.as_str())
|
||||
.map(String::as_str)
|
||||
.chain(std::iter::once(dependency_alias.as_str()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(">"),
|
||||
|
|
142
src/scripts.rs
142
src/scripts.rs
|
@ -1,8 +1,9 @@
|
|||
use crate::Project;
|
||||
use futures::FutureExt;
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fmt::{Debug, Display, Formatter},
|
||||
path::Path,
|
||||
path::PathBuf,
|
||||
process::Stdio,
|
||||
};
|
||||
use tokio::{
|
||||
|
@ -31,14 +32,57 @@ impl Display for ScriptName {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(project), level = "debug")]
|
||||
pub(crate) async fn execute_script<A: IntoIterator<Item = S> + Debug, S: AsRef<OsStr> + Debug>(
|
||||
script_name: ScriptName,
|
||||
script_path: &Path,
|
||||
args: A,
|
||||
/// Finds a script in the project, whether it be in the current package or it's workspace
|
||||
pub async fn find_script(
|
||||
project: &Project,
|
||||
script_name: ScriptName,
|
||||
) -> Result<Option<PathBuf>, errors::FindScriptError> {
|
||||
let script_name_str = script_name.to_string();
|
||||
|
||||
let script_path = match project
|
||||
.deser_manifest()
|
||||
.await?
|
||||
.scripts
|
||||
.remove(&script_name_str)
|
||||
{
|
||||
Some(script) => script.to_path(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()),
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Some(script_path))
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) trait ExecuteScriptHooks {
|
||||
fn not_found(&self, script: ScriptName) {}
|
||||
}
|
||||
|
||||
#[instrument(skip(project, hooks), level = "debug")]
|
||||
pub(crate) async fn execute_script<
|
||||
A: IntoIterator<Item = S> + Debug,
|
||||
S: AsRef<OsStr> + Debug,
|
||||
H: ExecuteScriptHooks,
|
||||
>(
|
||||
script_name: ScriptName,
|
||||
project: &Project,
|
||||
hooks: H,
|
||||
args: A,
|
||||
return_stdout: bool,
|
||||
) -> Result<Option<String>, std::io::Error> {
|
||||
) -> Result<Option<String>, errors::ExecuteScriptError> {
|
||||
let Some(script_path) = find_script(project, script_name).await? else {
|
||||
hooks.not_found(script_name);
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
match Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(script_path.as_os_str())
|
||||
|
@ -54,39 +98,32 @@ pub(crate) async fn execute_script<A: IntoIterator<Item = S> + Debug, S: AsRef<O
|
|||
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
|
||||
let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();
|
||||
|
||||
let script = script_name.to_string();
|
||||
let script_2 = script.to_string();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(line) = stderr.next_line().await.transpose() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
tracing::error!("[{script}]: {line}");
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("ERROR IN READING STDERR OF {script}: {e}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut stdout_str = String::new();
|
||||
|
||||
while let Some(line) = stdout.next_line().await.transpose() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
if return_stdout {
|
||||
stdout_str.push_str(&line);
|
||||
stdout_str.push('\n');
|
||||
} else {
|
||||
tracing::info!("[{script_2}]: {line}");
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(line) = stdout.next_line().map(Result::transpose) => match line {
|
||||
Ok(line) => {
|
||||
if return_stdout {
|
||||
stdout_str.push_str(&line);
|
||||
stdout_str.push('\n');
|
||||
} else {
|
||||
tracing::info!("[{script_name}]: {line}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("ERROR IN READING STDOUT OF {script_2}: {e}");
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("ERROR IN READING STDOUT OF {script_name}: {e}");
|
||||
}
|
||||
},
|
||||
Some(line) = stderr.next_line().map(Result::transpose) => match line {
|
||||
Ok(line) => {
|
||||
tracing::error!("[{script_name}]: {line}");
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("ERROR IN READING STDERR OF {script_name}: {e}");
|
||||
}
|
||||
},
|
||||
else => break,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +138,35 @@ pub(crate) async fn execute_script<A: IntoIterator<Item = S> + Debug, S: AsRef<O
|
|||
|
||||
Ok(None)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur when using scripts
|
||||
pub mod errors {
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can occur when finding a script
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FindScriptError {
|
||||
/// Reading the manifest failed
|
||||
#[error("error reading manifest")]
|
||||
ManifestRead(#[from] crate::errors::ManifestReadError),
|
||||
|
||||
/// An IO error occurred
|
||||
#[error("IO error")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
/// Errors which can occur while executing a script
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExecuteScriptError {
|
||||
/// Finding the script failed
|
||||
#[error("finding the script failed")]
|
||||
FindScript(#[from] FindScriptError),
|
||||
|
||||
/// An IO error occurred
|
||||
#[error("IO error")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -690,10 +690,10 @@ pub mod errors {
|
|||
#[error("error interacting with the file system")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
/// An error occurred while searching for a Wally lib export
|
||||
/// An error occurred while creating a Wally target
|
||||
#[cfg(feature = "wally-compat")]
|
||||
#[error("error searching for Wally lib export")]
|
||||
FindLibPath(#[from] crate::source::wally::compat_util::errors::FindLibPathError),
|
||||
#[error("error creating Wally target")]
|
||||
GetTarget(#[from] crate::source::wally::compat_util::errors::GetTargetError),
|
||||
|
||||
/// No manifest was found
|
||||
#[error("no manifest found in repository {0}")]
|
||||
|
|
|
@ -6,7 +6,7 @@ use tempfile::TempDir;
|
|||
|
||||
use crate::{
|
||||
manifest::target::Target,
|
||||
scripts::{execute_script, ScriptName},
|
||||
scripts::{execute_script, ExecuteScriptHooks, ScriptName},
|
||||
source::wally::manifest::{Realm, WallyManifest},
|
||||
Project, LINK_LIB_NO_FILE_FOUND,
|
||||
};
|
||||
|
@ -20,39 +20,36 @@ struct SourcemapNode {
|
|||
file_paths: Vec<RelativePathBuf>,
|
||||
}
|
||||
|
||||
#[instrument(skip(project, package_dir), level = "debug")]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct CompatExecuteScriptHooks;
|
||||
|
||||
impl ExecuteScriptHooks for CompatExecuteScriptHooks {
|
||||
fn not_found(&self, script: ScriptName) {
|
||||
tracing::warn!("no {script} found in project. wally types will not be generated");
|
||||
}
|
||||
}
|
||||
|
||||
async fn find_lib_path(
|
||||
project: &Project,
|
||||
package_dir: &Path,
|
||||
) -> Result<Option<RelativePathBuf>, errors::FindLibPathError> {
|
||||
let manifest = project.deser_manifest().await?;
|
||||
|
||||
let Some(script_path) = manifest
|
||||
.scripts
|
||||
.get(&ScriptName::SourcemapGenerator.to_string())
|
||||
else {
|
||||
tracing::warn!("no sourcemap generator script found in manifest");
|
||||
) -> Result<Option<RelativePathBuf>, errors::GetTargetError> {
|
||||
let Some(result) = execute_script(
|
||||
ScriptName::SourcemapGenerator,
|
||||
project,
|
||||
CompatExecuteScriptHooks,
|
||||
[package_dir],
|
||||
true,
|
||||
)
|
||||
.await?
|
||||
.filter(|result| !result.is_empty()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let result = execute_script(
|
||||
ScriptName::SourcemapGenerator,
|
||||
&script_path.to_path(project.package_dir()),
|
||||
[package_dir],
|
||||
project,
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(result) = result.filter(|result| !result.is_empty()) {
|
||||
let node: SourcemapNode = serde_json::from_str(&result)?;
|
||||
Ok(node.file_paths.into_iter().find(|path| {
|
||||
path.extension()
|
||||
.is_some_and(|ext| ext == "lua" || ext == "luau")
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
let node: SourcemapNode = serde_json::from_str(&result)?;
|
||||
Ok(node.file_paths.into_iter().find(|path| {
|
||||
path.extension()
|
||||
.is_some_and(|ext| ext == "lua" || ext == "luau")
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) const WALLY_MANIFEST_FILE_NAME: &str = "wally.toml";
|
||||
|
@ -61,7 +58,7 @@ pub(crate) const WALLY_MANIFEST_FILE_NAME: &str = "wally.toml";
|
|||
pub(crate) async fn get_target(
|
||||
project: &Project,
|
||||
tempdir: &TempDir,
|
||||
) -> Result<Target, errors::FindLibPathError> {
|
||||
) -> Result<Target, errors::GetTargetError> {
|
||||
let lib = find_lib_path(project, tempdir.path())
|
||||
.await?
|
||||
.or_else(|| Some(RelativePathBuf::from(LINK_LIB_NO_FILE_FOUND)));
|
||||
|
@ -84,14 +81,14 @@ pub mod errors {
|
|||
/// Errors that can occur when finding the lib path
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum FindLibPathError {
|
||||
/// An error occurred deserializing the project manifest
|
||||
#[error("error deserializing manifest")]
|
||||
Manifest(#[from] crate::errors::ManifestReadError),
|
||||
pub enum GetTargetError {
|
||||
/// Reading the manifest failed
|
||||
#[error("error reading manifest")]
|
||||
ManifestRead(#[from] crate::errors::ManifestReadError),
|
||||
|
||||
/// An error occurred while executing the sourcemap generator script
|
||||
#[error("error executing sourcemap generator script")]
|
||||
Script(#[from] std::io::Error),
|
||||
/// An error occurred while executing a script
|
||||
#[error("error executing script")]
|
||||
ExecuteScript(#[from] crate::scripts::errors::ExecuteScriptError),
|
||||
|
||||
/// An error occurred while deserializing the sourcemap result
|
||||
#[error("error deserializing sourcemap result")]
|
||||
|
@ -100,5 +97,9 @@ pub mod errors {
|
|||
/// An error occurred while deserializing the wally manifest
|
||||
#[error("error deserializing wally manifest")]
|
||||
WallyManifest(#[from] toml::de::Error),
|
||||
|
||||
/// IO error
|
||||
#[error("io error")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,9 +464,9 @@ pub mod errors {
|
|||
#[error("error serializing index file")]
|
||||
SerializeIndex(#[from] toml::ser::Error),
|
||||
|
||||
/// Error getting lib path
|
||||
#[error("error getting lib path")]
|
||||
LibPath(#[from] crate::source::wally::compat_util::errors::FindLibPathError),
|
||||
/// Creating the target failed
|
||||
#[error("error creating a target")]
|
||||
GetTarget(#[from] crate::source::wally::compat_util::errors::GetTargetError),
|
||||
|
||||
/// Error writing index file
|
||||
#[error("error writing index file")]
|
||||
|
|
Loading…
Add table
Reference in a new issue