mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: implement linking
This commit is contained in:
parent
fdad8995a4
commit
10ca24a0cc
14 changed files with 630 additions and 101 deletions
|
@ -1,12 +1,24 @@
|
||||||
|
use anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::Project;
|
use pesde::Project;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct InstallCommand {}
|
pub struct InstallCommand {}
|
||||||
|
|
||||||
impl InstallCommand {
|
impl InstallCommand {
|
||||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||||
dbg!(project.dependency_graph(None)?);
|
let mut refreshed_sources = HashSet::new();
|
||||||
|
let graph = project
|
||||||
|
.dependency_graph(None, &mut refreshed_sources)
|
||||||
|
.context("failed to build dependency graph")?;
|
||||||
|
let downloaded_graph = project
|
||||||
|
.download_graph(&graph, &mut refreshed_sources)
|
||||||
|
.context("failed to download dependencies")?;
|
||||||
|
|
||||||
|
project
|
||||||
|
.link_dependencies(&downloaded_graph)
|
||||||
|
.context("failed to link dependencies")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
79
src/download.rs
Normal file
79
src/download.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashSet},
|
||||||
|
fs::create_dir_all,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
lockfile::{DependencyGraph, DownloadedDependencyGraphNode, DownloadedGraph},
|
||||||
|
source::{pesde::PesdePackageSource, PackageRefs, PackageSource, PackageSources},
|
||||||
|
Project, PACKAGES_CONTAINER_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Project {
|
||||||
|
pub fn download_graph(
|
||||||
|
&self,
|
||||||
|
graph: &DependencyGraph,
|
||||||
|
refreshed_sources: &mut HashSet<PackageSources>,
|
||||||
|
) -> Result<DownloadedGraph, errors::DownloadGraphError> {
|
||||||
|
let manifest = self.deser_manifest()?;
|
||||||
|
|
||||||
|
let mut downloaded_graph: DownloadedGraph = BTreeMap::new();
|
||||||
|
|
||||||
|
for (name, versions) in graph {
|
||||||
|
for (version, node) in versions {
|
||||||
|
let source = match &node.pkg_ref {
|
||||||
|
PackageRefs::Pesde(pkg_ref) => {
|
||||||
|
PackageSources::Pesde(PesdePackageSource::new(pkg_ref.index_url.clone()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if refreshed_sources.insert(source.clone()) {
|
||||||
|
source.refresh(self).map_err(Box::new)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let container_folder = node.container_folder(
|
||||||
|
&self
|
||||||
|
.path()
|
||||||
|
.join(node.base_folder(manifest.target.kind(), true))
|
||||||
|
.join(PACKAGES_CONTAINER_NAME),
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
);
|
||||||
|
|
||||||
|
create_dir_all(&container_folder)?;
|
||||||
|
|
||||||
|
let target = source.download(&node.pkg_ref, &container_folder, self)?;
|
||||||
|
|
||||||
|
downloaded_graph.entry(name.clone()).or_default().insert(
|
||||||
|
version.clone(),
|
||||||
|
DownloadedDependencyGraphNode {
|
||||||
|
node: node.clone(),
|
||||||
|
target,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(downloaded_graph)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod errors {
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum DownloadGraphError {
|
||||||
|
#[error("error deserializing project manifest")]
|
||||||
|
ManifestDeserializationFailed(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
#[error("failed to refresh package source")]
|
||||||
|
RefreshFailed(#[from] Box<crate::source::errors::RefreshError>),
|
||||||
|
|
||||||
|
#[error("error interacting with filesystem")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error("failed to download package")]
|
||||||
|
DownloadFailed(#[from] crate::source::errors::DownloadError),
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ use crate::lockfile::Lockfile;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub mod download;
|
||||||
|
pub mod linking;
|
||||||
pub mod lockfile;
|
pub mod lockfile;
|
||||||
pub mod manifest;
|
pub mod manifest;
|
||||||
pub mod names;
|
pub mod names;
|
||||||
|
@ -17,6 +19,7 @@ pub mod source;
|
||||||
pub const MANIFEST_FILE_NAME: &str = "pesde.yaml";
|
pub const MANIFEST_FILE_NAME: &str = "pesde.yaml";
|
||||||
pub const LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
pub const LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
||||||
pub const DEFAULT_INDEX_NAME: &str = "default";
|
pub const DEFAULT_INDEX_NAME: &str = "default";
|
||||||
|
pub const PACKAGES_CONTAINER_NAME: &str = ".pesde";
|
||||||
|
|
||||||
pub(crate) static REQWEST_CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| {
|
pub(crate) static REQWEST_CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| {
|
||||||
reqwest::blocking::Client::builder()
|
reqwest::blocking::Client::builder()
|
||||||
|
|
128
src/linking/generator.rs
Normal file
128
src/linking/generator.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
use std::path::{Component, Path};
|
||||||
|
|
||||||
|
use full_moon::{ast::luau::ExportedTypeDeclaration, visitors::Visitor};
|
||||||
|
|
||||||
|
use crate::manifest::Target;
|
||||||
|
|
||||||
|
struct TypeVisitor {
|
||||||
|
types: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visitor for TypeVisitor {
|
||||||
|
fn visit_exported_type_declaration(&mut self, node: &ExportedTypeDeclaration) {
|
||||||
|
let name = node.type_declaration().type_name().to_string();
|
||||||
|
|
||||||
|
let (declaration_generics, generics) =
|
||||||
|
if let Some(declaration) = node.type_declaration().generics() {
|
||||||
|
let mut declaration_generics = vec![];
|
||||||
|
let mut generics = vec![];
|
||||||
|
|
||||||
|
for generic in declaration.generics().iter() {
|
||||||
|
declaration_generics.push(generic.to_string());
|
||||||
|
|
||||||
|
if generic.default_type().is_some() {
|
||||||
|
generics.push(generic.parameter().to_string())
|
||||||
|
} else {
|
||||||
|
generics.push(generic.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
format!("<{}>", declaration_generics.join(", ")),
|
||||||
|
format!("<{}>", generics.join(", ")),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
("".to_string(), "".to_string())
|
||||||
|
};
|
||||||
|
|
||||||
|
self.types.push(format!(
|
||||||
|
"export type {name}{declaration_generics} = module.{name}{generics}\n"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_file_types(file: &str) -> Result<Vec<String>, Vec<full_moon::Error>> {
|
||||||
|
let ast = full_moon::parse(file)?;
|
||||||
|
let mut visitor = TypeVisitor { types: vec![] };
|
||||||
|
visitor.visit_ast(&ast);
|
||||||
|
|
||||||
|
Ok(visitor.types)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
|
||||||
|
path: &str,
|
||||||
|
types: I,
|
||||||
|
) -> String {
|
||||||
|
let mut output = format!("local module = require({path})\n");
|
||||||
|
|
||||||
|
for ty in types {
|
||||||
|
output.push_str(ty.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str("return module");
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_require_path(
|
||||||
|
target: &Target,
|
||||||
|
base_dir: &Path,
|
||||||
|
destination_dir: &Path,
|
||||||
|
use_new_structure: bool,
|
||||||
|
) -> Result<String, errors::GetRequirePathError> {
|
||||||
|
let Some(lib_file) = target.lib_path() else {
|
||||||
|
return Err(errors::GetRequirePathError::NoLibPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = pathdiff::diff_paths(destination_dir, base_dir).unwrap();
|
||||||
|
let path = if !use_new_structure {
|
||||||
|
lib_file.to_path(path)
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
if matches!(target, Target::Roblox { .. }) {
|
||||||
|
let path = path
|
||||||
|
.components()
|
||||||
|
.filter_map(|component| match component {
|
||||||
|
Component::ParentDir => Some(".Parent".to_string()),
|
||||||
|
Component::Normal(part) if part != "init.lua" && part != "init.luau" => {
|
||||||
|
Some(format!(
|
||||||
|
"[{:?}]",
|
||||||
|
part.to_string_lossy()
|
||||||
|
.trim_end_matches(".lua")
|
||||||
|
.trim_end_matches(".luau")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
return Ok(format!("script{path}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = path
|
||||||
|
.components()
|
||||||
|
.filter_map(|ct| match ct {
|
||||||
|
Component::ParentDir => Some("..".to_string()),
|
||||||
|
Component::Normal(part) => Some(format!("{}", part.to_string_lossy())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("/");
|
||||||
|
|
||||||
|
Ok(format!("./{path}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod errors {
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum GetRequirePathError {
|
||||||
|
#[error("get require path called for target without a lib path")]
|
||||||
|
NoLibPath,
|
||||||
|
}
|
||||||
|
}
|
177
src/linking/mod.rs
Normal file
177
src/linking/mod.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use crate::{
|
||||||
|
linking::generator::get_file_types, lockfile::DownloadedGraph, manifest::Manifest,
|
||||||
|
names::PackageNames, source::PackageRef, Project, MANIFEST_FILE_NAME, PACKAGES_CONTAINER_NAME,
|
||||||
|
};
|
||||||
|
use semver::Version;
|
||||||
|
use std::{collections::BTreeMap, fs::create_dir_all};
|
||||||
|
|
||||||
|
pub mod generator;
|
||||||
|
|
||||||
|
fn read_manifest(path: &std::path::Path) -> Result<Manifest, errors::LinkingError> {
|
||||||
|
let manifest = std::fs::read_to_string(path.join(MANIFEST_FILE_NAME))?;
|
||||||
|
serde_yaml::from_str(&manifest)
|
||||||
|
.map_err(|e| errors::LinkingError::DependencyManifest(path.display().to_string(), e))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Project {
|
||||||
|
pub fn link_dependencies(&self, graph: &DownloadedGraph) -> Result<(), errors::LinkingError> {
|
||||||
|
let manifest = self.deser_manifest()?;
|
||||||
|
|
||||||
|
let mut package_types = BTreeMap::<&PackageNames, BTreeMap<&Version, Vec<String>>>::new();
|
||||||
|
|
||||||
|
for (name, versions) in graph {
|
||||||
|
for (version, node) in versions {
|
||||||
|
let Some(lib_file) = node.target.lib_path() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let container_folder = node.node.container_folder(
|
||||||
|
&self
|
||||||
|
.path()
|
||||||
|
.join(node.node.base_folder(manifest.target.kind(), true))
|
||||||
|
.join(PACKAGES_CONTAINER_NAME),
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
);
|
||||||
|
|
||||||
|
let lib_file = lib_file.to_path(container_folder);
|
||||||
|
|
||||||
|
let contents = match std::fs::read_to_string(&lib_file) {
|
||||||
|
Ok(contents) => contents,
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
return Err(errors::LinkingError::LibFileNotFound(
|
||||||
|
lib_file.display().to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let types = match get_file_types(&contents) {
|
||||||
|
Ok(types) => types,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(errors::LinkingError::FullMoon(
|
||||||
|
lib_file.display().to_string(),
|
||||||
|
e,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
package_types
|
||||||
|
.entry(name)
|
||||||
|
.or_default()
|
||||||
|
.insert(version, types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, versions) in graph {
|
||||||
|
for (version, node) in versions {
|
||||||
|
let base_folder = self.path().join(
|
||||||
|
self.path()
|
||||||
|
.join(node.node.base_folder(manifest.target.kind(), true)),
|
||||||
|
);
|
||||||
|
create_dir_all(&base_folder)?;
|
||||||
|
let base_folder = base_folder.canonicalize()?;
|
||||||
|
let packages_container_folder = base_folder.join(PACKAGES_CONTAINER_NAME);
|
||||||
|
|
||||||
|
let container_folder =
|
||||||
|
node.node
|
||||||
|
.container_folder(&packages_container_folder, name, version);
|
||||||
|
|
||||||
|
let node_manifest = read_manifest(&container_folder)?;
|
||||||
|
|
||||||
|
if let Some((alias, types)) = package_types
|
||||||
|
.get(name)
|
||||||
|
.and_then(|v| v.get(version))
|
||||||
|
.and_then(|types| node.node.direct.as_ref().map(|(alias, _)| (alias, types)))
|
||||||
|
{
|
||||||
|
let module = generator::generate_linking_module(
|
||||||
|
&generator::get_require_path(
|
||||||
|
&node_manifest.target,
|
||||||
|
&base_folder,
|
||||||
|
&container_folder,
|
||||||
|
node.node.pkg_ref.use_new_structure(),
|
||||||
|
)?,
|
||||||
|
types,
|
||||||
|
);
|
||||||
|
|
||||||
|
std::fs::write(base_folder.join(format!("{alias}.luau")), module)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dependency_name, (dependency_version, dependency_alias)) in
|
||||||
|
&node.node.dependencies
|
||||||
|
{
|
||||||
|
let Some(dependency_node) = graph
|
||||||
|
.get(dependency_name)
|
||||||
|
.and_then(|v| v.get(dependency_version))
|
||||||
|
else {
|
||||||
|
return Err(errors::LinkingError::DependencyNotFound(
|
||||||
|
dependency_name.to_string(),
|
||||||
|
dependency_version.to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let dependency_container_folder = dependency_node.node.container_folder(
|
||||||
|
&packages_container_folder,
|
||||||
|
dependency_name,
|
||||||
|
dependency_version,
|
||||||
|
);
|
||||||
|
|
||||||
|
let dependency_manifest = read_manifest(&dependency_container_folder)?;
|
||||||
|
|
||||||
|
let linker_folder = container_folder
|
||||||
|
.join(dependency_node.node.base_folder(node.target.kind(), false));
|
||||||
|
create_dir_all(&linker_folder)?;
|
||||||
|
let linker_folder = linker_folder.canonicalize()?;
|
||||||
|
|
||||||
|
let linker_file = linker_folder.join(format!("{dependency_alias}.luau"));
|
||||||
|
|
||||||
|
let module = generator::generate_linking_module(
|
||||||
|
&generator::get_require_path(
|
||||||
|
&dependency_manifest.target,
|
||||||
|
&linker_file,
|
||||||
|
&dependency_container_folder,
|
||||||
|
node.node.pkg_ref.use_new_structure(),
|
||||||
|
)?,
|
||||||
|
package_types
|
||||||
|
.get(dependency_name)
|
||||||
|
.and_then(|v| v.get(dependency_version))
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
std::fs::write(linker_file, module)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod errors {
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum LinkingError {
|
||||||
|
#[error("error deserializing project manifest")]
|
||||||
|
Manifest(#[from] crate::errors::ManifestReadError),
|
||||||
|
|
||||||
|
#[error("error deserializing manifest at {0}")]
|
||||||
|
DependencyManifest(String, #[source] serde_yaml::Error),
|
||||||
|
|
||||||
|
#[error("error interacting with filesystem")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error("dependency not found: {0}@{1}")]
|
||||||
|
DependencyNotFound(String, String),
|
||||||
|
|
||||||
|
#[error("library file at {0} not found")]
|
||||||
|
LibFileNotFound(String),
|
||||||
|
|
||||||
|
#[error("error parsing Luau script at {0}")]
|
||||||
|
FullMoon(String, Vec<full_moon::Error>),
|
||||||
|
|
||||||
|
#[error("error generating require path")]
|
||||||
|
GetRequirePath(#[from] crate::linking::generator::errors::GetRequirePathError),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
manifest::{DependencyType, OverrideKey},
|
manifest::{DependencyType, OverrideKey, Target, TargetKind},
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
source::{DependencySpecifiers, PackageRefs},
|
source::{DependencySpecifiers, PackageRef, PackageRefs},
|
||||||
};
|
};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{btree_map::Entry, BTreeMap};
|
use std::{
|
||||||
|
collections::{btree_map::Entry, BTreeMap},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type Graph<Node> = BTreeMap<PackageNames, BTreeMap<Version, Node>>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct DependencyGraphNode {
|
pub struct DependencyGraphNode {
|
||||||
|
@ -16,7 +21,29 @@ pub struct DependencyGraphNode {
|
||||||
pub ty: DependencyType,
|
pub ty: DependencyType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DependencyGraph = BTreeMap<PackageNames, BTreeMap<Version, DependencyGraphNode>>;
|
impl DependencyGraphNode {
|
||||||
|
pub fn base_folder(&self, project_target: TargetKind, is_top_level: bool) -> String {
|
||||||
|
if is_top_level || self.pkg_ref.use_new_structure() {
|
||||||
|
project_target.packages_folder(&self.pkg_ref.target_kind())
|
||||||
|
} else {
|
||||||
|
"..".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn container_folder<P: AsRef<Path>>(
|
||||||
|
&self,
|
||||||
|
path: &P,
|
||||||
|
name: &PackageNames,
|
||||||
|
version: &Version,
|
||||||
|
) -> PathBuf {
|
||||||
|
path.as_ref()
|
||||||
|
.join(name.escaped())
|
||||||
|
.join(version.to_string())
|
||||||
|
.join(name.as_str().1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DependencyGraph = Graph<DependencyGraphNode>;
|
||||||
|
|
||||||
pub fn insert_node(
|
pub fn insert_node(
|
||||||
graph: &mut DependencyGraph,
|
graph: &mut DependencyGraph,
|
||||||
|
@ -50,6 +77,14 @@ pub fn insert_node(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct DownloadedDependencyGraphNode {
|
||||||
|
pub node: DependencyGraphNode,
|
||||||
|
pub target: Target,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DownloadedGraph = Graph<DownloadedDependencyGraphNode>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Lockfile {
|
pub struct Lockfile {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -2,6 +2,7 @@ use crate::cli::get_token;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use pesde::{AuthConfig, Project};
|
use pesde::{AuthConfig, Project};
|
||||||
|
use std::fs::create_dir_all;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
let data_dir = project_dirs.data_dir();
|
let data_dir = project_dirs.data_dir();
|
||||||
|
create_dir_all(data_dir).expect("failed to create data directory");
|
||||||
|
|
||||||
if let Err(err) = get_token(data_dir).and_then(|token| {
|
if let Err(err) = get_token(data_dir).and_then(|token| {
|
||||||
cli.subcommand.run(Project::new(
|
cli.subcommand.run(Project::new(
|
||||||
|
@ -35,16 +37,33 @@ fn main() {
|
||||||
AuthConfig::new().with_pesde_token(token),
|
AuthConfig::new().with_pesde_token(token),
|
||||||
))
|
))
|
||||||
}) {
|
}) {
|
||||||
eprintln!("{}: {}\n", "error".red().bold(), err.to_string().bold());
|
eprintln!("{}: {err}\n", "error".red().bold());
|
||||||
|
|
||||||
let cause = err.chain().skip(1).collect::<Vec<_>>();
|
let cause = err.chain().skip(1).collect::<Vec<_>>();
|
||||||
|
|
||||||
if !cause.is_empty() {
|
if !cause.is_empty() {
|
||||||
eprintln!("{}:", "caused by".red().bold());
|
eprintln!("{}:", "caused by".red().bold());
|
||||||
for err in cause {
|
for err in cause {
|
||||||
eprintln!(" - {}", err.to_string().bold());
|
eprintln!(" - {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let backtrace = err.backtrace();
|
||||||
|
match backtrace.status() {
|
||||||
|
std::backtrace::BacktraceStatus::Disabled => {
|
||||||
|
eprintln!(
|
||||||
|
"\n{}: set RUST_BACKTRACE=1 for a backtrace",
|
||||||
|
"help".yellow().bold()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::backtrace::BacktraceStatus::Captured => {
|
||||||
|
eprintln!("\n{}:\n{backtrace}", "backtrace".yellow().bold());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!("\n{}: not captured", "backtrace".yellow().bold());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
|
@ -58,7 +58,7 @@ impl TargetKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
#[serde(rename_all = "snake_case", tag = "environment", remote = "Self")]
|
#[serde(rename_all = "snake_case", tag = "environment", remote = "Self")]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
|
@ -75,6 +75,39 @@ pub enum Target {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Target {
|
||||||
|
pub fn kind(&self) -> TargetKind {
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
Target::Roblox { .. } => TargetKind::Roblox,
|
||||||
|
#[cfg(feature = "lune")]
|
||||||
|
Target::Lune { .. } => TargetKind::Lune,
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
Target::Luau { .. } => TargetKind::Luau,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "roblox")]
|
||||||
|
Target::Roblox { lib } => Some(lib),
|
||||||
|
#[cfg(feature = "lune")]
|
||||||
|
Target::Lune { lib, .. } => lib.as_ref(),
|
||||||
|
#[cfg(feature = "luau")]
|
||||||
|
Target::Luau { lib, .. } => lib.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Target {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
Self::serialize(self, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Target {
|
impl<'de> Deserialize<'de> for Target {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -115,19 +148,6 @@ impl Display for Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
|
||||||
pub fn kind(&self) -> TargetKind {
|
|
||||||
match self {
|
|
||||||
#[cfg(feature = "roblox")]
|
|
||||||
Target::Roblox { .. } => TargetKind::Roblox,
|
|
||||||
#[cfg(feature = "lune")]
|
|
||||||
Target::Lune { .. } => TargetKind::Lune,
|
|
||||||
#[cfg(feature = "luau")]
|
|
||||||
Target::Luau { .. } => TargetKind::Luau,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
Debug, DeserializeFromStr, SerializeDisplay, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
|
||||||
)]
|
)]
|
||||||
|
@ -189,10 +209,10 @@ pub struct Manifest {
|
||||||
pub scripts: BTreeMap<String, RelativePathBuf>,
|
pub scripts: BTreeMap<String, RelativePathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub indices: BTreeMap<String, url::Url>,
|
pub indices: BTreeMap<String, url::Url>,
|
||||||
#[cfg(feature = "wally")]
|
#[cfg(feature = "wally-compat")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wally_indices: BTreeMap<String, url::Url>,
|
pub wally_indices: BTreeMap<String, url::Url>,
|
||||||
#[cfg(all(feature = "wally", feature = "roblox"))]
|
#[cfg(all(feature = "wally-compat", feature = "roblox"))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub sourcemap_generator: Option<String>,
|
pub sourcemap_generator: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
18
src/names.rs
18
src/names.rs
|
@ -63,6 +63,10 @@ impl PackageName {
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
(&self.0, &self.1)
|
(&self.0, &self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn escaped(&self) -> String {
|
||||||
|
format!("{}+{}", self.0, self.1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -70,6 +74,20 @@ pub enum PackageNames {
|
||||||
Pesde(PackageName),
|
Pesde(PackageName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PackageNames {
|
||||||
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
|
match self {
|
||||||
|
PackageNames::Pesde(name) => name.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn escaped(&self) -> String {
|
||||||
|
match self {
|
||||||
|
PackageNames::Pesde(name) => name.escaped(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for PackageNames {
|
impl Display for PackageNames {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -11,19 +11,17 @@ use semver::Version;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
// TODO: implement dependency overrides
|
// TODO: implement dependency overrides, account for targets using the is_compatible_with method
|
||||||
pub fn dependency_graph(
|
pub fn dependency_graph(
|
||||||
&self,
|
&self,
|
||||||
previous_graph: Option<&DependencyGraph>,
|
previous_graph: Option<&DependencyGraph>,
|
||||||
|
refreshed_sources: &mut HashSet<PackageSources>,
|
||||||
) -> Result<DependencyGraph, Box<errors::DependencyGraphError>> {
|
) -> Result<DependencyGraph, Box<errors::DependencyGraphError>> {
|
||||||
let manifest = self.deser_manifest().map_err(|e| Box::new(e.into()))?;
|
let manifest = self.deser_manifest().map_err(|e| Box::new(e.into()))?;
|
||||||
|
|
||||||
let mut all_dependencies = manifest
|
let mut all_specifiers = manifest
|
||||||
.all_dependencies()
|
.all_dependencies()
|
||||||
.map_err(|e| Box::new(e.into()))?;
|
.map_err(|e| Box::new(e.into()))?
|
||||||
|
|
||||||
let mut all_specifiers = all_dependencies
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(alias, (spec, ty))| ((spec, ty), alias))
|
.map(|(alias, (spec, ty))| ((spec, ty), alias))
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
@ -38,14 +36,12 @@ impl Project {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
match all_specifiers.remove(&(specifier.clone(), node.ty)) {
|
if all_specifiers
|
||||||
Some(alias) => {
|
.remove(&(specifier.clone(), node.ty))
|
||||||
all_dependencies.remove(&alias);
|
.is_none()
|
||||||
}
|
{
|
||||||
None => {
|
// this dependency is no longer in the manifest, or it's type has changed
|
||||||
// this dependency is no longer in the manifest, or it's type has changed
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("resolved {}@{} from old dependency graph", name, version);
|
log::debug!("resolved {}@{} from old dependency graph", name, version);
|
||||||
|
@ -96,10 +92,9 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut refreshed_sources = HashSet::new();
|
let mut queue = all_specifiers
|
||||||
let mut queue = all_dependencies
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(alias, (spec, ty))| (alias, spec, ty, None::<(PackageNames, Version)>, 0usize))
|
.map(|((spec, ty), alias)| (alias, spec, ty, None::<(PackageNames, Version)>, 0usize))
|
||||||
.collect::<VecDeque<_>>();
|
.collect::<VecDeque<_>>();
|
||||||
|
|
||||||
while let Some((alias, specifier, ty, dependant, depth)) = queue.pop_front() {
|
while let Some((alias, specifier, ty, dependant, depth)) = queue.pop_front() {
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
use crate::{manifest::DependencyType, names::PackageNames, Project};
|
|
||||||
use semver::Version;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
manifest::{DependencyType, Target, TargetKind},
|
||||||
|
names::PackageNames,
|
||||||
|
Project,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod pesde;
|
pub mod pesde;
|
||||||
|
|
||||||
pub(crate) fn hash<S: std::hash::Hash>(struc: &S) -> String {
|
pub(crate) fn hash<S: std::hash::Hash>(struc: &S) -> String {
|
||||||
|
@ -20,7 +26,7 @@ pub(crate) fn hash<S: std::hash::Hash>(struc: &S) -> String {
|
||||||
#[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 {
|
||||||
Pesde(pesde::PesdeDependencySpecifier),
|
Pesde(pesde::specifier::PesdeDependencySpecifier),
|
||||||
}
|
}
|
||||||
pub trait DependencySpecifier: Debug + Display {}
|
pub trait DependencySpecifier: Debug + Display {}
|
||||||
impl DependencySpecifier for DependencySpecifiers {}
|
impl DependencySpecifier for DependencySpecifiers {}
|
||||||
|
@ -35,10 +41,12 @@ impl Display for DependencySpecifiers {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum PackageRefs {
|
pub enum PackageRefs {
|
||||||
Pesde(pesde::PesdePackageRef),
|
Pesde(pesde::pkg_ref::PesdePackageRef),
|
||||||
}
|
}
|
||||||
pub trait PackageRef: Debug {
|
pub trait PackageRef: Debug {
|
||||||
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)>;
|
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)>;
|
||||||
|
fn use_new_structure(&self) -> bool;
|
||||||
|
fn target_kind(&self) -> TargetKind;
|
||||||
}
|
}
|
||||||
impl PackageRef for PackageRefs {
|
impl PackageRef for PackageRefs {
|
||||||
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)> {
|
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)> {
|
||||||
|
@ -46,6 +54,18 @@ impl PackageRef for PackageRefs {
|
||||||
PackageRefs::Pesde(pkg_ref) => pkg_ref.dependencies(),
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.dependencies(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn use_new_structure(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.use_new_structure(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_kind(&self) -> TargetKind {
|
||||||
|
match self {
|
||||||
|
PackageRefs::Pesde(pkg_ref) => pkg_ref.target_kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ResolveResult<Ref> = (PackageNames, BTreeMap<Version, Ref>);
|
pub type ResolveResult<Ref> = (PackageNames, BTreeMap<Version, Ref>);
|
||||||
|
@ -76,7 +96,7 @@ pub trait PackageSource: Debug {
|
||||||
pkg_ref: &Self::Ref,
|
pkg_ref: &Self::Ref,
|
||||||
destination: &Path,
|
destination: &Path,
|
||||||
project: &Project,
|
project: &Project,
|
||||||
) -> Result<(), Self::DownloadError>;
|
) -> Result<Target, Self::DownloadError>;
|
||||||
}
|
}
|
||||||
impl PackageSource for PackageSources {
|
impl PackageSource for PackageSources {
|
||||||
type Ref = PackageRefs;
|
type Ref = PackageRefs;
|
||||||
|
@ -119,7 +139,7 @@ impl PackageSource for PackageSources {
|
||||||
pkg_ref: &Self::Ref,
|
pkg_ref: &Self::Ref,
|
||||||
destination: &Path,
|
destination: &Path,
|
||||||
project: &Project,
|
project: &Project,
|
||||||
) -> Result<(), Self::DownloadError> {
|
) -> Result<Target, Self::DownloadError> {
|
||||||
match (self, pkg_ref) {
|
match (self, pkg_ref) {
|
||||||
(PackageSources::Pesde(source), PackageRefs::Pesde(pkg_ref)) => source
|
(PackageSources::Pesde(source), PackageRefs::Pesde(pkg_ref)) => source
|
||||||
.download(pkg_ref, destination, project)
|
.download(pkg_ref, destination, project)
|
||||||
|
|
|
@ -1,63 +1,22 @@
|
||||||
use std::{
|
use std::{collections::BTreeMap, fmt::Debug, hash::Hash, path::Path};
|
||||||
collections::BTreeMap,
|
|
||||||
fmt::{Debug, Display},
|
|
||||||
hash::Hash,
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use gix::remote::Direction;
|
use gix::remote::Direction;
|
||||||
use semver::{Version, VersionReq};
|
use semver::Version;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use pkg_ref::PesdePackageRef;
|
||||||
|
use specifier::PesdeDependencySpecifier;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
authenticate_conn,
|
authenticate_conn,
|
||||||
manifest::{DependencyType, TargetKind},
|
manifest::{DependencyType, Target},
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
source::{
|
source::{hash, DependencySpecifiers, PackageSource, ResolveResult},
|
||||||
hash, DependencySpecifier, DependencySpecifiers, PackageRef, PackageSource, ResolveResult,
|
|
||||||
},
|
|
||||||
Project, REQWEST_CLIENT,
|
Project, REQWEST_CLIENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
pub mod pkg_ref;
|
||||||
pub struct PesdeDependencySpecifier {
|
pub mod specifier;
|
||||||
pub name: PackageName,
|
|
||||||
pub version: VersionReq,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub index: Option<String>,
|
|
||||||
}
|
|
||||||
impl DependencySpecifier for PesdeDependencySpecifier {}
|
|
||||||
|
|
||||||
impl Display for PesdeDependencySpecifier {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}@{}", self.name, self.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
|
||||||
pub struct PesdePackageRef {
|
|
||||||
name: PackageName,
|
|
||||||
version: Version,
|
|
||||||
index_url: gix::Url,
|
|
||||||
dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,
|
|
||||||
}
|
|
||||||
impl PackageRef for PesdePackageRef {
|
|
||||||
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)> {
|
|
||||||
&self.dependencies
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for PesdePackageRef {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.version.cmp(&other.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for PesdePackageRef {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
pub struct PesdePackageSource {
|
pub struct PesdePackageSource {
|
||||||
|
@ -359,6 +318,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
version: entry.version,
|
version: entry.version,
|
||||||
index_url: self.repo_url.clone(),
|
index_url: self.repo_url.clone(),
|
||||||
dependencies: entry.dependencies,
|
dependencies: entry.dependencies,
|
||||||
|
target: entry.target,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -371,7 +331,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
pkg_ref: &Self::Ref,
|
pkg_ref: &Self::Ref,
|
||||||
destination: &Path,
|
destination: &Path,
|
||||||
project: &Project,
|
project: &Project,
|
||||||
) -> Result<(), Self::DownloadError> {
|
) -> Result<Target, Self::DownloadError> {
|
||||||
let config = self.config(project)?;
|
let config = self.config(project)?;
|
||||||
|
|
||||||
let (scope, name) = pkg_ref.name.as_str();
|
let (scope, name) = pkg_ref.name.as_str();
|
||||||
|
@ -397,7 +357,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
|
|
||||||
archive.unpack(destination)?;
|
archive.unpack(destination)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(pkg_ref.target.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,7 +392,7 @@ impl IndexConfig {
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct IndexFileEntry {
|
pub struct IndexFileEntry {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub target: TargetKind,
|
pub target: Target,
|
||||||
#[serde(default = "chrono::Utc::now")]
|
#[serde(default = "chrono::Utc::now")]
|
||||||
pub published_at: chrono::DateTime<chrono::Utc>,
|
pub published_at: chrono::DateTime<chrono::Utc>,
|
||||||
|
|
44
src/source/pesde/pkg_ref.rs
Normal file
44
src/source/pesde/pkg_ref.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
manifest::{DependencyType, Target, TargetKind},
|
||||||
|
names::PackageName,
|
||||||
|
source::{DependencySpecifiers, PackageRef},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||||
|
pub struct PesdePackageRef {
|
||||||
|
pub name: PackageName,
|
||||||
|
pub version: Version,
|
||||||
|
pub index_url: gix::Url,
|
||||||
|
pub dependencies: BTreeMap<String, (DependencySpecifiers, DependencyType)>,
|
||||||
|
pub target: Target,
|
||||||
|
}
|
||||||
|
impl PackageRef for PesdePackageRef {
|
||||||
|
fn dependencies(&self) -> &BTreeMap<String, (DependencySpecifiers, DependencyType)> {
|
||||||
|
&self.dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_new_structure(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_kind(&self) -> TargetKind {
|
||||||
|
self.target.kind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for PesdePackageRef {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.version.cmp(&other.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for PesdePackageRef {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
19
src/source/pesde/specifier.rs
Normal file
19
src/source/pesde/specifier.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use crate::{names::PackageName, source::DependencySpecifier};
|
||||||
|
use semver::VersionReq;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PesdeDependencySpecifier {
|
||||||
|
pub name: PackageName,
|
||||||
|
pub version: VersionReq,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub index: Option<String>,
|
||||||
|
}
|
||||||
|
impl DependencySpecifier for PesdeDependencySpecifier {}
|
||||||
|
|
||||||
|
impl Display for PesdeDependencySpecifier {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}@{}", self.name, self.version)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue