auto 功能初步实现

Signed-off-by: Jia Chao <jiac13@chinaunicom.cn>
This commit is contained in:
Jia Chao 2024-07-02 15:51:18 +08:00
parent 6a75014e83
commit f65a0c3182
3 changed files with 154 additions and 5 deletions

View File

@ -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"] }

View File

@ -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<Self> {
// 从文件中读取配置
pub fn from<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
let data = std::fs::read_to_string(path)?;
Ok(serde_json::from_str::<Self>(&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<Self> {
pub fn from<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
let data = std::fs::read_to_string(path)?;
Ok(serde_json::from_str::<Self>(&data)?)

View File

@ -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<dyn std::error::Error + Send + Sync>;
pub type Result<T> = std::result::Result<T, Error>;
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(())
}