mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-06 20:00:53 +01:00
docs: add package docs
This commit is contained in:
parent
e07ec4e859
commit
431c2b634f
22 changed files with 345 additions and 17 deletions
|
@ -29,19 +29,21 @@ impl SelfInstallCommand {
|
||||||
.0;
|
.0;
|
||||||
let path: String = env.get_value("Path").context("failed to get Path value")?;
|
let path: String = env.get_value("Path").context("failed to get Path value")?;
|
||||||
|
|
||||||
|
let bin_dir = bin_dir.to_string_lossy();
|
||||||
|
|
||||||
let exists = path
|
let exists = path
|
||||||
.split(';')
|
.split(';')
|
||||||
.any(|part| part == bin_dir.to_string_lossy().as_ref());
|
.any(|part| *part == bin_dir);
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
let new_path = format!("{path};{}", bin_dir.to_string_lossy());
|
let new_path = format!("{path};{bin_dir}");
|
||||||
env.set_value("Path", &new_path)
|
env.set_value("Path", &new_path)
|
||||||
.context("failed to set Path value")?;
|
.context("failed to set Path value")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"installed {} {}!",
|
"installed {} {}!",
|
||||||
env!("CARGO_PKG_NAME").cyan(),
|
env!("CARGO_BIN_NAME").cyan(),
|
||||||
env!("CARGO_PKG_VERSION").yellow(),
|
env!("CARGO_PKG_VERSION").yellow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -59,13 +61,13 @@ impl SelfInstallCommand {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
println!(
|
println!(
|
||||||
r#"installed {} {}! in order to be able to run binary exports as programs, add the following line to your shell profile:
|
r#"installed {} {}! add the following line to your shell profile in order to get the binary and binary exports as executables usable from anywhere:
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
and then restart your shell.
|
and then restart your shell.
|
||||||
"#,
|
"#,
|
||||||
env!("CARGO_PKG_NAME").cyan(),
|
env!("CARGO_BIN_NAME").cyan(),
|
||||||
env!("CARGO_PKG_VERSION").yellow(),
|
env!("CARGO_PKG_VERSION").yellow(),
|
||||||
format!(r#"export PATH="$PATH:~/{}/bin""#, HOME_DIR)
|
format!(r#"export PATH="$PATH:~/{}/bin""#, HOME_DIR)
|
||||||
.bold()
|
.bold()
|
||||||
|
|
|
@ -20,6 +20,7 @@ type MultithreadDownloadJob = (
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Downloads a graph of dependencies
|
||||||
pub fn download_graph(
|
pub fn download_graph(
|
||||||
&self,
|
&self,
|
||||||
graph: &DependencyGraph,
|
graph: &DependencyGraph,
|
||||||
|
@ -101,24 +102,31 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when downloading a graph
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when downloading a graph
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum DownloadGraphError {
|
pub enum DownloadGraphError {
|
||||||
|
/// Error occurred deserializing the project manifest
|
||||||
#[error("error deserializing project manifest")]
|
#[error("error deserializing project manifest")]
|
||||||
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
/// Error occurred refreshing a package source
|
||||||
#[error("failed to refresh package source")]
|
#[error("failed to refresh package source")]
|
||||||
RefreshFailed(#[from] Box<crate::source::errors::RefreshError>),
|
RefreshFailed(#[from] Box<crate::source::errors::RefreshError>),
|
||||||
|
|
||||||
|
/// Error interacting with the filesystem
|
||||||
#[error("error interacting with filesystem")]
|
#[error("error interacting with filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// Error downloading a package
|
||||||
#[error("failed to download package")]
|
#[error("failed to download package")]
|
||||||
DownloadFailed(#[from] crate::source::errors::DownloadError),
|
DownloadFailed(#[from] crate::source::errors::DownloadError),
|
||||||
|
|
||||||
|
/// Error writing package contents
|
||||||
#[error("failed to write package contents")]
|
#[error("failed to write package contents")]
|
||||||
WriteFailed(std::io::Error),
|
WriteFailed(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
46
src/lib.rs
46
src/lib.rs
|
@ -1,4 +1,7 @@
|
||||||
// #![deny(missing_docs)] - TODO: bring this back before publishing 0.5
|
#![deny(missing_docs)]
|
||||||
|
//! pesde is a package manager for Luau, designed to be feature-rich and easy to use.
|
||||||
|
//! pesde has its own registry, however it can also use Wally, and GitHub as package sources.
|
||||||
|
//! It has been designed with multiple targets in mind, namely Roblox, Lune, and Luau.
|
||||||
|
|
||||||
#[cfg(not(any(feature = "roblox", feature = "lune", feature = "luau")))]
|
#[cfg(not(any(feature = "roblox", feature = "lune", feature = "luau")))]
|
||||||
compile_error!("at least one of the features `roblox`, `lune`, or `luau` must be enabled");
|
compile_error!("at least one of the features `roblox`, `lune`, or `luau` must be enabled");
|
||||||
|
@ -6,24 +9,39 @@ compile_error!("at least one of the features `roblox`, `lune`, or `luau` must be
|
||||||
use crate::lockfile::Lockfile;
|
use crate::lockfile::Lockfile;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
/// Downloading packages
|
||||||
pub mod download;
|
pub mod download;
|
||||||
|
/// Linking packages
|
||||||
pub mod linking;
|
pub mod linking;
|
||||||
|
/// Lockfile
|
||||||
pub mod lockfile;
|
pub mod lockfile;
|
||||||
|
/// Manifest
|
||||||
pub mod manifest;
|
pub mod manifest;
|
||||||
|
/// Package names
|
||||||
pub mod names;
|
pub mod names;
|
||||||
|
/// Patching packages
|
||||||
#[cfg(feature = "patches")]
|
#[cfg(feature = "patches")]
|
||||||
pub mod patches;
|
pub mod patches;
|
||||||
|
/// Resolving packages
|
||||||
pub mod resolver;
|
pub mod resolver;
|
||||||
|
/// Running scripts
|
||||||
pub mod scripts;
|
pub mod scripts;
|
||||||
|
/// Package sources
|
||||||
pub mod source;
|
pub mod source;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
|
|
||||||
|
/// The name of the manifest file
|
||||||
pub const MANIFEST_FILE_NAME: &str = "pesde.toml";
|
pub const MANIFEST_FILE_NAME: &str = "pesde.toml";
|
||||||
|
/// The name of the lockfile
|
||||||
pub const LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
pub const LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
||||||
|
/// The name of the default index
|
||||||
pub const DEFAULT_INDEX_NAME: &str = "default";
|
pub const DEFAULT_INDEX_NAME: &str = "default";
|
||||||
|
/// The name of the packages container
|
||||||
pub const PACKAGES_CONTAINER_NAME: &str = ".pesde";
|
pub const PACKAGES_CONTAINER_NAME: &str = ".pesde";
|
||||||
|
/// Maximum size of a package's archive
|
||||||
pub const MAX_ARCHIVE_SIZE: usize = 4 * 1024 * 1024;
|
pub const MAX_ARCHIVE_SIZE: usize = 4 * 1024 * 1024;
|
||||||
|
|
||||||
|
/// Struct containing the authentication configuration
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct AuthConfig {
|
pub struct AuthConfig {
|
||||||
pesde_token: Option<String>,
|
pesde_token: Option<String>,
|
||||||
|
@ -31,23 +49,28 @@ pub struct AuthConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthConfig {
|
impl AuthConfig {
|
||||||
|
/// Create a new `AuthConfig`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
AuthConfig::default()
|
AuthConfig::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the pesde token
|
||||||
pub fn pesde_token(&self) -> Option<&str> {
|
pub fn pesde_token(&self) -> Option<&str> {
|
||||||
self.pesde_token.as_deref()
|
self.pesde_token.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the git credentials
|
||||||
pub fn git_credentials(&self) -> Option<&gix::sec::identity::Account> {
|
pub fn git_credentials(&self) -> Option<&gix::sec::identity::Account> {
|
||||||
self.git_credentials.as_ref()
|
self.git_credentials.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the pesde token
|
||||||
pub fn with_pesde_token<S: AsRef<str>>(mut self, token: Option<S>) -> Self {
|
pub fn with_pesde_token<S: AsRef<str>>(mut self, token: Option<S>) -> Self {
|
||||||
self.pesde_token = token.map(|s| s.as_ref().to_string());
|
self.pesde_token = token.map(|s| s.as_ref().to_string());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the git credentials
|
||||||
pub fn with_git_credentials(
|
pub fn with_git_credentials(
|
||||||
mut self,
|
mut self,
|
||||||
git_credentials: Option<gix::sec::identity::Account>,
|
git_credentials: Option<gix::sec::identity::Account>,
|
||||||
|
@ -57,6 +80,7 @@ impl AuthConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main struct of the pesde library, representing a project
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -66,6 +90,7 @@ pub struct Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Create a new `Project`
|
||||||
pub fn new<P: AsRef<Path>, Q: AsRef<Path>, R: AsRef<Path>>(
|
pub fn new<P: AsRef<Path>, Q: AsRef<Path>, R: AsRef<Path>>(
|
||||||
path: P,
|
path: P,
|
||||||
data_dir: Q,
|
data_dir: Q,
|
||||||
|
@ -80,41 +105,50 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the path
|
||||||
pub fn path(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the data directory
|
||||||
pub fn data_dir(&self) -> &Path {
|
pub fn data_dir(&self) -> &Path {
|
||||||
&self.data_dir
|
&self.data_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the authentication configuration
|
||||||
pub fn auth_config(&self) -> &AuthConfig {
|
pub fn auth_config(&self) -> &AuthConfig {
|
||||||
&self.auth_config
|
&self.auth_config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the CAS (content-addressable storage) directory
|
||||||
pub fn cas_dir(&self) -> &Path {
|
pub fn cas_dir(&self) -> &Path {
|
||||||
&self.cas_dir
|
&self.cas_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the manifest file
|
||||||
pub fn read_manifest(&self) -> Result<String, errors::ManifestReadError> {
|
pub fn read_manifest(&self) -> Result<String, errors::ManifestReadError> {
|
||||||
let string = std::fs::read_to_string(self.path.join(MANIFEST_FILE_NAME))?;
|
let string = std::fs::read_to_string(self.path.join(MANIFEST_FILE_NAME))?;
|
||||||
Ok(string)
|
Ok(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize the manifest file
|
||||||
pub fn deser_manifest(&self) -> Result<manifest::Manifest, errors::ManifestReadError> {
|
pub fn deser_manifest(&self) -> Result<manifest::Manifest, errors::ManifestReadError> {
|
||||||
let string = std::fs::read_to_string(self.path.join(MANIFEST_FILE_NAME))?;
|
let string = std::fs::read_to_string(self.path.join(MANIFEST_FILE_NAME))?;
|
||||||
Ok(toml::from_str(&string)?)
|
Ok(toml::from_str(&string)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the manifest file
|
||||||
pub fn write_manifest<S: AsRef<[u8]>>(&self, manifest: S) -> Result<(), std::io::Error> {
|
pub fn write_manifest<S: AsRef<[u8]>>(&self, manifest: S) -> Result<(), std::io::Error> {
|
||||||
std::fs::write(self.path.join(MANIFEST_FILE_NAME), manifest.as_ref())
|
std::fs::write(self.path.join(MANIFEST_FILE_NAME), manifest.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize the lockfile
|
||||||
pub fn deser_lockfile(&self) -> Result<Lockfile, errors::LockfileReadError> {
|
pub fn deser_lockfile(&self) -> Result<Lockfile, errors::LockfileReadError> {
|
||||||
let string = std::fs::read_to_string(self.path.join(LOCKFILE_FILE_NAME))?;
|
let string = std::fs::read_to_string(self.path.join(LOCKFILE_FILE_NAME))?;
|
||||||
Ok(toml::from_str(&string)?)
|
Ok(toml::from_str(&string)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the lockfile
|
||||||
pub fn write_lockfile(&self, lockfile: Lockfile) -> Result<(), errors::LockfileWriteError> {
|
pub fn write_lockfile(&self, lockfile: Lockfile) -> Result<(), errors::LockfileWriteError> {
|
||||||
let string = toml::to_string(&lockfile)?;
|
let string = toml::to_string(&lockfile)?;
|
||||||
std::fs::write(self.path.join(LOCKFILE_FILE_NAME), string)?;
|
std::fs::write(self.path.join(LOCKFILE_FILE_NAME), string)?;
|
||||||
|
@ -122,35 +156,45 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading or writing files
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when reading the manifest file
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ManifestReadError {
|
pub enum ManifestReadError {
|
||||||
|
/// An IO error occurred
|
||||||
#[error("io error reading manifest file")]
|
#[error("io error reading manifest file")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// An error occurred while deserializing the manifest file
|
||||||
#[error("error deserializing manifest file")]
|
#[error("error deserializing manifest file")]
|
||||||
Serde(#[from] toml::de::Error),
|
Serde(#[from] toml::de::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading the lockfile
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum LockfileReadError {
|
pub enum LockfileReadError {
|
||||||
|
/// An IO error occurred
|
||||||
#[error("io error reading lockfile")]
|
#[error("io error reading lockfile")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// An error occurred while deserializing the lockfile
|
||||||
#[error("error deserializing lockfile")]
|
#[error("error deserializing lockfile")]
|
||||||
Serde(#[from] toml::de::Error),
|
Serde(#[from] toml::de::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when writing the lockfile
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum LockfileWriteError {
|
pub enum LockfileWriteError {
|
||||||
|
/// An IO error occurred
|
||||||
#[error("io error writing lockfile")]
|
#[error("io error writing lockfile")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// An error occurred while serializing the lockfile
|
||||||
#[error("error serializing lockfile")]
|
#[error("error serializing lockfile")]
|
||||||
Serde(#[from] toml::ser::Error),
|
Serde(#[from] toml::ser::Error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl Visitor for TypeVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the types exported by a file
|
||||||
pub fn get_file_types(file: &str) -> Result<Vec<String>, Vec<full_moon::Error>> {
|
pub fn get_file_types(file: &str) -> Result<Vec<String>, Vec<full_moon::Error>> {
|
||||||
let ast = full_moon::parse(file)?;
|
let ast = full_moon::parse(file)?;
|
||||||
let mut visitor = TypeVisitor { types: vec![] };
|
let mut visitor = TypeVisitor { types: vec![] };
|
||||||
|
@ -49,6 +50,7 @@ pub fn get_file_types(file: &str) -> Result<Vec<String>, Vec<full_moon::Error>>
|
||||||
Ok(visitor.types)
|
Ok(visitor.types)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a linking module for a library
|
||||||
pub fn generate_lib_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
|
pub fn generate_lib_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
|
||||||
path: &str,
|
path: &str,
|
||||||
types: I,
|
types: I,
|
||||||
|
@ -80,6 +82,7 @@ fn luau_style_path(path: &Path) -> String {
|
||||||
format!("{require:?}")
|
format!("{require:?}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the require path for a library
|
||||||
pub fn get_lib_require_path(
|
pub fn get_lib_require_path(
|
||||||
target: &TargetKind,
|
target: &TargetKind,
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
|
@ -121,10 +124,12 @@ pub fn get_lib_require_path(
|
||||||
luau_style_path(&path)
|
luau_style_path(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a linking module for a binary
|
||||||
pub fn generate_bin_linking_module(path: &str) -> String {
|
pub fn generate_bin_linking_module(path: &str) -> String {
|
||||||
format!("return require({path})")
|
format!("return require({path})")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the require path for a binary
|
||||||
pub fn get_bin_require_path(
|
pub fn get_bin_require_path(
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
bin_file: &RelativePathBuf,
|
bin_file: &RelativePathBuf,
|
||||||
|
|
|
@ -13,6 +13,7 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Generates linking modules for a project
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
|
|
||||||
fn create_and_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
|
fn create_and_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
|
||||||
|
@ -28,6 +29,7 @@ fn write_cas(destination: PathBuf, cas_dir: &Path, contents: &str) -> std::io::R
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Links the dependencies of the project
|
||||||
pub fn link_dependencies(&self, graph: &DownloadedGraph) -> Result<(), errors::LinkingError> {
|
pub fn link_dependencies(&self, graph: &DownloadedGraph) -> Result<(), errors::LinkingError> {
|
||||||
let manifest = self.deser_manifest()?;
|
let manifest = self.deser_manifest()?;
|
||||||
|
|
||||||
|
@ -207,27 +209,35 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur while linking dependencies
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur while linking dependencies
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum LinkingError {
|
pub enum LinkingError {
|
||||||
|
/// An error occurred while deserializing the project manifest
|
||||||
#[error("error deserializing project manifest")]
|
#[error("error deserializing project manifest")]
|
||||||
Manifest(#[from] crate::errors::ManifestReadError),
|
Manifest(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
/// An error occurred while interacting with the filesystem
|
||||||
#[error("error interacting with filesystem")]
|
#[error("error interacting with filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// A dependency was not found
|
||||||
#[error("dependency not found: {0}@{1}")]
|
#[error("dependency not found: {0}@{1}")]
|
||||||
DependencyNotFound(String, String),
|
DependencyNotFound(String, String),
|
||||||
|
|
||||||
|
/// The library file was not found
|
||||||
#[error("library file at {0} not found")]
|
#[error("library file at {0} not found")]
|
||||||
LibFileNotFound(String),
|
LibFileNotFound(String),
|
||||||
|
|
||||||
|
/// An error occurred while parsing a Luau script
|
||||||
#[error("error parsing Luau script at {0}")]
|
#[error("error parsing Luau script at {0}")]
|
||||||
FullMoon(String, Vec<full_moon::Error>),
|
FullMoon(String, Vec<full_moon::Error>),
|
||||||
|
|
||||||
|
/// An error occurred while generating a Roblox sync config
|
||||||
#[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),
|
||||||
|
|
|
@ -17,19 +17,26 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A graph of dependencies
|
||||||
pub type Graph<Node> = BTreeMap<PackageNames, BTreeMap<VersionId, Node>>;
|
pub type Graph<Node> = BTreeMap<PackageNames, BTreeMap<VersionId, Node>>;
|
||||||
|
|
||||||
|
/// A dependency graph node
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct DependencyGraphNode {
|
pub struct DependencyGraphNode {
|
||||||
|
/// The alias and specifiers for the dependency, if it is a direct dependency (i.e. used by the current project)
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub direct: Option<(String, DependencySpecifiers)>,
|
pub direct: Option<(String, DependencySpecifiers)>,
|
||||||
|
/// The dependencies of the package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub dependencies: BTreeMap<PackageNames, (VersionId, String)>,
|
pub dependencies: BTreeMap<PackageNames, (VersionId, String)>,
|
||||||
|
/// The type of the dependency
|
||||||
pub ty: DependencyType,
|
pub ty: DependencyType,
|
||||||
|
/// The package reference
|
||||||
pub pkg_ref: PackageRefs,
|
pub pkg_ref: PackageRefs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DependencyGraphNode {
|
impl DependencyGraphNode {
|
||||||
|
/// Returns the folder to store dependencies in for this package
|
||||||
pub fn base_folder(&self, project_target: TargetKind, is_top_level: bool) -> String {
|
pub fn base_folder(&self, project_target: TargetKind, is_top_level: bool) -> String {
|
||||||
if is_top_level || self.pkg_ref.use_new_structure() {
|
if is_top_level || self.pkg_ref.use_new_structure() {
|
||||||
project_target.packages_folder(&self.pkg_ref.target_kind())
|
project_target.packages_folder(&self.pkg_ref.target_kind())
|
||||||
|
@ -38,6 +45,7 @@ impl DependencyGraphNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the folder to store the contents of the package in
|
||||||
pub fn container_folder<P: AsRef<Path>>(
|
pub fn container_folder<P: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
path: &P,
|
path: &P,
|
||||||
|
@ -51,8 +59,10 @@ impl DependencyGraphNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A graph of `DependencyGraphNode`s
|
||||||
pub type DependencyGraph = Graph<DependencyGraphNode>;
|
pub type DependencyGraph = Graph<DependencyGraphNode>;
|
||||||
|
|
||||||
|
/// Inserts a node into a graph
|
||||||
pub fn insert_node(
|
pub fn insert_node(
|
||||||
graph: &mut DependencyGraph,
|
graph: &mut DependencyGraph,
|
||||||
name: PackageNames,
|
name: PackageNames,
|
||||||
|
@ -92,23 +102,33 @@ pub fn insert_node(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A downloaded dependency graph node, i.e. a `DependencyGraphNode` with a `Target`
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct DownloadedDependencyGraphNode {
|
pub struct DownloadedDependencyGraphNode {
|
||||||
|
/// The target of the package
|
||||||
pub target: Target,
|
pub target: Target,
|
||||||
|
/// The node
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub node: DependencyGraphNode,
|
pub node: DependencyGraphNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A graph of `DownloadedDependencyGraphNode`s
|
||||||
pub type DownloadedGraph = Graph<DownloadedDependencyGraphNode>;
|
pub type DownloadedGraph = Graph<DownloadedDependencyGraphNode>;
|
||||||
|
|
||||||
|
/// A lockfile
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Lockfile {
|
pub struct Lockfile {
|
||||||
|
/// The name of the package
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
|
/// The version of the package
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
|
/// The target of the package
|
||||||
pub target: TargetKind,
|
pub target: TargetKind,
|
||||||
|
/// The overrides of the package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
||||||
|
|
||||||
|
/// The graph of dependencies
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub graph: DownloadedGraph,
|
pub graph: DownloadedGraph,
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ fn run() -> anyhow::Result<()> {
|
||||||
parent.as_os_str() != "bin"
|
parent.as_os_str() != "bin"
|
||||||
|| parent
|
|| parent
|
||||||
.parent()
|
.parent()
|
||||||
.is_some_and(|parent| parent.as_os_str() != cli::HOME_DIR)
|
.is_some_and(|parent| parent.as_os_str() != HOME_DIR)
|
||||||
}) {
|
}) {
|
||||||
break 'scripts;
|
break 'scripts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,32 +10,46 @@ use crate::{
|
||||||
source::specifiers::DependencySpecifiers,
|
source::specifiers::DependencySpecifiers,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Overrides
|
||||||
pub mod overrides;
|
pub mod overrides;
|
||||||
|
/// Targets
|
||||||
pub mod target;
|
pub mod target;
|
||||||
|
|
||||||
|
/// A package manifest
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Manifest {
|
pub struct Manifest {
|
||||||
|
/// The name of the package
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
|
/// The version of the package
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
|
/// The description of the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
/// The license of the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub license: Option<String>,
|
pub license: Option<String>,
|
||||||
|
/// The authors of the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub authors: Option<Vec<String>>,
|
pub authors: Option<Vec<String>>,
|
||||||
|
/// The repository of the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub repository: Option<String>,
|
pub repository: Option<String>,
|
||||||
|
/// The target of the package
|
||||||
pub target: Target,
|
pub target: Target,
|
||||||
|
/// Whether the package is private
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub private: bool,
|
pub private: bool,
|
||||||
|
/// The scripts of the package
|
||||||
#[serde(default, skip_serializing)]
|
#[serde(default, skip_serializing)]
|
||||||
pub scripts: BTreeMap<String, RelativePathBuf>,
|
pub scripts: BTreeMap<String, RelativePathBuf>,
|
||||||
|
/// The indices to use for the package
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
serialize_with = "crate::util::serialize_gix_url_map",
|
serialize_with = "crate::util::serialize_gix_url_map",
|
||||||
deserialize_with = "crate::util::deserialize_gix_url_map"
|
deserialize_with = "crate::util::deserialize_gix_url_map"
|
||||||
)]
|
)]
|
||||||
pub indices: BTreeMap<String, gix::Url>,
|
pub indices: BTreeMap<String, gix::Url>,
|
||||||
|
/// The indices to use for the package's wally dependencies
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
|
@ -44,10 +58,13 @@ pub struct Manifest {
|
||||||
deserialize_with = "crate::util::deserialize_gix_url_map"
|
deserialize_with = "crate::util::deserialize_gix_url_map"
|
||||||
)]
|
)]
|
||||||
pub wally_indices: BTreeMap<String, gix::Url>,
|
pub wally_indices: BTreeMap<String, gix::Url>,
|
||||||
|
/// The overrides this package has
|
||||||
#[serde(default, skip_serializing)]
|
#[serde(default, skip_serializing)]
|
||||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
||||||
|
/// The files to include in the package
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub includes: BTreeSet<String>,
|
pub includes: BTreeSet<String>,
|
||||||
|
/// The patches to apply to packages
|
||||||
#[cfg(feature = "patches")]
|
#[cfg(feature = "patches")]
|
||||||
#[serde(default, skip_serializing)]
|
#[serde(default, skip_serializing)]
|
||||||
pub patches: BTreeMap<
|
pub patches: BTreeMap<
|
||||||
|
@ -55,25 +72,34 @@ pub struct Manifest {
|
||||||
BTreeMap<crate::source::version_id::VersionId, RelativePathBuf>,
|
BTreeMap<crate::source::version_id::VersionId, RelativePathBuf>,
|
||||||
>,
|
>,
|
||||||
#[serde(default, skip_serializing)]
|
#[serde(default, skip_serializing)]
|
||||||
|
/// Which version of the pesde CLI this package uses
|
||||||
pub pesde_version: Option<Version>,
|
pub pesde_version: Option<Version>,
|
||||||
|
|
||||||
|
/// The standard dependencies of the package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub dependencies: BTreeMap<String, DependencySpecifiers>,
|
pub dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
|
/// The peer dependencies of the package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub peer_dependencies: BTreeMap<String, DependencySpecifiers>,
|
pub peer_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
/// The dev dependencies of the package
|
||||||
|
#[serde(default, skip_serializing)]
|
||||||
pub dev_dependencies: BTreeMap<String, DependencySpecifiers>,
|
pub dev_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A dependency type
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum DependencyType {
|
pub enum DependencyType {
|
||||||
|
/// A standard dependency
|
||||||
Standard,
|
Standard,
|
||||||
Dev,
|
/// A peer dependency
|
||||||
Peer,
|
Peer,
|
||||||
|
/// A dev dependency
|
||||||
|
Dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manifest {
|
impl Manifest {
|
||||||
|
/// Get all dependencies from the manifest
|
||||||
pub fn all_dependencies(
|
pub fn all_dependencies(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
@ -98,12 +124,15 @@ impl Manifest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when interacting with manifests
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when trying to get all dependencies from a manifest
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum AllDependenciesError {
|
pub enum AllDependenciesError {
|
||||||
|
/// Another specifier is already using the alias
|
||||||
#[error("another specifier is already using the alias {0}")]
|
#[error("another specifier is already using the alias {0}")]
|
||||||
AliasConflict(String),
|
AliasConflict(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::{
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An override key
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
||||||
)]
|
)]
|
||||||
|
@ -46,12 +47,15 @@ impl Display for OverrideKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when interacting with override keys
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when parsing an override key
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum OverrideKeyFromStr {
|
pub enum OverrideKeyFromStr {
|
||||||
|
/// The override key is empty
|
||||||
#[error("empty override key")]
|
#[error("empty override key")]
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,17 @@ use std::{
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A kind of target
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
||||||
pub enum TargetKind {
|
pub enum TargetKind {
|
||||||
|
/// A Roblox target
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Roblox,
|
Roblox,
|
||||||
|
/// A Lune target
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Lune,
|
Lune,
|
||||||
|
/// A Luau target
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
Luau,
|
Luau,
|
||||||
}
|
}
|
||||||
|
@ -47,6 +51,7 @@ impl FromStr for TargetKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetKind {
|
impl TargetKind {
|
||||||
|
/// All possible target variants
|
||||||
pub const VARIANTS: &'static [TargetKind] = &[
|
pub const VARIANTS: &'static [TargetKind] = &[
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
TargetKind::Roblox,
|
TargetKind::Roblox,
|
||||||
|
@ -56,7 +61,8 @@ impl TargetKind {
|
||||||
TargetKind::Luau,
|
TargetKind::Luau,
|
||||||
];
|
];
|
||||||
|
|
||||||
// self is the project's target, dependency is the target of the dependency
|
/// Whether this target is compatible with another target
|
||||||
|
/// self is the project's target, dependency is the target of the dependency
|
||||||
pub fn is_compatible_with(&self, dependency: &Self) -> bool {
|
pub fn is_compatible_with(&self, dependency: &Self) -> bool {
|
||||||
if self == dependency {
|
if self == dependency {
|
||||||
return true;
|
return true;
|
||||||
|
@ -70,6 +76,8 @@ impl TargetKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The folder to store packages in for this target
|
||||||
|
/// self is the project's target, dependency is the target of the dependency
|
||||||
pub fn packages_folder(&self, dependency: &Self) -> String {
|
pub fn packages_folder(&self, dependency: &Self) -> String {
|
||||||
if self == dependency {
|
if self == dependency {
|
||||||
return "packages".to_string();
|
return "packages".to_string();
|
||||||
|
@ -79,33 +87,44 @@ impl TargetKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A target of a package
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
#[serde(rename_all = "snake_case", tag = "environment")]
|
#[serde(rename_all = "snake_case", tag = "environment")]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
|
/// A Roblox target
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Roblox {
|
Roblox {
|
||||||
|
/// The path to the lib export file
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
lib: Option<RelativePathBuf>,
|
lib: Option<RelativePathBuf>,
|
||||||
|
/// The files to include in the sync tool's config
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
build_files: BTreeSet<String>,
|
build_files: BTreeSet<String>,
|
||||||
},
|
},
|
||||||
|
/// A Lune target
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Lune {
|
Lune {
|
||||||
|
/// The path to the lib export file
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
lib: Option<RelativePathBuf>,
|
lib: Option<RelativePathBuf>,
|
||||||
|
/// The path to the bin export file
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
bin: Option<RelativePathBuf>,
|
bin: Option<RelativePathBuf>,
|
||||||
},
|
},
|
||||||
|
/// A Luau target
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
Luau {
|
Luau {
|
||||||
|
/// The path to the lib export file
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
lib: Option<RelativePathBuf>,
|
lib: Option<RelativePathBuf>,
|
||||||
|
/// The path to the bin export file
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
bin: Option<RelativePathBuf>,
|
bin: Option<RelativePathBuf>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
|
/// Returns the kind of this target
|
||||||
pub fn kind(&self) -> TargetKind {
|
pub fn kind(&self) -> TargetKind {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
|
@ -117,6 +136,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the lib export file
|
||||||
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
|
@ -128,6 +148,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the bin export file
|
||||||
pub fn bin_path(&self) -> Option<&RelativePathBuf> {
|
pub fn bin_path(&self) -> Option<&RelativePathBuf> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
|
@ -139,6 +160,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validates the target for publishing
|
||||||
pub fn validate_publish(&self) -> Result<(), errors::TargetValidatePublishError> {
|
pub fn validate_publish(&self) -> Result<(), errors::TargetValidatePublishError> {
|
||||||
let has_exports = match self {
|
let has_exports = match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
|
@ -170,23 +192,29 @@ impl Display for Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum TargetValidatePublishError {
|
pub enum TargetValidatePublishError {
|
||||||
|
/// No exported files specified
|
||||||
#[error("no exported files specified")]
|
#[error("no exported files specified")]
|
||||||
NoExportedFiles,
|
NoExportedFiles,
|
||||||
|
|
||||||
|
/// Roblox target must have at least one build file
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
#[error("roblox target must have at least one build file")]
|
#[error("roblox target must have at least one build file")]
|
||||||
NoBuildFiles,
|
NoBuildFiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when parsing a target kind from a string
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum TargetKindFromStr {
|
pub enum TargetKindFromStr {
|
||||||
|
/// The target kind is unknown
|
||||||
#[error("unknown target kind {0}")]
|
#[error("unknown target kind {0}")]
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
19
src/names.rs
19
src/names.rs
|
@ -2,9 +2,12 @@ use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
|
|
||||||
|
/// The invalid part of a package name
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ErrorReason {
|
pub enum ErrorReason {
|
||||||
|
/// The scope of the package name is invalid
|
||||||
Scope,
|
Scope,
|
||||||
|
/// The name of the package name is invalid
|
||||||
Name,
|
Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +20,7 @@ impl Display for ErrorReason {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pesde package name
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
||||||
)]
|
)]
|
||||||
|
@ -59,29 +63,35 @@ impl Display for PackageName {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageName {
|
impl PackageName {
|
||||||
|
/// Returns the parts of the package name
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
(&self.0, &self.1)
|
(&self.0, &self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the package name as a string suitable for use in the filesystem
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
format!("{}+{}", self.0, self.1)
|
format!("{}+{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All possible package names
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, DeserializeFromStr, SerializeDisplay, Clone, Hash, PartialEq, Eq, PartialOrd, Ord,
|
Debug, DeserializeFromStr, SerializeDisplay, Clone, Hash, PartialEq, Eq, PartialOrd, Ord,
|
||||||
)]
|
)]
|
||||||
pub enum PackageNames {
|
pub enum PackageNames {
|
||||||
|
/// A pesde package name
|
||||||
Pesde(PackageName),
|
Pesde(PackageName),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageNames {
|
impl PackageNames {
|
||||||
|
/// Returns the parts of the package name
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.as_str(),
|
PackageNames::Pesde(name) => name.as_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the package name as a string suitable for use in the filesystem
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.escaped(),
|
PackageNames::Pesde(name) => name.escaped(),
|
||||||
|
@ -109,32 +119,41 @@ impl FromStr for PackageNames {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when working with package names
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::names::ErrorReason;
|
use crate::names::ErrorReason;
|
||||||
|
|
||||||
|
/// Errors that can occur when working with pesde package names
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum PackageNameError {
|
pub enum PackageNameError {
|
||||||
|
/// The package name is not in the format `scope/name`
|
||||||
#[error("package name `{0}` is not in the format `scope/name`")]
|
#[error("package name `{0}` is not in the format `scope/name`")]
|
||||||
InvalidFormat(String),
|
InvalidFormat(String),
|
||||||
|
|
||||||
|
/// The package name is outside the allowed characters: a-z, 0-9, and _
|
||||||
#[error("package {0} `{1}` contains characters outside a-z, 0-9, and _")]
|
#[error("package {0} `{1}` contains characters outside a-z, 0-9, and _")]
|
||||||
InvalidCharacters(ErrorReason, String),
|
InvalidCharacters(ErrorReason, String),
|
||||||
|
|
||||||
|
/// The package name contains only digits
|
||||||
#[error("package {0} `{1}` contains only digits")]
|
#[error("package {0} `{1}` contains only digits")]
|
||||||
OnlyDigits(ErrorReason, String),
|
OnlyDigits(ErrorReason, String),
|
||||||
|
|
||||||
|
/// The package name starts or ends with an underscore
|
||||||
#[error("package {0} `{1}` starts or ends with an underscore")]
|
#[error("package {0} `{1}` starts or ends with an underscore")]
|
||||||
PrePostfixUnderscore(ErrorReason, String),
|
PrePostfixUnderscore(ErrorReason, String),
|
||||||
|
|
||||||
|
/// The package name is not within 3-32 characters long
|
||||||
#[error("package {0} `{1}` is not within 3-32 characters long")]
|
#[error("package {0} `{1}` is not within 3-32 characters long")]
|
||||||
InvalidLength(ErrorReason, String),
|
InvalidLength(ErrorReason, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when working with package names
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum PackageNamesError {
|
pub enum PackageNamesError {
|
||||||
|
/// The pesde package name is invalid
|
||||||
#[error("invalid package name {0}")]
|
#[error("invalid package name {0}")]
|
||||||
InvalidPackageName(String),
|
InvalidPackageName(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use git2::{ApplyLocation, ApplyOptions, Diff, DiffFormat, DiffLineType, Reposito
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use std::{fs::read, path::Path};
|
use std::{fs::read, path::Path};
|
||||||
|
|
||||||
|
/// Set up a git repository for patches
|
||||||
pub fn setup_patches_repo<P: AsRef<Path>>(dir: P) -> Result<Repository, git2::Error> {
|
pub fn setup_patches_repo<P: AsRef<Path>>(dir: P) -> Result<Repository, git2::Error> {
|
||||||
let repo = Repository::init(&dir)?;
|
let repo = Repository::init(&dir)?;
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ pub fn setup_patches_repo<P: AsRef<Path>>(dir: P) -> Result<Repository, git2::Er
|
||||||
Ok(repo)
|
Ok(repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a patch from the current state of the repository
|
||||||
pub fn create_patch<P: AsRef<Path>>(dir: P) -> Result<Vec<u8>, git2::Error> {
|
pub fn create_patch<P: AsRef<Path>>(dir: P) -> Result<Vec<u8>, git2::Error> {
|
||||||
let mut patches = vec![];
|
let mut patches = vec![];
|
||||||
let repo = Repository::open(dir.as_ref())?;
|
let repo = Repository::open(dir.as_ref())?;
|
||||||
|
@ -65,6 +67,7 @@ pub fn create_patch<P: AsRef<Path>>(dir: P) -> Result<Vec<u8>, git2::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Apply patches to the project's dependencies
|
||||||
pub fn apply_patches(&self, graph: &DownloadedGraph) -> Result<(), errors::ApplyPatchesError> {
|
pub fn apply_patches(&self, graph: &DownloadedGraph) -> Result<(), errors::ApplyPatchesError> {
|
||||||
let manifest = self.deser_manifest()?;
|
let manifest = self.deser_manifest()?;
|
||||||
|
|
||||||
|
@ -140,27 +143,34 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when using patches
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{names::PackageNames, source::version_id::VersionId};
|
use crate::{names::PackageNames, source::version_id::VersionId};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when applying patches
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ApplyPatchesError {
|
pub enum ApplyPatchesError {
|
||||||
|
/// Error deserializing the project manifest
|
||||||
#[error("error deserializing project manifest")]
|
#[error("error deserializing project manifest")]
|
||||||
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
/// Error interacting with git
|
||||||
#[error("error interacting with git")]
|
#[error("error interacting with git")]
|
||||||
GitError(#[from] git2::Error),
|
GitError(#[from] git2::Error),
|
||||||
|
|
||||||
|
/// Error reading the patch file
|
||||||
#[error("error reading patch file at {0}")]
|
#[error("error reading patch file at {0}")]
|
||||||
PatchReadError(PathBuf, #[source] std::io::Error),
|
PatchReadError(PathBuf, #[source] std::io::Error),
|
||||||
|
|
||||||
|
/// Error removing the .git directory
|
||||||
#[error("error removing .git directory")]
|
#[error("error removing .git directory")]
|
||||||
GitDirectoryRemovalError(PathBuf, #[source] std::io::Error),
|
GitDirectoryRemovalError(PathBuf, #[source] std::io::Error),
|
||||||
|
|
||||||
|
/// Package not found in the graph
|
||||||
#[error("package {0}@{1} not found in graph")]
|
#[error("package {0}@{1} not found in graph")]
|
||||||
PackageNotFound(PackageNames, VersionId),
|
PackageNotFound(PackageNames, VersionId),
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Create a dependency graph from the project's manifest
|
||||||
pub fn dependency_graph(
|
pub fn dependency_graph(
|
||||||
&self,
|
&self,
|
||||||
previous_graph: Option<&DependencyGraph>,
|
previous_graph: Option<&DependencyGraph>,
|
||||||
|
@ -293,27 +294,35 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when resolving dependencies
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when creating a dependency graph
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum DependencyGraphError {
|
pub enum DependencyGraphError {
|
||||||
|
/// An error occurred while deserializing the manifest
|
||||||
#[error("failed to deserialize manifest")]
|
#[error("failed to deserialize manifest")]
|
||||||
ManifestRead(#[from] crate::errors::ManifestReadError),
|
ManifestRead(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
/// An error occurred while reading all dependencies from the manifest
|
||||||
#[error("error getting all project dependencies")]
|
#[error("error getting all project dependencies")]
|
||||||
AllDependencies(#[from] crate::manifest::errors::AllDependenciesError),
|
AllDependencies(#[from] crate::manifest::errors::AllDependenciesError),
|
||||||
|
|
||||||
|
/// An index was not found in the manifest
|
||||||
#[error("index named {0} not found in manifest")]
|
#[error("index named {0} not found in manifest")]
|
||||||
IndexNotFound(String),
|
IndexNotFound(String),
|
||||||
|
|
||||||
|
/// An error occurred while refreshing a package source
|
||||||
#[error("error refreshing package source")]
|
#[error("error refreshing package source")]
|
||||||
Refresh(#[from] crate::source::errors::RefreshError),
|
Refresh(#[from] crate::source::errors::RefreshError),
|
||||||
|
|
||||||
|
/// An error occurred while resolving a package
|
||||||
#[error("error resolving package")]
|
#[error("error resolving package")]
|
||||||
Resolve(#[from] crate::source::errors::ResolveError),
|
Resolve(#[from] crate::source::errors::ResolveError),
|
||||||
|
|
||||||
|
/// No matching version was found for a specifier
|
||||||
#[error("no matching version found for {0}")]
|
#[error("no matching version found for {0}")]
|
||||||
NoMatchingVersion(String),
|
NoMatchingVersion(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,13 @@ use std::{
|
||||||
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
/// Script names used by pesde
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum ScriptName {
|
pub enum ScriptName {
|
||||||
|
/// Generates a config for syncing tools for Roblox. For example, for Rojo it should create a `default.project.json` file
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
RobloxSyncConfigGenerator,
|
RobloxSyncConfigGenerator,
|
||||||
|
/// Prints a sourcemap for a Wally package, used for finding the library export file
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
SourcemapGenerator,
|
SourcemapGenerator,
|
||||||
}
|
}
|
||||||
|
@ -27,6 +30,7 @@ impl Display for ScriptName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes a script with the given arguments
|
||||||
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
||||||
script_name: Option<&str>,
|
script_name: Option<&str>,
|
||||||
script_path: &Path,
|
script_path: &Path,
|
||||||
|
|
|
@ -6,14 +6,18 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A file system entry
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum FSEntry {
|
pub enum FSEntry {
|
||||||
|
/// A file with the given hash
|
||||||
#[serde(rename = "f")]
|
#[serde(rename = "f")]
|
||||||
File(String),
|
File(String),
|
||||||
|
/// A directory
|
||||||
#[serde(rename = "d")]
|
#[serde(rename = "d")]
|
||||||
Directory,
|
Directory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A package's file system
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct PackageFS(pub(crate) BTreeMap<RelativePathBuf, FSEntry>);
|
pub struct PackageFS(pub(crate) BTreeMap<RelativePathBuf, FSEntry>);
|
||||||
|
@ -37,6 +41,7 @@ pub(crate) fn store_in_cas<P: AsRef<Path>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageFS {
|
impl PackageFS {
|
||||||
|
/// Write the package to the given destination
|
||||||
pub fn write_to<P: AsRef<Path>, Q: AsRef<Path>>(
|
pub fn write_to<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
destination: P,
|
destination: P,
|
||||||
|
|
|
@ -10,23 +10,32 @@ use crate::{
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Packages' filesystems
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
/// The pesde package source
|
||||||
pub mod pesde;
|
pub mod pesde;
|
||||||
|
/// Package references
|
||||||
pub mod refs;
|
pub mod refs;
|
||||||
|
/// Dependency specifiers
|
||||||
pub mod specifiers;
|
pub mod specifiers;
|
||||||
|
/// Traits for sources and packages
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
/// Version IDs
|
||||||
pub mod version_id;
|
pub mod version_id;
|
||||||
|
|
||||||
|
/// The result of resolving a package
|
||||||
pub type ResolveResult<Ref> = (PackageNames, BTreeMap<VersionId, Ref>);
|
pub type ResolveResult<Ref> = (PackageNames, BTreeMap<VersionId, Ref>);
|
||||||
|
|
||||||
|
/// All possible package sources
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
pub enum PackageSources {
|
pub enum PackageSources {
|
||||||
|
/// A pesde package source
|
||||||
Pesde(pesde::PesdePackageSource),
|
Pesde(pesde::PesdePackageSource),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageSource for PackageSources {
|
impl PackageSource for PackageSources {
|
||||||
type Ref = PackageRefs;
|
|
||||||
type Specifier = DependencySpecifiers;
|
type Specifier = DependencySpecifiers;
|
||||||
|
type Ref = PackageRefs;
|
||||||
type RefreshError = errors::RefreshError;
|
type RefreshError = errors::RefreshError;
|
||||||
type ResolveError = errors::ResolveError;
|
type ResolveError = errors::ResolveError;
|
||||||
type DownloadError = errors::DownloadError;
|
type DownloadError = errors::DownloadError;
|
||||||
|
@ -77,32 +86,41 @@ impl PackageSource for PackageSources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when interacting with a package source
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that occur when refreshing a package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum RefreshError {
|
pub enum RefreshError {
|
||||||
|
/// The pesde package source failed to refresh
|
||||||
#[error("error refreshing pesde package source")]
|
#[error("error refreshing pesde package source")]
|
||||||
Pesde(#[from] crate::source::pesde::errors::RefreshError),
|
Pesde(#[from] crate::source::pesde::errors::RefreshError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when resolving a package
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ResolveError {
|
pub enum ResolveError {
|
||||||
|
/// The dependency specifier does not match the source (if using the CLI, this is a bug - file an issue)
|
||||||
#[error("mismatched dependency specifier for source")]
|
#[error("mismatched dependency specifier for source")]
|
||||||
Mismatch,
|
Mismatch,
|
||||||
|
|
||||||
|
/// The pesde package source failed to resolve
|
||||||
#[error("error resolving pesde package")]
|
#[error("error resolving pesde package")]
|
||||||
Pesde(#[from] crate::source::pesde::errors::ResolveError),
|
Pesde(#[from] crate::source::pesde::errors::ResolveError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when downloading a package
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum DownloadError {
|
pub enum DownloadError {
|
||||||
|
/// The package ref does not match the source (if using the CLI, this is a bug - file an issue)
|
||||||
#[error("mismatched package ref for source")]
|
#[error("mismatched package ref for source")]
|
||||||
Mismatch,
|
Mismatch,
|
||||||
|
|
||||||
|
/// The pesde package source failed to download
|
||||||
#[error("error downloading pesde package")]
|
#[error("error downloading pesde package")]
|
||||||
Pesde(#[from] crate::source::pesde::errors::DownloadError),
|
Pesde(#[from] crate::source::pesde::errors::DownloadError),
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,22 +25,29 @@ use crate::{
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The pesde package reference
|
||||||
pub mod pkg_ref;
|
pub mod pkg_ref;
|
||||||
|
/// The pesde dependency specifier
|
||||||
pub mod specifier;
|
pub mod specifier;
|
||||||
|
|
||||||
|
/// The pesde package source
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
pub struct PesdePackageSource {
|
pub struct PesdePackageSource {
|
||||||
repo_url: gix::Url,
|
repo_url: gix::Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The file containing scope information
|
||||||
pub const SCOPE_INFO_FILE: &str = "scope.toml";
|
pub const SCOPE_INFO_FILE: &str = "scope.toml";
|
||||||
|
|
||||||
|
/// Information about a scope
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ScopeInfo {
|
pub struct ScopeInfo {
|
||||||
|
/// The people authorized to publish packages to this scope
|
||||||
pub owners: BTreeSet<u64>,
|
pub owners: BTreeSet<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PesdePackageSource {
|
impl PesdePackageSource {
|
||||||
|
/// Creates a new pesde package source
|
||||||
pub fn new(repo_url: gix::Url) -> Self {
|
pub fn new(repo_url: gix::Url) -> Self {
|
||||||
Self { repo_url }
|
Self { repo_url }
|
||||||
}
|
}
|
||||||
|
@ -49,10 +56,12 @@ impl PesdePackageSource {
|
||||||
self.repo_url.to_bstring().to_vec()
|
self.repo_url.to_bstring().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The path to the index
|
||||||
pub fn path(&self, project: &Project) -> std::path::PathBuf {
|
pub fn path(&self, project: &Project) -> std::path::PathBuf {
|
||||||
project.data_dir.join("indices").join(hash(self.as_bytes()))
|
project.data_dir.join("indices").join(hash(self.as_bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The URL of the repository
|
||||||
pub fn repo_url(&self) -> &gix::Url {
|
pub fn repo_url(&self) -> &gix::Url {
|
||||||
&self.repo_url
|
&self.repo_url
|
||||||
}
|
}
|
||||||
|
@ -108,6 +117,7 @@ impl PesdePackageSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a file from the index
|
||||||
pub fn read_file<
|
pub fn read_file<
|
||||||
I: IntoIterator<Item = P> + Clone,
|
I: IntoIterator<Item = P> + Clone,
|
||||||
P: ToString + PartialEq<gix::bstr::BStr>,
|
P: ToString + PartialEq<gix::bstr::BStr>,
|
||||||
|
@ -154,6 +164,7 @@ impl PesdePackageSource {
|
||||||
Ok(Some(string))
|
Ok(Some(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads the config file
|
||||||
pub fn config(&self, project: &Project) -> Result<IndexConfig, errors::ConfigError> {
|
pub fn config(&self, project: &Project) -> Result<IndexConfig, errors::ConfigError> {
|
||||||
let file = self.read_file(["config.toml"], project).map_err(Box::new)?;
|
let file = self.read_file(["config.toml"], project).map_err(Box::new)?;
|
||||||
|
|
||||||
|
@ -171,6 +182,7 @@ impl PesdePackageSource {
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads all packages from the index
|
||||||
pub fn all_packages(
|
pub fn all_packages(
|
||||||
&self,
|
&self,
|
||||||
project: &Project,
|
project: &Project,
|
||||||
|
@ -253,6 +265,7 @@ impl PesdePackageSource {
|
||||||
Ok(packages)
|
Ok(packages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The git2 repository for the index
|
||||||
#[cfg(feature = "git2")]
|
#[cfg(feature = "git2")]
|
||||||
pub fn repo_git2(&self, project: &Project) -> Result<git2::Repository, git2::Error> {
|
pub fn repo_git2(&self, project: &Project) -> Result<git2::Repository, git2::Error> {
|
||||||
let path = self.path(project);
|
let path = self.path(project);
|
||||||
|
@ -262,8 +275,8 @@ impl PesdePackageSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackageSource for PesdePackageSource {
|
impl PackageSource for PesdePackageSource {
|
||||||
type Ref = PesdePackageRef;
|
|
||||||
type Specifier = PesdeDependencySpecifier;
|
type Specifier = PesdeDependencySpecifier;
|
||||||
|
type Ref = PesdePackageRef;
|
||||||
type RefreshError = errors::RefreshError;
|
type RefreshError = errors::RefreshError;
|
||||||
type ResolveError = errors::ResolveError;
|
type ResolveError = errors::ResolveError;
|
||||||
type DownloadError = errors::DownloadError;
|
type DownloadError = errors::DownloadError;
|
||||||
|
@ -446,23 +459,31 @@ impl PackageSource for PesdePackageSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The configuration for the pesde index
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct IndexConfig {
|
pub struct IndexConfig {
|
||||||
|
/// The URL of the API
|
||||||
pub api: url::Url,
|
pub api: url::Url,
|
||||||
|
/// The URL to download packages from
|
||||||
pub download: Option<String>,
|
pub download: Option<String>,
|
||||||
|
/// Whether git is allowed as a source for publishing packages
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub git_allowed: bool,
|
pub git_allowed: bool,
|
||||||
|
/// Whether other registries are allowed as a source for publishing packages
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub other_registries_allowed: bool,
|
pub other_registries_allowed: bool,
|
||||||
|
/// The OAuth client ID for GitHub
|
||||||
pub github_oauth_client_id: String,
|
pub github_oauth_client_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexConfig {
|
impl IndexConfig {
|
||||||
|
/// The URL of the API
|
||||||
pub fn api(&self) -> &str {
|
pub fn api(&self) -> &str {
|
||||||
self.api.as_str().trim_end_matches('/')
|
self.api.as_str().trim_end_matches('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The URL to download packages from
|
||||||
pub fn download(&self) -> String {
|
pub fn download(&self) -> String {
|
||||||
self.download
|
self.download
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
@ -471,181 +492,239 @@ impl IndexConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The entry in a package's index file
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IndexFileEntry {
|
pub struct IndexFileEntry {
|
||||||
|
/// The target for this package
|
||||||
pub target: Target,
|
pub target: Target,
|
||||||
|
/// When this package was published
|
||||||
#[serde(default = "chrono::Utc::now")]
|
#[serde(default = "chrono::Utc::now")]
|
||||||
pub published_at: chrono::DateTime<chrono::Utc>,
|
pub published_at: chrono::DateTime<chrono::Utc>,
|
||||||
|
|
||||||
|
/// The description of this package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
/// The license of this package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub license: Option<String>,
|
pub license: Option<String>,
|
||||||
|
|
||||||
|
/// The dependencies of this package
|
||||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,
|
pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The index file for a package
|
||||||
pub type IndexFile = BTreeMap<VersionId, IndexFileEntry>;
|
pub type IndexFile = BTreeMap<VersionId, IndexFileEntry>;
|
||||||
|
|
||||||
|
/// Errors that can occur when interacting with the pesde package source
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when refreshing the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum RefreshError {
|
pub enum RefreshError {
|
||||||
|
/// Error interacting with the filesystem
|
||||||
#[error("error interacting with the filesystem")]
|
#[error("error interacting with the filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// Error opening the repository
|
||||||
#[error("error opening repository at {0}")]
|
#[error("error opening repository at {0}")]
|
||||||
Open(PathBuf, #[source] gix::open::Error),
|
Open(PathBuf, #[source] gix::open::Error),
|
||||||
|
|
||||||
|
/// No default remote found in repository
|
||||||
#[error("no default remote found in repository at {0}")]
|
#[error("no default remote found in repository at {0}")]
|
||||||
NoDefaultRemote(PathBuf),
|
NoDefaultRemote(PathBuf),
|
||||||
|
|
||||||
|
/// Error getting default remote from repository
|
||||||
#[error("error getting default remote from repository at {0}")]
|
#[error("error getting default remote from repository at {0}")]
|
||||||
GetDefaultRemote(PathBuf, #[source] gix::remote::find::existing::Error),
|
GetDefaultRemote(PathBuf, #[source] gix::remote::find::existing::Error),
|
||||||
|
|
||||||
|
/// Error connecting to remote repository
|
||||||
#[error("error connecting to remote repository at {0}")]
|
#[error("error connecting to remote repository at {0}")]
|
||||||
Connect(gix::Url, #[source] gix::remote::connect::Error),
|
Connect(gix::Url, #[source] gix::remote::connect::Error),
|
||||||
|
|
||||||
|
/// Error preparing fetch from remote repository
|
||||||
#[error("error preparing fetch from remote repository at {0}")]
|
#[error("error preparing fetch from remote repository at {0}")]
|
||||||
PrepareFetch(gix::Url, #[source] gix::remote::fetch::prepare::Error),
|
PrepareFetch(gix::Url, #[source] gix::remote::fetch::prepare::Error),
|
||||||
|
|
||||||
|
/// Error reading from remote repository
|
||||||
#[error("error reading from remote repository at {0}")]
|
#[error("error reading from remote repository at {0}")]
|
||||||
Read(gix::Url, #[source] gix::remote::fetch::Error),
|
Read(gix::Url, #[source] gix::remote::fetch::Error),
|
||||||
|
|
||||||
|
/// Error cloning repository
|
||||||
#[error("error cloning repository from {0}")]
|
#[error("error cloning repository from {0}")]
|
||||||
Clone(gix::Url, #[source] gix::clone::Error),
|
Clone(gix::Url, #[source] gix::clone::Error),
|
||||||
|
|
||||||
|
/// Error fetching repository
|
||||||
#[error("error fetching repository from {0}")]
|
#[error("error fetching repository from {0}")]
|
||||||
Fetch(gix::Url, #[source] gix::clone::fetch::Error),
|
Fetch(gix::Url, #[source] gix::clone::fetch::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading the pesde package source's tree
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum TreeError {
|
pub enum TreeError {
|
||||||
|
/// Error interacting with the filesystem
|
||||||
#[error("error interacting with the filesystem")]
|
#[error("error interacting with the filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// No default remote found in repository
|
||||||
#[error("no default remote found in repository at {0}")]
|
#[error("no default remote found in repository at {0}")]
|
||||||
NoDefaultRemote(PathBuf),
|
NoDefaultRemote(PathBuf),
|
||||||
|
|
||||||
|
/// Error getting default remote from repository
|
||||||
#[error("error getting default remote from repository at {0}")]
|
#[error("error getting default remote from repository at {0}")]
|
||||||
GetDefaultRemote(PathBuf, #[source] Box<gix::remote::find::existing::Error>),
|
GetDefaultRemote(PathBuf, #[source] Box<gix::remote::find::existing::Error>),
|
||||||
|
|
||||||
|
/// Error getting refspec from remote repository
|
||||||
#[error("no refspecs found in repository at {0}")]
|
#[error("no refspecs found in repository at {0}")]
|
||||||
NoRefSpecs(PathBuf),
|
NoRefSpecs(PathBuf),
|
||||||
|
|
||||||
|
/// Error getting local refspec from remote repository
|
||||||
#[error("no local refspec found in repository at {0}")]
|
#[error("no local refspec found in repository at {0}")]
|
||||||
NoLocalRefSpec(PathBuf),
|
NoLocalRefSpec(PathBuf),
|
||||||
|
|
||||||
|
/// Error finding reference in repository
|
||||||
#[error("no reference found for local refspec {0}")]
|
#[error("no reference found for local refspec {0}")]
|
||||||
NoReference(String, #[source] gix::reference::find::existing::Error),
|
NoReference(String, #[source] gix::reference::find::existing::Error),
|
||||||
|
|
||||||
|
/// Error peeling reference in repository
|
||||||
#[error("cannot peel reference {0}")]
|
#[error("cannot peel reference {0}")]
|
||||||
CannotPeel(String, #[source] gix::reference::peel::Error),
|
CannotPeel(String, #[source] gix::reference::peel::Error),
|
||||||
|
|
||||||
|
/// Error converting id to object in repository
|
||||||
#[error("error converting id {0} to object")]
|
#[error("error converting id {0} to object")]
|
||||||
CannotConvertToObject(String, #[source] gix::object::find::existing::Error),
|
CannotConvertToObject(String, #[source] gix::object::find::existing::Error),
|
||||||
|
|
||||||
|
/// Error peeling object to tree in repository
|
||||||
#[error("error peeling object {0} to tree")]
|
#[error("error peeling object {0} to tree")]
|
||||||
CannotPeelToTree(String, #[source] gix::object::peel::to_kind::Error),
|
CannotPeelToTree(String, #[source] gix::object::peel::to_kind::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading a file from the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ReadFile {
|
pub enum ReadFile {
|
||||||
|
/// Error opening the repository
|
||||||
#[error("error opening repository at {0}")]
|
#[error("error opening repository at {0}")]
|
||||||
Open(PathBuf, #[source] Box<gix::open::Error>),
|
Open(PathBuf, #[source] Box<gix::open::Error>),
|
||||||
|
|
||||||
|
/// Error reading tree from repository
|
||||||
#[error("error getting tree from repository at {0}")]
|
#[error("error getting tree from repository at {0}")]
|
||||||
Tree(PathBuf, #[source] Box<TreeError>),
|
Tree(PathBuf, #[source] Box<TreeError>),
|
||||||
|
|
||||||
|
/// Error looking up entry in tree
|
||||||
#[error("error looking up entry {0} in tree")]
|
#[error("error looking up entry {0} in tree")]
|
||||||
Lookup(String, #[source] gix::object::find::existing::Error),
|
Lookup(String, #[source] gix::object::find::existing::Error),
|
||||||
|
|
||||||
|
/// Error reading file as utf8
|
||||||
#[error("error parsing file for {0} as utf8")]
|
#[error("error parsing file for {0} as utf8")]
|
||||||
Utf8(String, #[source] std::string::FromUtf8Error),
|
Utf8(String, #[source] std::string::FromUtf8Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when resolving a package from the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ResolveError {
|
pub enum ResolveError {
|
||||||
|
/// Error interacting with the filesystem
|
||||||
#[error("error interacting with the filesystem")]
|
#[error("error interacting with the filesystem")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// Package not found in index
|
||||||
#[error("package {0} not found")]
|
#[error("package {0} not found")]
|
||||||
NotFound(String),
|
NotFound(String),
|
||||||
|
|
||||||
|
/// Error reading file for package
|
||||||
#[error("error reading file for {0}")]
|
#[error("error reading file for {0}")]
|
||||||
Read(String, #[source] Box<ReadFile>),
|
Read(String, #[source] Box<ReadFile>),
|
||||||
|
|
||||||
|
/// Error parsing file for package
|
||||||
#[error("error parsing file for {0}")]
|
#[error("error parsing file for {0}")]
|
||||||
Parse(String, #[source] toml::de::Error),
|
Parse(String, #[source] toml::de::Error),
|
||||||
|
|
||||||
|
/// Error parsing file for package as utf8
|
||||||
#[error("error parsing file for {0} to utf8")]
|
#[error("error parsing file for {0} to utf8")]
|
||||||
Utf8(String, #[source] std::string::FromUtf8Error),
|
Utf8(String, #[source] std::string::FromUtf8Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading the config file for the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
|
/// Error reading file
|
||||||
#[error("error reading config file")]
|
#[error("error reading config file")]
|
||||||
ReadFile(#[from] Box<ReadFile>),
|
ReadFile(#[from] Box<ReadFile>),
|
||||||
|
|
||||||
|
/// Error parsing config file
|
||||||
#[error("error parsing config file")]
|
#[error("error parsing config file")]
|
||||||
Parse(#[from] toml::de::Error),
|
Parse(#[from] toml::de::Error),
|
||||||
|
|
||||||
|
/// The config file is missing
|
||||||
#[error("missing config file for index at {0}")]
|
#[error("missing config file for index at {0}")]
|
||||||
Missing(Box<gix::Url>),
|
Missing(Box<gix::Url>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when reading all packages from the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum AllPackagesError {
|
pub enum AllPackagesError {
|
||||||
|
/// Error opening the repository
|
||||||
#[error("error opening repository at {0}")]
|
#[error("error opening repository at {0}")]
|
||||||
Open(PathBuf, #[source] Box<gix::open::Error>),
|
Open(PathBuf, #[source] Box<gix::open::Error>),
|
||||||
|
|
||||||
|
/// Error reading tree from repository
|
||||||
#[error("error getting tree from repository at {0}")]
|
#[error("error getting tree from repository at {0}")]
|
||||||
Tree(PathBuf, #[source] Box<TreeError>),
|
Tree(PathBuf, #[source] Box<TreeError>),
|
||||||
|
|
||||||
|
/// Error decoding entry in repository
|
||||||
#[error("error decoding entry in repository at {0}")]
|
#[error("error decoding entry in repository at {0}")]
|
||||||
Decode(PathBuf, #[source] gix::objs::decode::Error),
|
Decode(PathBuf, #[source] gix::objs::decode::Error),
|
||||||
|
|
||||||
|
/// Error converting entry in repository
|
||||||
#[error("error converting entry in repository at {0}")]
|
#[error("error converting entry in repository at {0}")]
|
||||||
Convert(PathBuf, #[source] gix::object::find::existing::Error),
|
Convert(PathBuf, #[source] gix::object::find::existing::Error),
|
||||||
|
|
||||||
|
/// Error deserializing file in repository
|
||||||
#[error("error deserializing file {0} in repository at {1}")]
|
#[error("error deserializing file {0} in repository at {1}")]
|
||||||
Deserialize(String, PathBuf, #[source] Box<toml::de::Error>),
|
Deserialize(String, PathBuf, #[source] Box<toml::de::Error>),
|
||||||
|
|
||||||
|
/// Error parsing file in repository as utf8
|
||||||
#[error("error parsing file for {0} as utf8")]
|
#[error("error parsing file for {0} as utf8")]
|
||||||
Utf8(String, #[source] std::string::FromUtf8Error),
|
Utf8(String, #[source] std::string::FromUtf8Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when downloading a package from the pesde package source
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum DownloadError {
|
pub enum DownloadError {
|
||||||
|
/// Error reading index file
|
||||||
#[error("error reading config file")]
|
#[error("error reading config file")]
|
||||||
ReadFile(#[from] Box<ConfigError>),
|
ReadFile(#[from] Box<ConfigError>),
|
||||||
|
|
||||||
|
/// Error downloading package
|
||||||
#[error("error downloading package")]
|
#[error("error downloading package")]
|
||||||
Download(#[from] reqwest::Error),
|
Download(#[from] reqwest::Error),
|
||||||
|
|
||||||
|
/// Error unpacking package
|
||||||
#[error("error unpacking package")]
|
#[error("error unpacking package")]
|
||||||
Unpack(#[from] std::io::Error),
|
Unpack(#[from] std::io::Error),
|
||||||
|
|
||||||
|
/// Error writing index file
|
||||||
#[error("error writing index file")]
|
#[error("error writing index file")]
|
||||||
WriteIndex(#[source] std::io::Error),
|
WriteIndex(#[source] std::io::Error),
|
||||||
|
|
||||||
|
/// Error serializing index file
|
||||||
#[error("error serializing index file")]
|
#[error("error serializing index file")]
|
||||||
SerializeIndex(#[from] toml::ser::Error),
|
SerializeIndex(#[from] toml::ser::Error),
|
||||||
|
|
||||||
|
/// Error deserializing index file
|
||||||
#[error("error deserializing index file")]
|
#[error("error deserializing index file")]
|
||||||
DeserializeIndex(#[from] toml::de::Error),
|
DeserializeIndex(#[from] toml::de::Error),
|
||||||
|
|
||||||
|
/// Error writing index file
|
||||||
#[error("error reading index file")]
|
#[error("error reading index file")]
|
||||||
ReadIndex(#[source] std::io::Error),
|
ReadIndex(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,17 @@ use semver::VersionReq;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
/// The specifier for a pesde dependency
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct PesdeDependencySpecifier {
|
pub struct PesdeDependencySpecifier {
|
||||||
|
/// The name of the package
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
|
/// The version requirement for the package
|
||||||
pub version: VersionReq,
|
pub version: VersionReq,
|
||||||
|
/// The index to use for the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub index: Option<String>,
|
pub index: Option<String>,
|
||||||
|
/// The target to use for the package
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub target: Option<TargetKind>,
|
pub target: Option<TargetKind>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@ use crate::{
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
/// All possible package references
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "snake_case", tag = "ref_ty")]
|
#[serde(rename_all = "snake_case", tag = "ref_ty")]
|
||||||
pub enum PackageRefs {
|
pub enum PackageRefs {
|
||||||
|
/// A pesde package reference
|
||||||
Pesde(pesde::pkg_ref::PesdePackageRef),
|
Pesde(pesde::pkg_ref::PesdePackageRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,11 @@ use crate::source::{pesde, traits::DependencySpecifier};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
/// All possible dependency specifiers
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum DependencySpecifiers {
|
pub enum DependencySpecifiers {
|
||||||
|
/// A pesde dependency specifier
|
||||||
Pesde(pesde::specifier::PesdeDependencySpecifier),
|
Pesde(pesde::specifier::PesdeDependencySpecifier),
|
||||||
}
|
}
|
||||||
impl DependencySpecifier for DependencySpecifiers {}
|
impl DependencySpecifier for DependencySpecifiers {}
|
||||||
|
|
|
@ -12,26 +12,40 @@ use crate::{
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A specifier for a dependency
|
||||||
pub trait DependencySpecifier: Debug + Display {}
|
pub trait DependencySpecifier: Debug + Display {}
|
||||||
|
|
||||||
|
/// A reference to a package
|
||||||
pub trait PackageRef: Debug {
|
pub trait PackageRef: Debug {
|
||||||
|
/// The dependencies of this package
|
||||||
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)>;
|
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)>;
|
||||||
|
/// Whether to use the new structure (`packages` folders inside the package's content folder) or the old structure (Wally-style, with linker files in the parent of the folder containing the package's contents)
|
||||||
fn use_new_structure(&self) -> bool;
|
fn use_new_structure(&self) -> bool;
|
||||||
|
/// The target of this package
|
||||||
fn target_kind(&self) -> TargetKind;
|
fn target_kind(&self) -> TargetKind;
|
||||||
|
/// The source of this package
|
||||||
fn source(&self) -> PackageSources;
|
fn source(&self) -> PackageSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A source of packages
|
||||||
pub trait PackageSource: Debug {
|
pub trait PackageSource: Debug {
|
||||||
type Ref: PackageRef;
|
/// The specifier type for this source
|
||||||
type Specifier: DependencySpecifier;
|
type Specifier: DependencySpecifier;
|
||||||
|
/// The reference type for this source
|
||||||
|
type Ref: PackageRef;
|
||||||
|
/// The error type for refreshing this source
|
||||||
type RefreshError: std::error::Error;
|
type RefreshError: std::error::Error;
|
||||||
|
/// The error type for resolving a package from this source
|
||||||
type ResolveError: std::error::Error;
|
type ResolveError: std::error::Error;
|
||||||
|
/// The error type for downloading a package from this source
|
||||||
type DownloadError: std::error::Error;
|
type DownloadError: std::error::Error;
|
||||||
|
|
||||||
|
/// Refreshes the source
|
||||||
fn refresh(&self, _project: &Project) -> Result<(), Self::RefreshError> {
|
fn refresh(&self, _project: &Project) -> Result<(), Self::RefreshError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves a specifier to a reference
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &Self::Specifier,
|
specifier: &Self::Specifier,
|
||||||
|
@ -39,6 +53,7 @@ pub trait PackageSource: Debug {
|
||||||
project_target: TargetKind,
|
project_target: TargetKind,
|
||||||
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError>;
|
) -> Result<ResolveResult<Self::Ref>, Self::ResolveError>;
|
||||||
|
|
||||||
|
/// Downloads a package
|
||||||
fn download(
|
fn download(
|
||||||
&self,
|
&self,
|
||||||
pkg_ref: &Self::Ref,
|
pkg_ref: &Self::Ref,
|
||||||
|
|
|
@ -3,24 +3,29 @@ use semver::Version;
|
||||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
|
/// A version ID, which is a combination of a version and a target
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
Debug, SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
||||||
)]
|
)]
|
||||||
pub struct VersionId(pub(crate) Version, pub(crate) TargetKind);
|
pub struct VersionId(pub(crate) Version, pub(crate) TargetKind);
|
||||||
|
|
||||||
impl VersionId {
|
impl VersionId {
|
||||||
|
/// Creates a new version ID
|
||||||
pub fn new(version: Version, target: TargetKind) -> Self {
|
pub fn new(version: Version, target: TargetKind) -> Self {
|
||||||
VersionId(version, target)
|
VersionId(version, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the version
|
||||||
pub fn version(&self) -> &Version {
|
pub fn version(&self) -> &Version {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Access the target
|
||||||
pub fn target(&self) -> &TargetKind {
|
pub fn target(&self) -> &TargetKind {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns this version ID as a string that can be used in the filesystem
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
format!("{}+{}", self.0, self.1)
|
format!("{}+{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
|
@ -47,18 +52,23 @@ impl FromStr for VersionId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when using a version ID
|
||||||
pub mod errors {
|
pub mod errors {
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Errors that can occur when parsing a version ID
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum VersionIdParseError {
|
pub enum VersionIdParseError {
|
||||||
#[error("malformed entry key {0}")]
|
/// The version ID is malformed
|
||||||
|
#[error("malformed version id {0}")]
|
||||||
Malformed(String),
|
Malformed(String),
|
||||||
|
|
||||||
|
/// The version is malformed
|
||||||
#[error("malformed version")]
|
#[error("malformed version")]
|
||||||
Version(#[from] semver::Error),
|
Version(#[from] semver::Error),
|
||||||
|
|
||||||
|
/// The target is malformed
|
||||||
#[error("malformed target")]
|
#[error("malformed target")]
|
||||||
Target(#[from] crate::manifest::target::errors::TargetKindFromStr),
|
Target(#[from] crate::manifest::target::errors::TargetKindFromStr),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue