From f65a0c3182b615ca1ab52f79789b4f6868e64ab1 Mon Sep 17 00:00:00 2001 From: Jia Chao Date: Tue, 2 Jul 2024 15:51:18 +0800 Subject: [PATCH] =?UTF-8?q?auto=20=E5=8A=9F=E8=83=BD=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jia Chao --- Cargo.toml | 2 + src/config.rs | 30 ++++++++++-- src/lib.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f0bd4f7..879b2af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,5 @@ clap = { version = "4.0", features = ["derive"] } cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" } serde = { version = "1", features = ["serde_derive"] } serde_json = { version = "1.0" } +tracing = { version = "0.1" } +tracing-subscriber = { version = "0.3", features = ["env-filter", "local-time"] } diff --git a/src/config.rs b/src/config.rs index 83c8da9..93015c9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use serde::{Deserialize, Serialize}; /// cvrf2cusa 自动化执行所需的配置 @@ -11,17 +13,28 @@ pub(crate) struct AutoConfig { } impl AutoConfig { - pub fn from(path: &str) -> crate::Result { + // 从文件中读取配置 + pub fn from>(path: P) -> crate::Result { let data = std::fs::read_to_string(path)?; Ok(serde_json::from_str::(&data)?) } + + // 获取 source 字段 + pub fn source(&self) -> &str { + &self.source + } + + // 获取 target 字段 + pub fn target(&self) -> &str { + &self.target + } } /// cuvars 中,关于源码追踪,自动修复相关的配置项,一般位于组件最底层的目录,`config.json` #[derive(Clone, Debug, Deserialize, Serialize)] pub(crate) struct RepairConfig { - // 对应了 openEuelr 的上游版本 + // 对应了 openEuelr 的上游版本, 例 22.03-LST,不可包含 openEuler 字段 upstream: String, // 此组件是否支持自动修复 @@ -31,9 +44,18 @@ pub(crate) struct RepairConfig { fixed_version: String, } +#[allow(dead_code)] impl RepairConfig { + pub fn new(upstream: String, autobuild: bool, fixed_version: String) -> Self { + RepairConfig { + upstream, + autobuild, + fixed_version + } + } + /// 从指定的路径读取文件并将之转换为 `RepairConfig` - pub fn read(path: &str) -> crate::Result { + pub fn from>(path: P) -> crate::Result { let data = std::fs::read_to_string(path)?; Ok(serde_json::from_str::(&data)?) @@ -53,4 +75,4 @@ impl RepairConfig { pub fn fixed_version(&self) -> &str { &self.fixed_version } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 3e3bb00..d13730c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,10 @@ use std::fs; use std::io::Write; use std::path::{Path, PathBuf}; +use tracing_subscriber::{fmt, EnvFilter}; +use tracing::{trace, debug, info, error}; + +use config::RepairConfig; use cvrf_xmlparser::{ CVRF, // SaInfo 即为 CUSA @@ -21,6 +25,7 @@ pub type Error = Box; pub type Result = std::result::Result; pub fn cumain() -> Result<()> { + set_up_logging()?; let cli = cli::parse(); match cli.subcommand { @@ -30,6 +35,15 @@ pub fn cumain() -> Result<()> { } } +fn set_up_logging() -> crate::Result<()> { + fmt() + .with_ansi(false) + .with_timer(fmt::time::OffsetTime::local_rfc_3339().unwrap()) + .with_line_number(true) + .with_env_filter(EnvFilter::from_default_env()) + .try_init() +} + /// 可使用 convert 函数将 cvrf 格式文件转换并输出至指定的 cusa 文件。 /// /// 例: @@ -178,9 +192,120 @@ pub fn auto() -> Result<()> { "cvrf2cusa.json" } }; + info!("Config file is: {}", config); let auto = config::AutoConfig::from(config)?; + info!("Load AutoConfig: {:?}", auto); + + let files = walk_dir(auto.source(), true); + + for _file in files { + match _file.extension() { + Some(tail) => { + if tail != "xml" { + continue; + } + + // 从 xml 中读取 cvrf 并转换为 cusa + let file = if let Some(file) = _file.to_str() { + file + } else { + continue; + }; + trace!("parsing {}", file); + let mut cvrf = CVRF::new(); + let _ = cvrf.load_xml(file); + + _save_2_cusa_db(auto.target(), &cvrf)?; + }, + _ => {}, + } + } + Ok(()) +} + +fn _save_2_cusa_db(dbpath: &str, cvrf: &CVRF) -> Result<()> { + let mut db = PathBuf::from(dbpath); + + let component = cvrf.affected_component().unwrap(); + trace!("Get affected_component: {}", component); + // 这里随便取一个 src 包名 + let _src = cvrf.producttree.packages["src"][0].productid.as_str(); + + // TODO: may empty + if _src == "" { + error!("{}: ProductTree->packages[\"src\"] have empty productid, ignore it!", cvrf.id()); + return Ok(()) + } + db.push(_src.chars().next().unwrap().to_string()); + // TODO!() + // db: "cusas/l/log4j,mybatis,netty,springframework,wildfly-security-manager,wildfly-elytron,wildfly-build-tools,wildfly-common,wildfly-core,thrift,json-lib,datanucleus-core,jgroups,mx4j,jboss-logging,infinispan,datanucleus-rdbms,avalon-logkit,datanucleus-api-jdo,avalon-framework,HikariCP,metrics" + // Error: Os { code: 63, kind: InvalidFilename, message: "File name too long" } + db.push(component); + + // 读取修复配置 + let mut repairconf = db.clone(); + repairconf.push("config.json"); + let repairconfig = match config::RepairConfig::from(&repairconf) { + Ok(repairconfig) => repairconfig, + _ => { + // 这里临时处理下,不应该创建 + // TO BE DELETE + let parent = repairconf.parent().unwrap(); + match fs::create_dir_all(parent) { + Ok(_) => {}, + Err(e) => { + error!("sa_id: {}, {}", cvrf.id(), e.to_string()); + return Ok(()); + } + } + let repairconfig = RepairConfig::new( + "22.03-LTS".to_string(), + true, + "".to_string(), + ); + // 写入默认配置 + let data = serde_json::to_string_pretty(&repairconfig)?; + let mut repair = fs::OpenOptions::new().read(true).write(true).create(true).open(repairconf)?; + repair.write(data.as_bytes())?; + repair.flush()?; + + repairconfig + } + }; + + // 是否影响当前软件包,即作上游判断 + let mut not_affected = true; + for product in cvrf.affected_products() { + if product.productid.ends_with(repairconfig.upstream()) { + not_affected = false; + } + } + if not_affected { + debug!("{} not effected {}'s {}, skip...", cvrf.id(), repairconfig.upstream(), component); + return Ok(()) + } + + // 增加 sa 信息 + let mut nvr = String::new(); + for product in &cvrf.producttree.packages["src"] { + if product.cpe.ends_with(repairconfig.upstream()) { + nvr = product.productid.clone(); + nvr.push_str(&format!("_{}.json", cvrf.id())); + break; + } + } + db.push(&nvr); + + if db.exists() { + debug!("{} is already converted!", cvrf.id()); + return Ok(()); + } + + let data = serde_json::to_string_pretty(&cvrf.sainfo())?; + let mut sa_file = fs::OpenOptions::new().read(true).write(true).create(true).open(db)?; + sa_file.write(data.as_bytes())?; + sa_file.flush()?; - todo!(); Ok(()) }