diff --git a/core/src/ten_manager/src/cmd/cmd_install.rs b/core/src/ten_manager/src/cmd/cmd_install.rs index d5e22c56f0..3e84c28896 100644 --- a/core/src/ten_manager/src/cmd/cmd_install.rs +++ b/core/src/ten_manager/src/cmd/cmd_install.rs @@ -21,7 +21,7 @@ use inquire::Confirm; use semver::VersionReq; use ten_rust::pkg_info::{ - dependencies::{DependencyRelationship, PkgDependency}, + dependencies::PkgDependency, find_to_be_replaced_local_pkgs, find_untracked_local_packages, get_pkg_info_from_path, pkg_type::PkgType, @@ -47,7 +47,7 @@ use crate::{ package_info::tman_get_all_existed_pkgs_info_of_app, solver::{ introducer::extract_introducer_relations_from_raw_solver_results, - solve::solve_all, + solve::{solve_all, DependencyRelationship}, solver_error::{parse_error_statement, print_conflict_info}, solver_result::{ extract_solver_results_from_raw_solver_results, @@ -292,16 +292,20 @@ fn write_pkgs_into_lock(pkgs: &Vec<&PkgInfo>, app_dir: &Path) -> Result<()> { fn parse_pkg_name_version( pkg_name_version: &str, -) -> Result<(String, Option, VersionReq)> { +) -> Result<(String, String, VersionReq)> { let parts: Vec<&str> = pkg_name_version.split('@').collect(); if parts.len() == 2 { Ok(( parts[0].to_string(), - Some(parts[1].to_string()), + parts[1].to_string(), VersionReq::parse(parts[1])?, )) } else { - Ok((pkg_name_version.to_string(), None, VersionReq::STAR)) + Ok(( + pkg_name_version.to_string(), + VersionReq::STAR.to_string(), + VersionReq::STAR, + )) } } @@ -584,12 +588,16 @@ pub async fn execute_cmd( ); let extra_dependency_relationship = DependencyRelationship { - pkg_type: app_pkg_.basic_info.type_and_name.pkg_type, - name: app_pkg_.basic_info.type_and_name.name.clone(), + type_and_name: PkgTypeAndName { + pkg_type: app_pkg_.basic_info.type_and_name.pkg_type, + name: app_pkg_.basic_info.type_and_name.name.clone(), + }, version: app_pkg_.basic_info.version.clone(), dependency: PkgDependency { - pkg_type: desired_pkg_type_, - name: desired_pkg_src_name_.clone(), + type_and_name: PkgTypeAndName { + pkg_type: desired_pkg_type_, + name: desired_pkg_src_name_.clone(), + }, version_req: desired_pkg_src_version_.clone(), version_req_str: desired_pkg_src_version_str_, }, diff --git a/core/src/ten_manager/src/dep_and_candidate/mod.rs b/core/src/ten_manager/src/dep_and_candidate/mod.rs index 0c1b3e7b3c..827bb4d7bb 100644 --- a/core/src/ten_manager/src/dep_and_candidate/mod.rs +++ b/core/src/ten_manager/src/dep_and_candidate/mod.rs @@ -5,7 +5,6 @@ // Refer to the "LICENSE" file in the root directory for more information. // use std::collections::{HashMap, HashSet}; -use std::hash::{Hash, Hasher}; use anyhow::{anyhow, Result}; use semver::{Version, VersionReq}; @@ -52,62 +51,35 @@ impl MergedVersionReq { } } -struct FoundDependency { - pkg_type: PkgType, - name: String, - version_reqs: MergedVersionReq, -} - -impl Hash for FoundDependency { - fn hash(&self, state: &mut H) { - self.pkg_type.hash(state); - self.name.hash(state); - } -} - -impl PartialEq for FoundDependency { - fn eq(&self, other: &Self) -> bool { - self.pkg_type == other.pkg_type && self.name == other.name - } -} - -impl Eq for FoundDependency {} - /// If the contents of merged_dependencies are the same before and after the /// merge, it means merged_dependencies has not changed, so return false. /// Otherwise, it means there has been a change, so return true. This allows the /// caller to know that there may be new content and that some actions may need /// to be taken. fn merge_dependency_to_dependencies( - merged_dependencies: &mut HashSet, + merged_dependencies: &mut HashMap, dependency: &PkgDependency, ) -> Result { - let searched_target = FoundDependency { - pkg_type: dependency.pkg_type, - name: dependency.name.clone(), - version_reqs: MergedVersionReq::default(), + let searched_target = PkgTypeAndName { + pkg_type: dependency.type_and_name.pkg_type, + name: dependency.type_and_name.name.clone(), }; let mut changed = true; - // Note that FoundDependency will only use pkg_identity as the hash key. - if let Some(mut existed_dependency) = - merged_dependencies.take(&searched_target) + if let Some(existed_dependency) = + merged_dependencies.get_mut(&searched_target) { - changed = existed_dependency - .version_reqs - .merge(&dependency.version_req)?; - - // Put back. - merged_dependencies.insert(existed_dependency); + changed = existed_dependency.merge(&dependency.version_req)?; } else { // This is the first time seeing this dependency. - - merged_dependencies.insert(FoundDependency { - pkg_type: dependency.pkg_type, - name: dependency.name.clone(), - version_reqs: MergedVersionReq::new(&dependency.version_req), - }); + merged_dependencies.insert( + PkgTypeAndName { + pkg_type: dependency.type_and_name.pkg_type, + name: dependency.type_and_name.name.clone(), + }, + MergedVersionReq::new(&dependency.version_req), + ); } Ok(changed) @@ -133,7 +105,7 @@ async fn process_dependencies_to_get_candidates( tman_config: &TmanConfig, support: &PkgSupport, input_dependencies: &Vec, - merged_dependencies: &mut HashSet, + merged_dependencies: &mut HashMap, all_candidates: &mut HashMap< PkgTypeAndName, HashMap, @@ -162,8 +134,8 @@ async fn process_dependencies_to_get_candidates( // criteria. let results = get_package_list( tman_config, - dependency.pkg_type, - &dependency.name, + dependency.type_and_name.pkg_type, + &dependency.type_and_name.name, &criteria, ) .await?; @@ -310,7 +282,7 @@ pub async fn get_all_candidates_from_deps( extra_dependencies: &Vec, locked_pkgs: Option<&HashMap>, ) -> Result>> { - let mut merged_dependencies = HashSet::::new(); + let mut merged_dependencies = HashMap::new(); let mut processed_pkgs = HashSet::::new(); // If there is extra dependencies (ex: specified in the command line), diff --git a/core/src/ten_manager/src/manifest_lock/mod.rs b/core/src/ten_manager/src/manifest_lock/mod.rs index 4ceab57188..185837762f 100644 --- a/core/src/ten_manager/src/manifest_lock/mod.rs +++ b/core/src/ten_manager/src/manifest_lock/mod.rs @@ -274,10 +274,13 @@ impl<'a> From<&'a ManifestLockItem> for PkgInfo { .map(|deps| { deps.into_iter() .map(|dep| PkgDependency { - pkg_type: PkgType::from_str(&dep.pkg_type).unwrap(), - name: dep.name, + type_and_name: PkgTypeAndName { + pkg_type: PkgType::from_str(&dep.pkg_type) + .unwrap(), + name: dep.name, + }, version_req: VersionReq::STAR, - version_req_str: None, + version_req_str: VersionReq::STAR.to_string(), }) .collect() }) @@ -305,8 +308,8 @@ pub struct ManifestLockItemDependencyItem { impl From for ManifestLockItemDependencyItem { fn from(pkg_dep: PkgDependency) -> Self { ManifestLockItemDependencyItem { - pkg_type: pkg_dep.pkg_type.to_string(), - name: pkg_dep.name, + pkg_type: pkg_dep.type_and_name.pkg_type.to_string(), + name: pkg_dep.type_and_name.name, } } } diff --git a/core/src/ten_manager/src/solver/introducer.rs b/core/src/ten_manager/src/solver/introducer.rs index 5a9254adfd..c9cc688ba9 100644 --- a/core/src/ten_manager/src/solver/introducer.rs +++ b/core/src/ten_manager/src/solver/introducer.rs @@ -68,11 +68,8 @@ pub fn extract_introducer_relations_from_raw_solver_results( { // The `version` declared in the `dependencies` section in // manifest.json is always present. - requested_version_str = requested_dep_in_introducer - .version_req_str - .as_ref() - .unwrap() - .clone(); + requested_version_str = + requested_dep_in_introducer.version_req_str.clone(); } else { return Err(anyhow::anyhow!( "Requested dependency [{}]{} not found in introducer, should not happen.", pkg_type_str, name @@ -110,11 +107,7 @@ pub fn get_dependency_chain( ) .unwrap(); chain.push(( - requested_dep_in_introducer - .version_req_str - .as_ref() - .unwrap() - .clone(), + requested_dep_in_introducer.version_req_str.clone(), conflict_pkg_identity.clone(), )); diff --git a/core/src/ten_manager/src/solver/solve.rs b/core/src/ten_manager/src/solver/solve.rs index b047fac771..4574e8c3e5 100644 --- a/core/src/ten_manager/src/solver/solve.rs +++ b/core/src/ten_manager/src/solver/solve.rs @@ -12,8 +12,9 @@ use clingo::{ SolveMode, Statistics, StatisticsType, }; +use semver::Version; use ten_rust::pkg_info::{ - dependencies::DependencyRelationship, pkg_basic_info::PkgBasicInfo, + dependencies::PkgDependency, pkg_basic_info::PkgBasicInfo, pkg_type::PkgType, pkg_type_and_name::PkgTypeAndName, PkgInfo, }; @@ -23,6 +24,13 @@ use crate::{ log::{tman_verbose_print, tman_verbose_println}, }; +#[derive(Debug)] +pub struct DependencyRelationship { + pub type_and_name: PkgTypeAndName, + pub version: Version, + pub dependency: PkgDependency, +} + fn get_model( tman_config: &TmanConfig, model: &Model, @@ -309,8 +317,8 @@ fn create_input_str_for_dependency_relationship( { input_str.push_str(&format!( "depends_on_declared(\"{}\", \"{}\", \"{}\", \"{}\", \"{}\", \"{}\").\n", - dependency_relationship.pkg_type, - dependency_relationship.name, + dependency_relationship.type_and_name.pkg_type, + dependency_relationship.type_and_name.name, dependency_relationship.version, candidate.1.basic_info.type_and_name.pkg_type, candidate.1.basic_info.type_and_name.name, @@ -322,8 +330,8 @@ fn create_input_str_for_dependency_relationship( return Err(TmanError::Custom( format!( "Failed to find candidates for {}:{}@{}", - dependency_relationship.dependency.pkg_type, - dependency_relationship.dependency.name, + dependency_relationship.dependency.type_and_name.pkg_type, + dependency_relationship.dependency.type_and_name.name, dependency_relationship.version, ) .to_string(), @@ -383,8 +391,8 @@ fn create_input_str_for_pkg_info_dependencies( return Err(TmanError::Custom( format!( "Failed to find candidates for [{}]{}({})", - dependency.pkg_type, - dependency.name, + dependency.type_and_name.pkg_type, + dependency.type_and_name.name, dependency.version_req ) .to_string(), @@ -395,8 +403,8 @@ fn create_input_str_for_pkg_info_dependencies( return Err(TmanError::Custom( format!( "Failed to find candidates for {}:{}@{}", - dependency.pkg_type, - dependency.name, + dependency.type_and_name.pkg_type, + dependency.type_and_name.name, dependency.version_req ) .to_string(), diff --git a/core/src/ten_rust/src/json/bindings.rs b/core/src/ten_rust/src/json/bindings.rs index 03c29d1b04..8560e914ea 100644 --- a/core/src/ten_rust/src/json/bindings.rs +++ b/core/src/ten_rust/src/json/bindings.rs @@ -11,7 +11,7 @@ use std::ptr; use crate::json; #[no_mangle] -pub extern "C" fn ten_remove_json_comments( +pub unsafe extern "C" fn ten_remove_json_comments( json_with_comments: *const c_char, ) -> *mut c_char { if json_with_comments.is_null() { diff --git a/core/src/ten_rust/src/pkg_info/dependencies.rs b/core/src/ten_rust/src/pkg_info/dependencies.rs index 4e117eaa93..604e6b2e7d 100644 --- a/core/src/ten_rust/src/pkg_info/dependencies.rs +++ b/core/src/ten_rust/src/pkg_info/dependencies.rs @@ -4,13 +4,10 @@ // Licensed under the Apache License, Version 2.0, with certain conditions. // Refer to the "LICENSE" file in the root directory for more information. // -use std::{ - hash::{Hash, Hasher}, - str::FromStr, -}; +use std::str::FromStr; use anyhow::Result; -use semver::{Version, VersionReq}; +use semver::VersionReq; use serde::{Deserialize, Serialize}; use super::{pkg_type::PkgType, pkg_type_and_name::PkgTypeAndName}; @@ -18,8 +15,7 @@ use crate::pkg_info::manifest::{dependency::ManifestDependency, Manifest}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PkgDependency { - pub pkg_type: PkgType, - pub name: String, + pub type_and_name: PkgTypeAndName, // The version requirement of this dependency, ex: the `version` // field declared in the `dependencies` section in the manifest.json, or @@ -28,15 +24,26 @@ pub struct PkgDependency { // The `version_req_str` is the original value in string form, while // `version_req` is the result after being converted to `VersionReq`. pub version_req: VersionReq, - pub version_req_str: Option, + pub version_req_str: String, +} + +impl PkgDependency { + pub fn new( + pkg_type: PkgType, + name: String, + version_req: VersionReq, + ) -> Self { + PkgDependency { + type_and_name: PkgTypeAndName { pkg_type, name }, + version_req_str: version_req.to_string(), + version_req, + } + } } impl From<&PkgDependency> for PkgTypeAndName { fn from(dependency: &PkgDependency) -> Self { - PkgTypeAndName { - pkg_type: dependency.pkg_type, - name: dependency.name.clone(), - } + dependency.type_and_name.clone() } } @@ -45,10 +52,12 @@ impl TryFrom<&ManifestDependency> for PkgDependency { fn try_from(manifest_dep: &ManifestDependency) -> Result { Ok(PkgDependency { - pkg_type: PkgType::from_str(&manifest_dep.pkg_type)?, - name: manifest_dep.name.clone(), + type_and_name: PkgTypeAndName { + pkg_type: PkgType::from_str(&manifest_dep.pkg_type)?, + name: manifest_dep.name.clone(), + }, version_req: VersionReq::parse(&manifest_dep.version)?, - version_req_str: Some(manifest_dep.version.clone()), + version_req_str: manifest_dep.version.clone(), }) } } @@ -66,65 +75,13 @@ pub fn get_pkg_dependencies_from_manifest( } } -pub fn get_pkg_dependencies_from_manifest_dependencies( - manifest_dependencies: &Vec, +fn get_pkg_dependencies_from_manifest_dependencies( + manifest_dependencies: &[ManifestDependency], ) -> Result> { - let mut dependencies = Vec::new(); - - for manifest_dependency in manifest_dependencies { - let pkg_type = PkgType::from_str(&manifest_dependency.pkg_type)?; - let name = manifest_dependency.name.clone(); - let version_req = VersionReq::parse(&manifest_dependency.version)?; - - dependencies.push(PkgDependency { - pkg_type, - name, - version_req, - version_req_str: Some(manifest_dependency.version.clone()), - }); - } - - Ok(dependencies) -} - -/// The hash function of `Dependency`. A unique dependency is identified by its -/// type and name. -impl Hash for PkgDependency { - fn hash(&self, state: &mut H) { - self.pkg_type.hash(state); - self.name.hash(state); - } -} - -impl PartialEq for PkgDependency { - fn eq(&self, other: &Self) -> bool { - self.pkg_type == other.pkg_type && self.name == other.name - } -} - -impl PkgDependency { - pub fn new( - pkg_type: PkgType, - name: String, - version_req: VersionReq, - ) -> Self { - PkgDependency { - pkg_type, - name, - version_req, - version_req_str: None, - } - } -} - -impl Eq for PkgDependency {} - -#[derive(Debug)] -pub struct DependencyRelationship { - pub pkg_type: PkgType, - pub name: String, - pub version: Version, - pub dependency: PkgDependency, + manifest_dependencies + .iter() + .map(PkgDependency::try_from) + .collect() } pub fn get_manifest_dependencies_from_pkg( diff --git a/core/src/ten_rust/src/pkg_info/hash.rs b/core/src/ten_rust/src/pkg_info/hash.rs index 91b3b50fb5..2694306182 100644 --- a/core/src/ten_rust/src/pkg_info/hash.rs +++ b/core/src/ten_rust/src/pkg_info/hash.rs @@ -46,8 +46,10 @@ fn gen_hash_hex( // Hash dependencies. for dep in dependencies { - let dep_string = - format!("{}:{}@{}", dep.pkg_type, dep.name, dep.version_req); + let dep_string = format!( + "{}:{}@{}", + dep.type_and_name.pkg_type, dep.type_and_name.name, dep.version_req + ); hasher.update(dep_string); } diff --git a/core/src/ten_rust/src/pkg_info/manifest/dependency.rs b/core/src/ten_rust/src/pkg_info/manifest/dependency.rs index 0330829072..378d833141 100644 --- a/core/src/ten_rust/src/pkg_info/manifest/dependency.rs +++ b/core/src/ten_rust/src/pkg_info/manifest/dependency.rs @@ -19,8 +19,8 @@ pub struct ManifestDependency { impl From<&PkgDependency> for ManifestDependency { fn from(pkg_dependency: &PkgDependency) -> Self { ManifestDependency { - pkg_type: pkg_dependency.pkg_type.to_string(), - name: pkg_dependency.name.clone(), + pkg_type: pkg_dependency.type_and_name.pkg_type.to_string(), + name: pkg_dependency.type_and_name.name.clone(), version: pkg_dependency.version_req.to_string(), } } diff --git a/core/src/ten_rust/src/pkg_info/mod.rs b/core/src/ten_rust/src/pkg_info/mod.rs index 822b2426e1..1a43d7d644 100644 --- a/core/src/ten_rust/src/pkg_info/mod.rs +++ b/core/src/ten_rust/src/pkg_info/mod.rs @@ -174,7 +174,8 @@ impl PkgInfo { pkg_name: &str, ) -> Option<&PkgDependency> { self.dependencies.iter().find(|dep| { - dep.pkg_type.to_string() == pkg_type && dep.name == pkg_name + dep.type_and_name.pkg_type.to_string() == pkg_type + && dep.type_and_name.name == pkg_name }) } } diff --git a/core/src/ten_rust/src/pkg_info/pkg_basic_info.rs b/core/src/ten_rust/src/pkg_info/pkg_basic_info.rs index e06abf80a6..ed9915ef59 100644 --- a/core/src/ten_rust/src/pkg_info/pkg_basic_info.rs +++ b/core/src/ten_rust/src/pkg_info/pkg_basic_info.rs @@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize}; use super::{ manifest::Manifest, pkg_type_and_name::PkgTypeAndName, - supports::{get_pkg_supports_from_manifest, PkgSupport}, + supports::{get_pkg_supports_from_manifest_supports, PkgSupport}, PkgInfo, }; @@ -41,8 +41,7 @@ pub struct PkgBasicInfo { impl Hash for PkgBasicInfo { fn hash(&self, state: &mut H) { - self.type_and_name.pkg_type.hash(state); - self.type_and_name.name.hash(state); + self.type_and_name.hash(state); self.version.hash(state); self.supports.hash(state); } @@ -105,7 +104,9 @@ impl TryFrom<&Manifest> for PkgBasicInfo { Ok(PkgBasicInfo { type_and_name: PkgTypeAndName::try_from(manifest)?, version: Version::parse(&manifest.version)?, - supports: get_pkg_supports_from_manifest(manifest)?, + supports: get_pkg_supports_from_manifest_supports( + &manifest.supports, + )?, }) } } diff --git a/core/src/ten_rust/src/pkg_info/supports.rs b/core/src/ten_rust/src/pkg_info/supports.rs index 2a00bca3fa..8b090639d1 100644 --- a/core/src/ten_rust/src/pkg_info/supports.rs +++ b/core/src/ten_rust/src/pkg_info/supports.rs @@ -7,10 +7,10 @@ use std::hash::Hash; use std::{fmt, str::FromStr}; -use anyhow::{anyhow, Error, Result}; +use anyhow::{anyhow, Context, Error, Result}; use serde::{Deserialize, Serialize}; -use crate::pkg_info::manifest::{support::ManifestSupport, Manifest}; +use crate::pkg_info::manifest::support::ManifestSupport; #[derive( Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, @@ -41,14 +41,24 @@ impl fmt::Display for PkgSupport { } } -impl From for PkgSupport { - fn from(manifest_support: ManifestSupport) -> Self { - PkgSupport { - os: manifest_support.os.map(|os| Os::from_str(&os).unwrap()), +impl TryFrom<&ManifestSupport> for PkgSupport { + type Error = anyhow::Error; + + fn try_from(manifest_support: &ManifestSupport) -> Result { + Ok(PkgSupport { + os: manifest_support + .os + .as_deref() + .map(Os::from_str) + .transpose() + .context("Failed to parse OS from manifest")?, arch: manifest_support .arch - .map(|arch| Arch::from_str(&arch).unwrap()), - } + .as_deref() + .map(Arch::from_str) + .transpose() + .context("Failed to parse Arch from manifest")?, + }) } } @@ -107,24 +117,25 @@ impl PkgSupport { } } -pub fn get_pkg_supports_from_manifest( - manifest: &Manifest, -) -> Result> { - get_pkg_supports_from_manifest_supports(&manifest.supports) -} - pub fn get_pkg_supports_from_manifest_supports( manifest_supports: &Option>, ) -> Result> { if let Some(supports) = &manifest_supports { - let pkg_supports: Vec = - supports.iter().cloned().map(PkgSupport::from).collect(); - Ok(pkg_supports) + Ok(supports + .iter() + .map(PkgSupport::try_from) + .collect::>>()?) } else { Ok(vec![]) } } +pub fn get_manifest_supports_from_pkg( + support: &[PkgSupport], +) -> Vec { + support.iter().map(|v| v.into()).collect() +} + pub fn is_pkg_supports_compatible_with( pkg_supports: &Vec, pivot: &PkgSupport, @@ -227,9 +238,3 @@ impl fmt::Display for Arch { } } } - -pub fn get_manifest_supports_from_pkg( - support: &[PkgSupport], -) -> Vec { - support.iter().map(|v| v.into()).collect() -}