mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: add roblox server target
This commit is contained in:
parent
30c4d0c391
commit
10c804e2f3
10 changed files with 232 additions and 75 deletions
|
@ -2,7 +2,10 @@ use crate::{error::Error, storage::StorageImpl};
|
||||||
use actix_web::{http::header::LOCATION, HttpResponse};
|
use actix_web::{http::header::LOCATION, HttpResponse};
|
||||||
use pesde::{names::PackageName, source::version_id::VersionId};
|
use pesde::{names::PackageName, source::version_id::VersionId};
|
||||||
use reqwest::header::{CONTENT_ENCODING, CONTENT_TYPE};
|
use reqwest::header::{CONTENT_ENCODING, CONTENT_TYPE};
|
||||||
use rusty_s3::{actions::PutObject, Bucket, Credentials, S3Action};
|
use rusty_s3::{
|
||||||
|
actions::{GetObject, PutObject},
|
||||||
|
Bucket, Credentials, S3Action,
|
||||||
|
};
|
||||||
use std::{fmt::Display, time::Duration};
|
use std::{fmt::Display, time::Duration};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -48,7 +51,7 @@ impl StorageImpl for S3Storage {
|
||||||
package_name: &PackageName,
|
package_name: &PackageName,
|
||||||
version: &VersionId,
|
version: &VersionId,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let object_url = PutObject::new(
|
let object_url = GetObject::new(
|
||||||
&self.s3_bucket,
|
&self.s3_bucket,
|
||||||
Some(&self.s3_credentials),
|
Some(&self.s3_credentials),
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -97,7 +100,7 @@ impl StorageImpl for S3Storage {
|
||||||
package_name: &PackageName,
|
package_name: &PackageName,
|
||||||
version: &VersionId,
|
version: &VersionId,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let object_url = PutObject::new(
|
let object_url = GetObject::new(
|
||||||
&self.s3_bucket,
|
&self.s3_bucket,
|
||||||
Some(&self.s3_credentials),
|
Some(&self.s3_credentials),
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -133,7 +136,7 @@ impl StorageImpl for S3Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_doc(&self, doc_hash: &str) -> Result<HttpResponse, Error> {
|
async fn get_doc(&self, doc_hash: &str) -> Result<HttpResponse, Error> {
|
||||||
let object_url = PutObject::new(
|
let object_url = GetObject::new(
|
||||||
&self.s3_bucket,
|
&self.s3_bucket,
|
||||||
Some(&self.s3_credentials),
|
Some(&self.s3_credentials),
|
||||||
&format!("doc/{}.gz", doc_hash),
|
&format!("doc/{}.gz", doc_hash),
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use std::{
|
|
||||||
io::{Seek, Write},
|
|
||||||
path::Component,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
use std::{
|
||||||
|
io::{Seek, Write},
|
||||||
|
path::Component,
|
||||||
|
};
|
||||||
use tempfile::tempfile;
|
use tempfile::tempfile;
|
||||||
|
|
||||||
|
use crate::cli::up_to_date_lockfile;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::target::Target,
|
manifest::{target::Target, DependencyType},
|
||||||
scripts::ScriptName,
|
scripts::ScriptName,
|
||||||
source::{
|
source::{
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
|
@ -42,10 +42,39 @@ impl PublishCommand {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest
|
if manifest.target.lib_path().is_none() && manifest.target.bin_path().is_none() {
|
||||||
.target
|
anyhow::bail!("no exports found in target");
|
||||||
.validate_publish()
|
}
|
||||||
.context("manifest not fit for publishing")?;
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
if matches!(
|
||||||
|
manifest.target,
|
||||||
|
Target::Roblox { .. } | Target::RobloxServer { .. }
|
||||||
|
) {
|
||||||
|
if !manifest.target.build_files().is_some_and(|f| !f.is_empty()) {
|
||||||
|
anyhow::bail!("no build files found in target");
|
||||||
|
}
|
||||||
|
|
||||||
|
match up_to_date_lockfile(&project)? {
|
||||||
|
Some(lockfile) => {
|
||||||
|
if lockfile
|
||||||
|
.graph
|
||||||
|
.values()
|
||||||
|
.flatten()
|
||||||
|
.filter_map(|(_, node)| node.node.direct.as_ref().map(|_| node))
|
||||||
|
.any(|node| {
|
||||||
|
node.target.build_files().is_none()
|
||||||
|
&& !matches!(node.node.ty, DependencyType::Dev)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
anyhow::bail!("roblox packages may not depend on non-roblox packages");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
anyhow::bail!("outdated lockfile, please run the install command first")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut archive = tar::Builder::new(flate2::write::GzEncoder::new(
|
let mut archive = tar::Builder::new(flate2::write::GzEncoder::new(
|
||||||
vec![],
|
vec![],
|
||||||
|
@ -65,6 +94,7 @@ impl PublishCommand {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
let mut roblox_target = match &mut manifest.target {
|
let mut roblox_target = match &mut manifest.target {
|
||||||
Target::Roblox { build_files, .. } => Some(build_files),
|
Target::Roblox { build_files, .. } => Some(build_files),
|
||||||
|
Target::RobloxServer { build_files, .. } => Some(build_files),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
#[cfg(not(feature = "roblox"))]
|
#[cfg(not(feature = "roblox"))]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::{Component, Path};
|
use std::path::{Component, Path};
|
||||||
|
|
||||||
use crate::manifest::target::TargetKind;
|
use crate::manifest::{target::TargetKind, Manifest};
|
||||||
use full_moon::{ast::luau::ExportedTypeDeclaration, visitors::Visitor};
|
use full_moon::{ast::luau::ExportedTypeDeclaration, visitors::Visitor};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
|
@ -82,14 +82,20 @@ fn luau_style_path(path: &Path) -> String {
|
||||||
format!("{require:?}")
|
format!("{require:?}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function should be simplified (especially to reduce the number of arguments),
|
||||||
|
// but it's not clear how to do that while maintaining the current functionality.
|
||||||
/// Get the require path for a library
|
/// Get the require path for a library
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn get_lib_require_path(
|
pub fn get_lib_require_path(
|
||||||
target: &TargetKind,
|
target: &TargetKind,
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
lib_file: &RelativePathBuf,
|
lib_file: &RelativePathBuf,
|
||||||
destination_dir: &Path,
|
destination_dir: &Path,
|
||||||
use_new_structure: bool,
|
use_new_structure: bool,
|
||||||
) -> String {
|
root_container_dir: &Path,
|
||||||
|
container_dir: &Path,
|
||||||
|
project_manifest: &Manifest,
|
||||||
|
) -> Result<String, errors::GetLibRequirePath> {
|
||||||
let path = pathdiff::diff_paths(destination_dir, base_dir).unwrap();
|
let path = pathdiff::diff_paths(destination_dir, base_dir).unwrap();
|
||||||
let path = if use_new_structure {
|
let path = if use_new_structure {
|
||||||
log::debug!("using new structure for require path with {:?}", lib_file);
|
log::debug!("using new structure for require path with {:?}", lib_file);
|
||||||
|
@ -100,7 +106,25 @@ pub fn get_lib_require_path(
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
if matches!(target, TargetKind::Roblox) {
|
if matches!(target, TargetKind::Roblox | TargetKind::RobloxServer) {
|
||||||
|
let (prefix, path) = match target.try_into() {
|
||||||
|
Ok(place_kind) if !destination_dir.starts_with(root_container_dir) => (
|
||||||
|
project_manifest
|
||||||
|
.place
|
||||||
|
.get(&place_kind)
|
||||||
|
.ok_or(errors::GetLibRequirePath::RobloxPlaceKindPathNotFound(
|
||||||
|
place_kind,
|
||||||
|
))?
|
||||||
|
.as_str(),
|
||||||
|
if use_new_structure {
|
||||||
|
lib_file.to_path(container_dir)
|
||||||
|
} else {
|
||||||
|
container_dir.to_path_buf()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => ("script.Parent", path),
|
||||||
|
};
|
||||||
|
|
||||||
let path = path
|
let path = path
|
||||||
.components()
|
.components()
|
||||||
.filter_map(|component| match component {
|
.filter_map(|component| match component {
|
||||||
|
@ -118,10 +142,10 @@ pub fn get_lib_require_path(
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
return format!("script.Parent{path}");
|
return Ok(format!("{prefix}{path}"));
|
||||||
};
|
};
|
||||||
|
|
||||||
luau_style_path(&path)
|
Ok(luau_style_path(&path))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a linking module for a binary
|
/// Generate a linking module for a binary
|
||||||
|
@ -144,3 +168,17 @@ pub fn get_bin_require_path(
|
||||||
|
|
||||||
luau_style_path(&path)
|
luau_style_path(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors for the linking module utilities
|
||||||
|
pub mod errors {
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// An error occurred while getting the require path for a library
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum GetLibRequirePath {
|
||||||
|
/// The path for the RobloxPlaceKind could not be found
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
#[error("could not find the path for the RobloxPlaceKind {0}")]
|
||||||
|
RobloxPlaceKindPathNotFound(crate::manifest::target::RobloxPlaceKind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
linking::generator::get_file_types,
|
linking::generator::get_file_types,
|
||||||
lockfile::DownloadedGraph,
|
lockfile::DownloadedGraph,
|
||||||
manifest::target::Target,
|
|
||||||
names::PackageNames,
|
names::PackageNames,
|
||||||
scripts::{execute_script, ScriptName},
|
scripts::{execute_script, ScriptName},
|
||||||
source::{fs::store_in_cas, traits::PackageRef, version_id::VersionId},
|
source::{fs::store_in_cas, traits::PackageRef, version_id::VersionId},
|
||||||
|
@ -92,8 +91,9 @@ impl Project {
|
||||||
.insert(version_id, types);
|
.insert(version_id, types);
|
||||||
|
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
if let Some(Target::Roblox { build_files, .. }) =
|
if let Some(build_files) = Some(&node.target)
|
||||||
Some(&node.target).filter(|_| !node.node.pkg_ref.like_wally())
|
.filter(|_| !node.node.pkg_ref.like_wally())
|
||||||
|
.and_then(|t| t.build_files())
|
||||||
{
|
{
|
||||||
let script_name = ScriptName::RobloxSyncConfigGenerator.to_string();
|
let script_name = ScriptName::RobloxSyncConfigGenerator.to_string();
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ impl Project {
|
||||||
|
|
||||||
for (name, versions) in graph {
|
for (name, versions) in graph {
|
||||||
for (version_id, node) in versions {
|
for (version_id, node) in versions {
|
||||||
let node_container_folder = {
|
let (node_container_folder, node_packages_folder) = {
|
||||||
let base_folder = create_and_canonicalize(
|
let base_folder = create_and_canonicalize(
|
||||||
self.package_dir().join(
|
self.package_dir().join(
|
||||||
manifest
|
manifest
|
||||||
|
@ -158,7 +158,10 @@ impl Project {
|
||||||
lib_file,
|
lib_file,
|
||||||
&container_folder,
|
&container_folder,
|
||||||
node.node.pkg_ref.use_new_structure(),
|
node.node.pkg_ref.use_new_structure(),
|
||||||
),
|
&base_folder,
|
||||||
|
container_folder.strip_prefix(&base_folder).unwrap(),
|
||||||
|
&manifest,
|
||||||
|
)?,
|
||||||
types,
|
types,
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
|
@ -180,7 +183,7 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container_folder
|
(container_folder, base_folder)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (dependency_name, (dependency_version_id, dependency_alias)) in
|
for (dependency_name, (dependency_version_id, dependency_alias)) in
|
||||||
|
@ -200,15 +203,21 @@ impl Project {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let packages_container_folder = create_and_canonicalize(
|
let base_folder = create_and_canonicalize(
|
||||||
self.package_dir().join(
|
self.package_dir().join(
|
||||||
node.node
|
node.node
|
||||||
.pkg_ref
|
.pkg_ref
|
||||||
.target_kind()
|
.target_kind()
|
||||||
.packages_folder(&dependency_node.node.pkg_ref.target_kind()),
|
.packages_folder(&dependency_node.node.pkg_ref.target_kind()),
|
||||||
),
|
),
|
||||||
)?
|
)?;
|
||||||
.join(PACKAGES_CONTAINER_NAME);
|
let packages_container_folder = base_folder.join(PACKAGES_CONTAINER_NAME);
|
||||||
|
|
||||||
|
let container_folder = dependency_node.node.container_folder(
|
||||||
|
&packages_container_folder,
|
||||||
|
dependency_name,
|
||||||
|
dependency_version_id.version(),
|
||||||
|
);
|
||||||
|
|
||||||
let linker_folder = create_and_canonicalize(
|
let linker_folder = create_and_canonicalize(
|
||||||
node_container_folder
|
node_container_folder
|
||||||
|
@ -223,13 +232,12 @@ impl Project {
|
||||||
&dependency_node.target.kind(),
|
&dependency_node.target.kind(),
|
||||||
&linker_folder,
|
&linker_folder,
|
||||||
lib_file,
|
lib_file,
|
||||||
&dependency_node.node.container_folder(
|
&container_folder,
|
||||||
&packages_container_folder,
|
|
||||||
dependency_name,
|
|
||||||
dependency_version_id.version(),
|
|
||||||
),
|
|
||||||
dependency_node.node.pkg_ref.use_new_structure(),
|
dependency_node.node.pkg_ref.use_new_structure(),
|
||||||
),
|
&node_packages_folder,
|
||||||
|
container_folder.strip_prefix(&base_folder).unwrap(),
|
||||||
|
&manifest,
|
||||||
|
)?,
|
||||||
package_types
|
package_types
|
||||||
.get(dependency_name)
|
.get(dependency_name)
|
||||||
.and_then(|v| v.get(dependency_version_id))
|
.and_then(|v| v.get(dependency_version_id))
|
||||||
|
@ -276,5 +284,9 @@ pub mod errors {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
#[error("error generating roblox sync config for {0}")]
|
#[error("error generating roblox sync config for {0}")]
|
||||||
GenerateRobloxSyncConfig(String, #[source] std::io::Error),
|
GenerateRobloxSyncConfig(String, #[source] std::io::Error),
|
||||||
|
|
||||||
|
/// An error occurred while getting the require path for a library
|
||||||
|
#[error("error getting require path for library")]
|
||||||
|
GetLibRequirePath(#[from] super::generator::errors::GetLibRequirePath),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,10 @@ pub struct Manifest {
|
||||||
/// A list of globs pointing to workspace members' directories
|
/// A list of globs pointing to workspace members' directories
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub workspace_members: Vec<String>,
|
pub workspace_members: Vec<String>,
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
/// The Roblox place of this project
|
||||||
|
#[serde(default, skip_serializing)]
|
||||||
|
pub place: BTreeMap<target::RobloxPlaceKind, String>,
|
||||||
|
|
||||||
/// The standard dependencies of the package
|
/// The standard dependencies of the package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeSet,
|
collections::BTreeSet,
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
|
@ -7,12 +8,16 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A kind of target
|
/// A kind of target
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(
|
||||||
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
SerializeDisplay, DeserializeFromStr, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord,
|
||||||
|
)]
|
||||||
pub enum TargetKind {
|
pub enum TargetKind {
|
||||||
/// A Roblox target
|
/// A Roblox target
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Roblox,
|
Roblox,
|
||||||
|
/// A Roblox server target
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
RobloxServer,
|
||||||
/// A Lune target
|
/// A Lune target
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Lune,
|
Lune,
|
||||||
|
@ -26,6 +31,8 @@ impl Display for TargetKind {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
TargetKind::Roblox => write!(f, "roblox"),
|
TargetKind::Roblox => write!(f, "roblox"),
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
TargetKind::RobloxServer => write!(f, "roblox_server"),
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
TargetKind::Lune => write!(f, "lune"),
|
TargetKind::Lune => write!(f, "lune"),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -41,6 +48,8 @@ impl FromStr for TargetKind {
|
||||||
match s {
|
match s {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
"roblox" => Ok(Self::Roblox),
|
"roblox" => Ok(Self::Roblox),
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
"roblox_server" => Ok(Self::RobloxServer),
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
"lune" => Ok(Self::Lune),
|
"lune" => Ok(Self::Lune),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -55,6 +64,8 @@ impl TargetKind {
|
||||||
pub const VARIANTS: &'static [TargetKind] = &[
|
pub const VARIANTS: &'static [TargetKind] = &[
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
TargetKind::Roblox,
|
TargetKind::Roblox,
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
TargetKind::RobloxServer,
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
TargetKind::Lune,
|
TargetKind::Lune,
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -72,6 +83,9 @@ impl TargetKind {
|
||||||
#[cfg(all(feature = "lune", feature = "luau"))]
|
#[cfg(all(feature = "lune", feature = "luau"))]
|
||||||
(TargetKind::Lune, TargetKind::Luau) => true,
|
(TargetKind::Lune, TargetKind::Luau) => true,
|
||||||
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
(TargetKind::RobloxServer, TargetKind::Roblox) => true,
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +115,16 @@ pub enum Target {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
build_files: BTreeSet<String>,
|
build_files: BTreeSet<String>,
|
||||||
},
|
},
|
||||||
|
/// A Roblox server target
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
RobloxServer {
|
||||||
|
/// The path to the lib export file
|
||||||
|
#[serde(default)]
|
||||||
|
lib: Option<RelativePathBuf>,
|
||||||
|
/// The files to include in the sync tool's config
|
||||||
|
#[serde(default)]
|
||||||
|
build_files: BTreeSet<String>,
|
||||||
|
},
|
||||||
/// A Lune target
|
/// A Lune target
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Lune {
|
Lune {
|
||||||
|
@ -129,6 +153,8 @@ impl Target {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Target::Roblox { .. } => TargetKind::Roblox,
|
Target::Roblox { .. } => TargetKind::Roblox,
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
Target::RobloxServer { .. } => TargetKind::RobloxServer,
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Target::Lune { .. } => TargetKind::Lune,
|
Target::Lune { .. } => TargetKind::Lune,
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -141,6 +167,8 @@ impl Target {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Target::Roblox { lib, .. } => lib.as_ref(),
|
Target::Roblox { lib, .. } => lib.as_ref(),
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
Target::RobloxServer { lib, .. } => lib.as_ref(),
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Target::Lune { lib, .. } => lib.as_ref(),
|
Target::Lune { lib, .. } => lib.as_ref(),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -153,6 +181,8 @@ impl Target {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Target::Roblox { .. } => None,
|
Target::Roblox { .. } => None,
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
Target::RobloxServer { .. } => None,
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Target::Lune { bin, .. } => bin.as_ref(),
|
Target::Lune { bin, .. } => bin.as_ref(),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
|
@ -160,28 +190,14 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates the target for publishing
|
/// Returns the Roblox build files
|
||||||
pub fn validate_publish(&self) -> Result<(), errors::TargetValidatePublishError> {
|
pub fn build_files(&self) -> Option<&BTreeSet<String>> {
|
||||||
let has_exports = match self {
|
|
||||||
#[cfg(feature = "roblox")]
|
|
||||||
Target::Roblox { lib, .. } => lib.is_some(),
|
|
||||||
#[cfg(feature = "lune")]
|
|
||||||
Target::Lune { lib, bin } => lib.is_some() || bin.is_some(),
|
|
||||||
#[cfg(feature = "luau")]
|
|
||||||
Target::Luau { lib, bin } => lib.is_some() || bin.is_some(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if !has_exports {
|
|
||||||
return Err(errors::TargetValidatePublishError::NoExportedFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Target::Roblox { build_files, .. } if build_files.is_empty() => {
|
Target::Roblox { build_files, .. } => Some(build_files),
|
||||||
Err(errors::TargetValidatePublishError::NoBuildFiles)
|
#[cfg(feature = "roblox")]
|
||||||
}
|
Target::RobloxServer { build_files, .. } => Some(build_files),
|
||||||
|
_ => None,
|
||||||
_ => Ok(()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,24 +208,46 @@ impl Display for Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
/// The kind of a Roblox place property
|
||||||
|
#[derive(
|
||||||
|
SerializeDisplay, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd,
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RobloxPlaceKind {
|
||||||
|
/// The shared dependencies location
|
||||||
|
Shared,
|
||||||
|
/// The server dependencies location
|
||||||
|
Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
impl TryInto<RobloxPlaceKind> for &TargetKind {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<RobloxPlaceKind, Self::Error> {
|
||||||
|
match self {
|
||||||
|
TargetKind::Roblox => Ok(RobloxPlaceKind::Shared),
|
||||||
|
TargetKind::RobloxServer => Ok(RobloxPlaceKind::Server),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
impl Display for RobloxPlaceKind {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
RobloxPlaceKind::Shared => write!(f, "shared"),
|
||||||
|
RobloxPlaceKind::Server => write!(f, "server"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Errors that can occur when working with targets
|
/// Errors that can occur when working with targets
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Errors that can occur when validating a target for publishing
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum TargetValidatePublishError {
|
|
||||||
/// No exported files specified
|
|
||||||
#[error("no exported files specified")]
|
|
||||||
NoExportedFiles,
|
|
||||||
|
|
||||||
/// Roblox target must have at least one build file
|
|
||||||
#[cfg(feature = "roblox")]
|
|
||||||
#[error("roblox target must have at least one build file")]
|
|
||||||
NoBuildFiles,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Errors that can occur when parsing a target kind from a string
|
/// Errors that can occur when parsing a target kind from a string
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|
|
@ -255,6 +255,10 @@ impl Project {
|
||||||
already_resolved.ty = ty;
|
already_resolved.ty = ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if already_resolved.direct.is_none() && depth == 0 {
|
||||||
|
already_resolved.direct = Some((alias.clone(), specifier.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,11 @@ impl PackageSource for GitPackageSource {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
None => {
|
None => {
|
||||||
match self
|
match self
|
||||||
.read_file(["wally.toml"], project, Some(tree.clone()))
|
.read_file(
|
||||||
|
[crate::source::wally::compat_util::WALLY_MANIFEST_FILE_NAME],
|
||||||
|
project,
|
||||||
|
Some(tree.clone()),
|
||||||
|
)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e)
|
errors::ResolveError::ReadManifest(Box::new(self.repo_url.clone()), e)
|
||||||
})? {
|
})? {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use tempfile::TempDir;
|
||||||
use crate::{
|
use crate::{
|
||||||
manifest::target::Target,
|
manifest::target::Target,
|
||||||
scripts::{execute_script, ScriptName},
|
scripts::{execute_script, ScriptName},
|
||||||
|
source::wally::manifest::{Realm, WallyManifest},
|
||||||
Project, LINK_LIB_NO_FILE_FOUND,
|
Project, LINK_LIB_NO_FILE_FOUND,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,14 +51,24 @@ pub(crate) fn find_lib_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) const WALLY_MANIFEST_FILE_NAME: &str = "wally.toml";
|
||||||
|
|
||||||
pub(crate) fn get_target(
|
pub(crate) fn get_target(
|
||||||
project: &Project,
|
project: &Project,
|
||||||
tempdir: &TempDir,
|
tempdir: &TempDir,
|
||||||
) -> Result<Target, errors::FindLibPathError> {
|
) -> Result<Target, errors::FindLibPathError> {
|
||||||
Ok(Target::Roblox {
|
let lib = find_lib_path(project, tempdir.path())?
|
||||||
lib: find_lib_path(project, tempdir.path())?
|
.or_else(|| Some(RelativePathBuf::from(LINK_LIB_NO_FILE_FOUND)));
|
||||||
.or_else(|| Some(RelativePathBuf::from(LINK_LIB_NO_FILE_FOUND))),
|
let build_files = Default::default();
|
||||||
build_files: Default::default(),
|
|
||||||
|
let manifest = tempdir.path().join(WALLY_MANIFEST_FILE_NAME);
|
||||||
|
let manifest = std::fs::read_to_string(&manifest)?;
|
||||||
|
let manifest: WallyManifest = toml::from_str(&manifest)?;
|
||||||
|
|
||||||
|
Ok(if matches!(manifest.package.realm, Realm::Shared) {
|
||||||
|
Target::Roblox { lib, build_files }
|
||||||
|
} else {
|
||||||
|
Target::RobloxServer { lib, build_files }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,5 +90,9 @@ pub mod errors {
|
||||||
/// An error occurred while deserializing the sourcemap result
|
/// An error occurred while deserializing the sourcemap result
|
||||||
#[error("error deserializing sourcemap result")]
|
#[error("error deserializing sourcemap result")]
|
||||||
Serde(#[from] serde_json::Error),
|
Serde(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
/// An error occurred while deserializing the wally manifest
|
||||||
|
#[error("error deserializing wally manifest")]
|
||||||
|
WallyManifest(#[from] toml::de::Error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,21 @@ use crate::{
|
||||||
source::{specifiers::DependencySpecifiers, wally::specifier::WallyDependencySpecifier},
|
source::{specifiers::DependencySpecifiers, wally::specifier::WallyDependencySpecifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum Realm {
|
||||||
|
#[serde(alias = "dev")]
|
||||||
|
Shared,
|
||||||
|
Server,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct WallyPackage {
|
pub struct WallyPackage {
|
||||||
pub name: WallyPackageName,
|
pub name: WallyPackageName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub registry: url::Url,
|
pub registry: url::Url,
|
||||||
|
pub realm: Realm,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_specifiers<'de, D: Deserializer<'de>>(
|
pub fn deserialize_specifiers<'de, D: Deserializer<'de>>(
|
||||||
|
|
Loading…
Reference in a new issue