diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f55da9c..84408f8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ stages: # List of stages for jobs, and their order of execution - test .setup-rust: - image: registry.cern.ch/docker.io/library/rust:latest + image: rust:latest before_script: - rustup component add clippy rustfmt diff --git a/CHANGELOG.md b/CHANGELOG.md index e22ba8a..d7baa7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.2.0] - 2025-02-12 - -### Added - -- Embedding XML git metadata -- New high-level API (`generate` function) +## [Unreleased] ### Fixed @@ -23,6 +18,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implemented basic code generation covering current CSR XML. -[unreleased]: https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/-/compare/v0.2.0...main -[0.2.0]: https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/-/compare/v0.1.0...v0.2.0 +[unreleased]: https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/-/compare/v0.1.0...main [0.1.0]: https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/~/tags/v0.1.0 diff --git a/Cargo.lock b/Cargo.lock index 550b77e..cc5e0d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,7 +353,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "endcap-sl-software-ri-generator" -version = "0.2.0" +version = "0.1.0" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2a17f3a..ab96610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "endcap-sl-software-ri-generator" -version = "0.2.0" +version = "0.1.0" authors = ["Wataru Otsubo "] edition = "2021" description = "A generator of register interface for mpsoc software from register map in xml format" diff --git a/README-ja.md b/README-ja.md index 7e770e3..1c22a35 100644 --- a/README-ja.md +++ b/README-ja.md @@ -25,9 +25,8 @@ rustupのインストールには公式サイトにある`curl`スクリプト ### バイナリクレートの使い方 ```bash -cargo build --features=bin --bins --release +cargo build --bins --release ``` - を実行します。 `--release`はオプションです。 diff --git a/README.md b/README.md index 9685c6f..d892165 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Note that `cargo` is available on lxplus, so you might be able to use that (it i Execute ```bash -cargo build --features=bin --bins --release +cargo build --bins --release ``` to build. diff --git a/src/converter.rs b/src/converter.rs index 81056e2..3ccc699 100644 --- a/src/converter.rs +++ b/src/converter.rs @@ -13,7 +13,7 @@ use thiserror::Error; use crate::parser::{ParseCustomBool, ParseEnumError, ParsePrefixedU32, ParsePrefixedU32Error}; use crate::types::{ BitString, Block, Field, Fifo, Memory, Module, ModuleBlockElements, MultipleParams, Register, - Value, XmlGitInfo, + Value, }; /// Possible errors in conversion, with positional information. @@ -164,7 +164,7 @@ mod util { } impl Module { - pub fn from_xml_dom(node: Node, git_info: XmlGitInfo) -> Result { + pub fn from_xml_dom(node: Node) -> Result { assert!(node.parent().unwrap().is_root()); assert_eq!(node.tag_name().name(), "module"); @@ -212,7 +212,6 @@ impl Module { elements_bitstring: child_bitstrings, elements_other: child_other, xmlhash: Sha256::digest(node.document().input_text()).into(), - git_info, }) } } diff --git a/src/generator.rs b/src/generator.rs index 67c12c7..7e9c2bc 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -130,8 +130,6 @@ impl Module { pub fn generate_code(self) -> Result, CodeGenError> { let build_metadata = format!( " -This code is auto generated using endcap_sl_software_ri_generator. - # Build metadata - timestamp: {} @@ -139,9 +137,9 @@ This code is auto generated using endcap_sl_software_ri_generator. ## CSR XML - sha256: {} -- git describe: {} -- git commit timestamp: {} -- git SHA: {} +- git describe: TODO (after building step is fixed) +- git commit timestamp: TODO +- git SHA: TODO ## Generator @@ -152,9 +150,6 @@ This code is auto generated using endcap_sl_software_ri_generator. ", Local::now().to_rfc3339_opts(chrono::SecondsFormat::Nanos, false), hex::encode(self.xmlhash), - self.git_info.describe, - self.git_info.commit_timestamp, - self.git_info.sha, GENERATOR_BUILD_TIMESTAMP, GENERATOR_GIT_DESCRIBE, GENERATOR_GIT_COMMIT_TIMESTAMP, @@ -369,6 +364,7 @@ impl CodeGen for Block { } }; let (out_path, next_parent_path) = mod_file_path(parent_path, &snake_case_name); + log::info!("{:?}", out_path); if let Some(old_out) = files.insert(out_path.clone(), out.clone()) { log::error!("path {}", out_path.display()); log::error!("old {}", old_out.to_string()); diff --git a/src/integrated.rs b/src/integrated.rs deleted file mode 100644 index a342730..0000000 --- a/src/integrated.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::path; - -use thiserror::Error; - -use crate::{ - converter, generator, - io::{get_xml_gitinfo, XmlGitInfoError}, - types, -}; - -#[derive(Debug, Error)] -pub enum Error { - #[error("error in getting xml git info: {0}")] - XmlGitInfoError(#[from] XmlGitInfoError), - #[error("io error: {0}")] - IOError(#[from] std::io::Error), - #[error("xml parse error: {0}")] - XmlParseError(#[from] roxmltree::Error), - #[error("dom conversion error: {0}")] - DomConversionError(#[from] converter::DomConversionError), - #[error("code generation error: {0}")] - CodeGenError(#[from] generator::CodeGenError), -} - -/// Generate register interface code from xml in `xml` and write them under directory `out`. -pub fn generate(xml: &path::Path, out: &path::Path) -> Result<(), Error> { - log::debug!("generate called: xml:{:?}, out: {:?}", xml, out); - - let xml_git_info = get_xml_gitinfo(xml)?; - log::debug!("xml git info {xml_git_info:?}"); - - let xmlfile = std::fs::read_to_string(xml)?; - let doc = roxmltree::Document::parse_with_options( - &xmlfile, - roxmltree::ParsingOptions { - allow_dtd: true, - nodes_limit: u32::MAX, - }, - )?; - log::debug!("xml parsed {doc:?}"); - - let register_map = types::Module::from_xml_dom(doc.root_element(), xml_git_info)?; - log::debug!("converted {register_map:?}"); - - let files = register_map.generate_code()?; - if log::log_enabled!(log::Level::Debug) { - for (path, code) in &files { - log::debug!("path: {:?}", path); - log::debug!("{}", prettyplease::unparse(code)); - log::trace!("{}", prettyplease::unparse(code)); - } - } - - crate::write_to_files(files, out)?; - log::debug!("wrote to files"); - - Ok(()) -} diff --git a/src/io.rs b/src/io.rs index 8b2b1eb..fc6ac57 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,75 +1,6 @@ //! File IO for generated codes. -use std::{collections::HashMap, fs, io, path, process}; - -use thiserror::Error; - -use crate::types::XmlGitInfo; - -#[derive(Debug, Error)] -pub enum XmlGitInfoError { - #[error("io error while getting xml git info: {msg} {source}")] - IOError { - msg: &'static str, - #[source] - source: io::Error, - }, - #[error("git failed: {msg}: {stderr}")] - CommandFailed { msg: &'static str, stderr: String }, -} - -impl XmlGitInfoError { - fn io_error(e: io::Error, msg: &'static str) -> Self { - XmlGitInfoError::IOError { msg, source: e } - } -} - -pub(crate) fn get_xml_gitinfo(xml_path: &path::Path) -> Result { - let describe = process::Command::new("git") - .args(["describe", "--always", "--dirty"]) - .current_dir(xml_path.parent().unwrap()) - .output() - .map_err(|e| XmlGitInfoError::io_error(e, "git describe"))?; - let describe = if describe.status.success() { - String::from_utf8_lossy(&describe.stdout).trim().to_owned() - } else { - return Err(XmlGitInfoError::CommandFailed { - msg: "git describe", - stderr: String::from_utf8_lossy(&describe.stderr).into_owned(), - }); - }; - let timestamp = process::Command::new("git") - .args(["log", "-1", "--pretty=format:'%cI'"]) - .current_dir(xml_path.parent().unwrap()) - .output() - .map_err(|e| XmlGitInfoError::io_error(e, "git log (timestamp)"))?; - let timestamp = if timestamp.status.success() { - String::from_utf8_lossy(×tamp.stdout).trim().to_owned() - } else { - return Err(XmlGitInfoError::CommandFailed { - msg: "git log (timestamp)", - stderr: String::from_utf8_lossy(×tamp.stderr).into_owned(), - }); - }; - let sha = process::Command::new("git") - .args(["rev-parse", "HEAD"]) - .current_dir(xml_path.parent().unwrap()) - .output() - .map_err(|e| XmlGitInfoError::io_error(e, "git rev-parse (sha)"))?; - let git_sha = if sha.status.success() { - String::from_utf8_lossy(&sha.stdout).trim().to_owned() - } else { - return Err(XmlGitInfoError::CommandFailed { - msg: "git rev-parse (sha)", - stderr: String::from_utf8_lossy(&sha.stderr).into_owned(), - }); - }; - Ok(XmlGitInfo { - describe, - commit_timestamp: timestamp, - sha: git_sha, - }) -} +use std::{collections::HashMap, fs, io, path}; /// Write formatted codes generated with [`Module::generate_code`](crate::types::Module::generate_code). pub fn write_to_files( diff --git a/src/lib.rs b/src/lib.rs index e76a395..58ac50a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,26 @@ //! //! # Example //! -//! See [`generate`]. +//! Here's a typical usage: +//! ```no_run +//! use endcap_sl_software_ri_generator::types; +//! +//! let xmlfile = std::fs::read_to_string("./csr.xml").expect("failed to open file"); +//! let doc = roxmltree::Document::parse_with_options( +//! &xmlfile, +//! roxmltree::ParsingOptions { +//! allow_dtd: true, +//! nodes_limit: u32::MAX, +//! }, +//! ) +//! .expect("failed to parse"); +//! +//! let register_map = types::Module::from_xml_dom(doc.root_element()).expect("failed to convert"); +//! +//! let files = register_map.generate_code().expect("failed to generate code"); +//! endcap_sl_software_ri_generator::write_to_files(files, +//! &std::path::PathBuf::from("out")).expect("failed to write"); +//! ``` //! //! # Overview //! @@ -25,12 +44,10 @@ pub mod converter; pub mod generator; -pub mod integrated; pub mod io; pub mod meta; mod parser; mod type_traits; pub mod types; -pub use integrated::generate; pub use io::write_to_files; diff --git a/src/main.rs b/src/main.rs index 3dc85ac..c320cef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ -use std::path; +use std::{fs, path}; use anyhow::Result; use clap::Parser; +use endcap_sl_software_ri_generator::types; +use itertools::Itertools; /// Generate register interface from register map xml. #[derive(Parser, Debug)] @@ -19,7 +21,35 @@ fn main() -> Result<()> { let args = Args::parse(); log::debug!("args: {:?}", args); - endcap_sl_software_ri_generator::generate(&args.xml, &args.out)?; + let xmlfile = fs::read_to_string(args.xml)?; + let doc = roxmltree::Document::parse_with_options( + &xmlfile, + roxmltree::ParsingOptions { + allow_dtd: true, + nodes_limit: u32::MAX, + }, + )?; + log::debug!("Parsed: {:#?}", doc); + + let register_map = types::Module::from_xml_dom(doc.root_element())?; + log::info!("read: {:?}", register_map); + log::debug!("read: {:#?}", register_map); + + let files = register_map.generate_code()?; + if log::log_enabled!(log::Level::Debug) { + for (path, code) in &files { + log::debug!("path: {:?}", path); + log::debug!("{}", prettyplease::unparse(code)); + log::trace!("{}", prettyplease::unparse(code)); + } + } + if log::log_enabled!(log::Level::Info) { + for filepath in files.keys().sorted() { + log::info!("{}", filepath.display()); + } + } + + endcap_sl_software_ri_generator::write_to_files(files, &args.out)?; Ok(()) } diff --git a/src/types.rs b/src/types.rs index 11d4800..e074786 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,7 +11,6 @@ pub struct Module { pub elements_bitstring: Vec, pub elements_other: Vec, pub xmlhash: [u8; 32], - pub git_info: XmlGitInfo, } #[derive(Debug)] @@ -152,10 +151,3 @@ pub enum FieldFifoInterface { Block, Both, } - -#[derive(Debug)] -pub struct XmlGitInfo { - pub(crate) describe: String, - pub(crate) commit_timestamp: String, - pub(crate) sha: String, -}