diff --git a/Cargo.lock b/Cargo.lock index 5cddd3e..c5a1c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,9 +263,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -438,6 +438,7 @@ dependencies = [ name = "lingua-franca" version = "0.2.0" dependencies = [ + "anyhow", "clap", "crossbeam", "git2", @@ -452,6 +453,7 @@ dependencies = [ "tempfile", "termion", "toml", + "url", "which", ] @@ -526,9 +528,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pkg-config" @@ -915,13 +917,14 @@ dependencies = [ [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0aa938b..ea386b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,6 @@ termion = "2.0" git2 = "0.18" run_script = "0.10" tempfile = "3.0" +#version = { version = "3.0", features = [] } +url = { version = "2.5", features = ["serde"] } +anyhow = "1.0.75" \ No newline at end of file diff --git a/src/package/management.rs b/src/package/management.rs new file mode 100644 index 0000000..af9f9e3 --- /dev/null +++ b/src/package/management.rs @@ -0,0 +1,54 @@ +use std::path::PathBuf; +use serde_derive::{Deserialize, Serialize}; +use url::Url; +use std::path::Path; +use crate::package::version::{Version, to_version_string, from_version_string}; + +#[derive(Clone, Deserialize, Serialize)] +enum ProjectSource { + #[serde(rename="git")] + Git(Url), + #[serde(rename="tarball")] + TarBall(Url), + #[serde(rename="path")] + Path(PathBuf) +} + +/// Dependency with source and version +#[derive(Clone, Deserialize, Serialize)] +pub struct DetailedDependency { + #[serde(deserialize_with="from_version_string", serialize_with="to_version_string")] + version: Version, + #[serde(flatten)] + mutual_exclusive: ProjectSource +} + +fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + + +impl DetailedDependency { + fn fetch(&self, library_path: &PathBuf) -> anyhow::Result<()>{ + match &self.mutual_exclusive { + ProjectSource::Path(path_buf) => { + Ok(copy_dir_all(path_buf, library_path)?) + }, + ProjectSource::Git(git_url ) => { + git2::Repository::clone(git_url.as_str(), library_path)?; + Ok(()) + }, + _ => todo!("Not Supported") + } + } +} \ No newline at end of file diff --git a/src/package/mod.rs b/src/package/mod.rs index 70a55f3..946a423 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -1,3 +1,6 @@ +pub mod version; +pub mod management; + use crate::args::{BuildSystem, InitArgs, Platform, TargetLanguage}; use crate::util::{analyzer, copy_recursively}; @@ -14,7 +17,9 @@ use crate::args::BuildSystem::{CMake, LFC}; use crate::util::errors::{BuildResult, LingoError}; use git2::Repository; use tempfile::tempdir; + use which::which; +use management::DetailedDependency; fn is_valid_location_for_project(path: &std::path::Path) -> bool { !path.join("src").exists() && !path.join(".git").exists() && !path.join("application").exists() @@ -128,23 +133,6 @@ impl App { } } -/// Simple or DetailedDependency -#[derive(Clone, Deserialize, Serialize)] -pub enum FileDependency { - // the version string - Simple(String), - /// version string and source - Advanced(DetailedDependency), -} - -/// Dependency with source and version -#[derive(Clone, Deserialize, Serialize)] -pub struct DetailedDependency { - version: String, - git: Option, - tarball: Option, - zip: Option, -} #[derive(Deserialize, Serialize, Clone)] pub struct PackageDescription { diff --git a/src/package/version.rs b/src/package/version.rs new file mode 100644 index 0000000..a1adda1 --- /dev/null +++ b/src/package/version.rs @@ -0,0 +1,78 @@ +use std::fmt; +use std::fmt::Display; +use std::str::FromStr; +use serde::{Deserializer, Serializer}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Version { + pub major : u32, + pub minor : u32, + pub patch : u32 +} + +impl Display for Version { + fn fmt( &self, fmtr : &mut fmt::Formatter ) -> fmt::Result { + write!( fmtr, "{}.{}.{}", self.major, self.minor, self.patch ) + } +} + +impl FromStr for Version { + type Err = String; + + fn from_str( s : &str ) -> Result { + let parts : Vec> = + s.split( '.' ) + .map( | elm | elm.parse::() + .map_err( |_| elm ) ) + .collect(); + + if parts.len() != 3 { + return + Err( format!( "Invalid version format: expected 3 components, got {}." + , parts.len() ) ); + } + + for part in &parts { + match part { + &Err( err ) => + return + Err( format!( "Invalid version format: expected integer, got '{}'." + , err ) ), + _ => {} + } + } + + Ok( Version { + major: parts[0].unwrap(), + minor: parts[1].unwrap(), + patch: parts[2].unwrap() + } ) + } +} + +pub(crate) fn from_version_string<'de, D: Deserializer<'de>>(d: D) -> Result { + struct VersionVisitor; + + impl<'de> serde::de::Visitor<'de> for VersionVisitor { + type Value = Version; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "cannot parse version") + } + + fn visit_str(self, s: &str) -> Result { + Ok(Version::from_str(s).map_err(|e| E::invalid_value(serde::de::Unexpected::Str(s), &self))?) + } + } + + d.deserialize_any(VersionVisitor) +} + +pub(crate) fn to_version_string(version: &Version, s: S) -> Result + where S: Serializer +{ + let serialized_string = format!("{}", version); + Ok(s.serialize_str(&serialized_string)?) +} + +