From 1ad74edae38d493d86acc253ad482a625438cae4 Mon Sep 17 00:00:00 2001 From: tanneberger Date: Fri, 31 May 2024 16:55:14 +0200 Subject: [PATCH] aggregating of cmake files --- src/backends/lfc.rs | 6 +- src/backends/mod.rs | 3 +- src/package/lock.rs | 79 ++++++++++++++++--- src/package/management.rs | 18 +++-- src/package/mod.rs | 39 ++++------ src/package/target_properties.rs | 128 +++++++++++++++---------------- 6 files changed, 159 insertions(+), 114 deletions(-) diff --git a/src/backends/lfc.rs b/src/backends/lfc.rs index b4213a5..27f7a8a 100644 --- a/src/backends/lfc.rs +++ b/src/backends/lfc.rs @@ -75,11 +75,7 @@ struct LfcJsonArgs<'a> { impl<'a> LfcJsonArgs<'a> { pub fn new(app: &'a App, compile_target_code: bool) -> Self { let mut hash_map: HashMap<&str, serde_json::Value> = HashMap::new(); - - app.properties.fast.map(|value| { - hash_map.insert("fast", serde_json::Value::Bool(value)); - }); - + hash_map.insert("fast", serde_json::Value::Bool(app.properties.fast)); Self { src: &app.main_reactor, diff --git a/src/backends/mod.rs b/src/backends/mod.rs index 638fe71..a56f5c0 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -31,9 +31,10 @@ pub fn execute_command<'a>(command: &CommandSpec, config: &'a Config) -> BatchBu match command { CommandSpec::Build(build) => { + println!("found {} libraries ... cloning", dependencies.len()); let manager = DependencyManager::from_dependencies( dependencies.clone(), - &PathBuf::new(), + &PathBuf::from("./target"), ); } diff --git a/src/package/lock.rs b/src/package/lock.rs index 5d71a6a..fb4f385 100644 --- a/src/package/lock.rs +++ b/src/package/lock.rs @@ -1,7 +1,13 @@ use crate::package::management::{copy_dir_all, LocationDescription}; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; -use std::path::PathBuf; +use std::fs; +use std::path::{Path, PathBuf}; +use std::thread::sleep; +use colored::Colorize; +use crate::package::ConfigFile; +use crate::package::target_properties::{LibraryTargetProperties, MergeTargetProperties}; +use crate::package::tree::{DependencyTreeNode, PackageDetails, ProjectSource}; #[derive(Deserialize, Serialize)] @@ -12,30 +18,83 @@ pub struct LockedResource { #[derive(Deserialize, Serialize)] pub struct DependencyLock { - dependencies: HashMap, + package_locations: HashMap, + + #[serde(skip)] + loaded_dependencies: Vec } impl DependencyLock { pub fn new() -> DependencyLock { Self { - dependencies: HashMap::new(), + package_locations: HashMap::new(), + loaded_dependencies: Vec::new() } } - pub fn from(dependencies: HashMap) -> DependencyLock { - Self { dependencies } + pub fn from(mut unlocked_locations: HashMap, loaded_dependencies: Vec) -> DependencyLock { + let mut package_locations = HashMap::new(); + for package in &loaded_dependencies { + let location = unlocked_locations.get_mut(&package.name).expect("cannot find package"); + + package_locations.insert(package.name.clone(), LockedResource { + location: location.clone(), + hash: package.hash.clone(), + }); + } + + Self { package_locations, loaded_dependencies } + } + + pub fn init(&mut self, lfc_include_folder: &Path) -> anyhow::Result<()> { + for lock in self.package_locations.iter() { + let temp = lfc_include_folder.clone().join(lock.0); + + print!("{} reading ... {}", lock.0.to_string().green().bold(), &temp.display()); + + let lingo_toml_text = fs::read_to_string(&temp.join("Lingo.toml")).expect("cannot read toml"); + let read_toml = toml::from_str::(&lingo_toml_text).expect("cannot parse toml").to_config(&temp); + + self.loaded_dependencies.push(DependencyTreeNode { + name: read_toml.package.name, + version: read_toml.package.version, + package: PackageDetails { + version: Default::default(), + mutual_exclusive: ProjectSource::Empty, + }, + location: temp, + hash: "".parse()?, + dependencies: vec![], + properties: read_toml.library.unwrap().properties + }) + } + + Ok(()) } - pub fn create_library_folder(&self, target_path: &PathBuf) -> anyhow::Result<()> { + pub fn create_library_folder(&self, source_path: &PathBuf, target_path: &PathBuf) -> anyhow::Result<()> { std::fs::create_dir_all(target_path)?; - for (name, lock) in self.dependencies.iter() { - //let local_source = lock.local.clone(); - //let find_source = target_path.clone().join(name); + for (name, lock) in self.package_locations.iter() { + let local_source = source_path.clone().join(lock.hash.clone()); + let find_source = target_path.clone().join(name); - //copy_dir_all(&local_source, &find_source)?; + println!("copying {} -> {}", &local_source.display(), &find_source.display()); + std::fs::create_dir_all(&find_source)?; + copy_dir_all(&local_source, &find_source)?; } Ok(()) } + + + pub fn aggregate_target_properties(&self) -> anyhow::Result { + let mut i = LibraryTargetProperties::default(); + + for tp in &self.loaded_dependencies { + i.merge(&tp.properties)?; + } + + return Ok(i); + } } diff --git a/src/package/management.rs b/src/package/management.rs index 3c623ba..020b5d8 100644 --- a/src/package/management.rs +++ b/src/package/management.rs @@ -91,10 +91,13 @@ impl DependencyManager { let mut manager; let mut lock: DependencyLock; - let lock_file = Path::new("../Lingo.lock"); + let lock_file = target_path.clone().join("../Lingo.lock"); if lock_file.exists() { - lock = serde_json::from_str::(&std::fs::read_to_string(lock_file)?)?; + println!("Found Lingo.lock skipping pulling"); + lock = serde_json::from_str::(&std::fs::read_to_string(lock_file).expect("cannot read lock file")).expect("cannot parse lock file"); + println!("reading lfc_include folder ..."); + lock.init(&target_path.clone().join("lfc_include")).expect("init failed"); } else { manager = DependencyManager::new(); @@ -103,15 +106,18 @@ impl DependencyManager { let selection = DependencyManager::flatten(root_nodes.clone())?; - lock = DependencyLock::from(selection); + lock = DependencyLock::from(selection, root_nodes); let mut lock_file = File::create(target_path.join("../Lingo.lock"))?; let serialized_json = serde_json::to_string_pretty(&lock)?; lock_file.write(serialized_json.as_ref())?; + + let include_folder = target_path.clone().join("lfc_include"); + lock.create_library_folder(&library_path, &include_folder).expect("creating lock folder failed"); } - let include_folder = target_path.clone().join("lfc_include"); - lock.create_library_folder(&include_folder)?; + let result = lock.aggregate_target_properties().expect("aggregation failed"); + println!("cmake: {}", &result.cmake_include); Ok(DependencyManager::new()) } @@ -304,6 +310,4 @@ impl DependencyManager { Ok(selection) } - //pub fn forward_target_properties(&self, app_target_properties: &mut AppTargetProperties) -> anyhow::Result<()> { - //} } diff --git a/src/package/mod.rs b/src/package/mod.rs index c98c506..39a37c7 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -25,12 +25,12 @@ use versions::Versioning; use crate::package::tree::PackageDetails; use which::which; -use crate::package::target_properties::{AppTargetProperties, CMakeLoadDeserializer, CMakeLoaderImpl, LibraryTargetProperties}; +use crate::package::target_properties::{AppTargetProperties, AppTargetPropertiesFile, LibraryTargetProperties, LibraryTargetPropertiesFile}; /// place where are the build artifacts will be dropped const OUTPUT_DIRECTORY: &str = "target"; // name of the folder inside the `OUTPUT_DIRECTORY` where libraries will be copied into -const LIBRARY_DIRECTORY: &str = "library"; +const LIBRARY_DIRECTORY: &str = "libraries"; fn is_valid_location_for_project(path: &std::path::Path) -> bool { !path.join("src").exists() && !path.join(".git").exists() && !path.join("application").exists() @@ -62,7 +62,7 @@ pub struct ConfigFile { pub dependencies: HashMap, } -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone)] pub struct Config { /// top level package description pub package: PackageDescription, @@ -71,11 +71,9 @@ pub struct Config { // pub properties: HashMap, /// list of apps defined inside this package - #[serde(rename = "app")] pub apps: Vec, /// library exported by this package - #[serde(rename = "lib")] pub library: Option, /// Dependencies for required to build this Lingua-Franca Project @@ -98,10 +96,10 @@ pub struct LibraryFile { pub platform: Option, /// target properties of that lingua-franca app - pub properties: LibraryTargetProperties + pub properties: LibraryTargetPropertiesFile } -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone)] pub struct Library { /// if not specified will default to value specified in the package description pub name: String, @@ -138,10 +136,10 @@ pub struct AppFile { pub platform: Option, /// target properties of that lingua-franca app - pub properties: AppTargetProperties + pub properties: AppTargetPropertiesFile } -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone)] pub struct App { /// Absolute path to the directory where the Lingo.toml file is located. pub root_path: PathBuf, @@ -188,7 +186,7 @@ impl AppFile { }, target: self.target, platform: self.platform.unwrap_or(Platform::Native), - properties: self.properties, + properties: self.properties.from(path), } } } @@ -221,7 +219,7 @@ impl LibraryFile { }, target: self.target, platform: self.platform.unwrap_or(Platform::Native), - properties: self.properties, + properties: self.properties.from(path), output_root: path.join(OUTPUT_DIRECTORY), } } @@ -368,21 +366,10 @@ impl ConfigFile { } pub fn from(path: &Path) -> io::Result { - let content = read_to_string(path)?; - - let loader = CMakeLoadDeserializer { - asset_loader: &mut CMakeLoaderImpl { - lib_path: PathBuf::from(path) - } - }; - - - let mut deserializer = toml::Deserializer::new(&content); - let scene = loader.deserialize(&mut deserializer) - .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("{}", e)))?; - - return - + read_to_string(path).and_then(|contents| { + toml::from_str(&contents) + .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("{}", e))) + }) } // Sets up a standard LF project for "native" development and deployment diff --git a/src/package/target_properties.rs b/src/package/target_properties.rs index ee5394b..889c2f9 100644 --- a/src/package/target_properties.rs +++ b/src/package/target_properties.rs @@ -1,71 +1,16 @@ use std::fmt; +use std::fmt::{Display, Formatter}; use std::io::Write; use std::path::{Path, PathBuf}; use serde::de::{DeserializeSeed, Error, Visitor}; use serde::{Deserializer, Serialize, Serializer, Deserialize}; +use serde::de::Unexpected::Str; pub trait CMakeLoader { fn read_file(&mut self, path: &String) -> anyhow::Result; } -pub struct CMakeLoaderImpl { - pub(crate) lib_path: PathBuf -} - -impl CMakeLoader for CMakeLoaderImpl { - fn read_file(&mut self, path: &String) -> anyhow::Result { - if path != "" { - let cmake_path = self.lib_path.join(PathBuf::from(path)); - println!("current: {}, reading: {}", std::env::current_dir().unwrap().display(), &path); - let content = std::fs::read_to_string(cmake_path)?; - Ok(AutoCmakeLoad(content)) - } else { - Ok(AutoCmakeLoad::default()) - } - } -} -pub struct CMakeLoadDeserializer<'a, L> { - pub(crate) asset_loader: &'a mut L, -} - -impl<'de, L> DeserializeSeed<'de> for CMakeLoadDeserializer<'_, L> - where - L: CMakeLoader, -{ - type Value = AutoCmakeLoad; - - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct FileFetchVisitor<'a, L> { - asset_loader: &'a mut L, - } - - impl<'de, L: CMakeLoader> Visitor<'de> for FileFetchVisitor<'_, L> { - type Value = AutoCmakeLoad; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("cannot read file or is not invalid path") - } - - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - let cmake_content = self.asset_loader.read_file(&v.to_string()).map_err(|e| E::custom("path cannot be read"))?; - - Ok(cmake_content) - } - } - - deserializer.deserialize_string(FileFetchVisitor { - asset_loader: self.asset_loader, - }) - } -} - impl Serialize for AutoCmakeLoad { fn serialize(&self, serializer: S) -> Result where @@ -75,18 +20,31 @@ impl Serialize for AutoCmakeLoad { } } +impl Display for AutoCmakeLoad { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} + #[derive(Serialize, Deserialize, Clone)] +pub enum GenericTargetPropertiesFile { + Library(LibraryTargetPropertiesFile), + App(AppTargetPropertiesFile) +} + + +#[derive(Clone)] pub enum GenericTargetProperties { Library(LibraryTargetProperties), App(AppTargetProperties) } #[derive(Clone)] -struct AutoCmakeLoad(String); +pub struct AutoCmakeLoad(String); impl Default for AutoCmakeLoad { fn default() -> Self { - Self("".to_string()) + Self(String::default()) } } @@ -98,23 +56,63 @@ impl MergeTargetProperty for AutoCmakeLoad { } #[derive(Serialize, Deserialize, Clone)] -pub struct LibraryTargetProperties { +pub struct LibraryTargetPropertiesFile { /// cmake include only available for C and CPP #[serde(rename="cmake-include", default)] - cmake_include: AutoCmakeLoad, + cmake_include: Option, } +#[derive(Clone)] +pub struct LibraryTargetProperties { + /// cmake include only available for C and CPP + pub cmake_include: AutoCmakeLoad, +} -#[derive(Serialize, Deserialize, Clone)] -pub struct AppTargetProperties { +impl LibraryTargetPropertiesFile { + pub fn from(self, base_path: &Path) -> LibraryTargetProperties { + LibraryTargetProperties { + cmake_include: AutoCmakeLoad(self.cmake_include.map(|cmake_file| { + let absolute_path= base_path.join(cmake_file); + std::fs::read_to_string(&absolute_path).expect("invalid file {absolute_path}") + }).unwrap_or(String::new())), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct AppTargetPropertiesFile { /// cmake include only available for C and CPP #[serde(rename="cmake-include", default)] + cmake_include: Option, + + /// if the runtime should wait for physical time to catch up + #[serde(default)] + pub fast: bool +} + +#[derive(Clone)] +pub struct AppTargetProperties { + /// cmake include only available for C and CPP cmake_include: AutoCmakeLoad, /// if the runtime should wait for physical time to catch up - pub fast: Option + pub fast: bool } +impl AppTargetPropertiesFile { + pub fn from(self, base_path: &Path) -> AppTargetProperties { + AppTargetProperties { + cmake_include: AutoCmakeLoad(self.cmake_include.map(|cmake_file| { + let absolute_path= base_path.join(cmake_file); + std::fs::read_to_string(&absolute_path).expect("invalid file {absolute_path}") + }).unwrap_or(String::new())), + fast: self.fast, + } + } +} + + + fn merge(a: Option, b: Option, f: fn(T, T) -> anyhow::Result>) -> anyhow::Result> { match (a, b) { (Some(x), Some(y)) => f(x, y), @@ -134,7 +132,7 @@ impl Default for AppTargetProperties { fn default() -> Self { Self { cmake_include: AutoCmakeLoad::default(), - fast: None + fast: false } } }