Compare commits

...

4 commits

9 changed files with 231 additions and 42 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target /target
result*

View file

@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased] ## [unreleased]
### Added
- Packagin with Nix flakes (with nixpkgs buildRustPackage) [!16](https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/-/merge_requests/16)
- Now xml metadata can be overwritten with corresponding environmental variables. [!17](https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/-/merge_requests/17)
### Changed ### Changed
- Improve error message from syn in generator. - Improve error message from syn in generator. !15
## [0.3.1] - 2025-04-11 ## [0.3.1] - 2025-04-11

View file

@ -33,7 +33,7 @@ cargo build --features=bin --bins --release
`target/release`に入ってるバイナリファイルを実行するか、`cargo run -- <XML> <OUT>`で実行できます。 `target/release`に入ってるバイナリファイルを実行するか、`cargo run -- <XML> <OUT>`で実行できます。
詳しくは`--help`を見てください。 詳しくは(`-h`ではなく)`--help`を見てください。
### ライブラリクレートの使い方 ### ライブラリクレートの使い方

View file

@ -36,7 +36,7 @@ to build.
Execute the binary generated in `target/release/`, or run with `cargo run -- <XML> <OUT>`. Execute the binary generated in `target/release/`, or run with `cargo run -- <XML> <OUT>`.
See the `--help` for more information. See the `--help`(not `-h`) for more information.
### Library crate usage ### Library crate usage

82
flake.lock generated Normal file
View file

@ -0,0 +1,82 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1744098102,
"narHash": "sha256-tzCdyIJj9AjysC3OuKA+tMD/kDEDAF9mICPDU7ix0JA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "c8cd81426f45942bb2906d5ed2fe21d2f19d95b7",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1744166053,
"narHash": "sha256-mpI7OzFwp+fUeDtZYQbVZ2YmtxTN2UNrrOwbYD27xKU=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "896158be1835589db6f42f45ef0a49b8b492cc66",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

37
flake.nix Normal file
View file

@ -0,0 +1,37 @@
{
description = "A very basic flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
nixpkgs,
flake-utils,
rust-overlay,
...
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ rust-overlay.overlays.default ];
};
in
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.rust-bin.stable.latest.default
];
};
packages.default = pkgs.callPackage ./nix/endcap-sl-software-ri-generator.nix { };
}
);
}

View file

@ -0,0 +1,11 @@
{ rustPlatform }:
# https://nixos.org/manual/nixpkgs/stable/#rust
rustPlatform.buildRustPackage {
pname = "endcap-sl-software-ri-generator";
version = "0.3.0";
src = ../.;
cargoLock.lockFile = ../Cargo.lock;
buildFeatures = [ "bin" ];
}

120
src/io.rs
View file

@ -1,11 +1,15 @@
//! File IO for generated codes. //! File IO for generated codes.
use std::{collections::HashMap, fs, io, path, process}; use std::{collections::HashMap, env, ffi::OsString, fs, io, path, process};
use thiserror::Error; use thiserror::Error;
use crate::types::XmlGitInfo; use crate::types::XmlGitInfo;
const ENVVAR_XML_GIT_DESCRIBE: &str = "XML_GIT_DESCRIBE";
const ENVVAR_XML_GIT_TIMESTAMP: &str = "XML_GIT_TIMESTAMP";
const ENVVAR_XML_GIT_SHA: &str = "XML_GIT_SHA";
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum XmlGitInfoError { pub enum XmlGitInfoError {
#[error("io error while getting xml git info: {msg} {source}")] #[error("io error while getting xml git info: {msg} {source}")]
@ -16,6 +20,8 @@ pub enum XmlGitInfoError {
}, },
#[error("git failed: {msg}: {stderr}")] #[error("git failed: {msg}: {stderr}")]
CommandFailed { msg: &'static str, stderr: String }, CommandFailed { msg: &'static str, stderr: String },
#[error("env var {var} is not unicode: {}", s.to_string_lossy())]
NotUnicodeEnvVar { var: &'static str, s: OsString },
} }
impl XmlGitInfoError { impl XmlGitInfoError {
@ -25,44 +31,84 @@ impl XmlGitInfoError {
} }
pub(crate) fn get_xml_gitinfo(xml_path: &path::Path) -> Result<XmlGitInfo, XmlGitInfoError> { pub(crate) fn get_xml_gitinfo(xml_path: &path::Path) -> Result<XmlGitInfo, XmlGitInfoError> {
let describe = process::Command::new("git") let describe = match env::var(ENVVAR_XML_GIT_DESCRIBE) {
.args(["describe", "--always", "--dirty"]) Ok(describe) => describe,
.current_dir(xml_path.parent().unwrap()) Err(env::VarError::NotUnicode(s)) => {
.output() return Err(XmlGitInfoError::NotUnicodeEnvVar {
.map_err(|e| XmlGitInfoError::io_error(e, "git describe"))?; var: ENVVAR_XML_GIT_DESCRIBE,
let describe = if describe.status.success() { s,
String::from_utf8_lossy(&describe.stdout).trim().to_owned() });
} else { }
return Err(XmlGitInfoError::CommandFailed { Err(env::VarError::NotPresent) => {
msg: "git describe", let out_describe = process::Command::new("git")
stderr: String::from_utf8_lossy(&describe.stderr).into_owned(), .args(["describe", "--always", "--dirty"])
}); .current_dir(xml_path.parent().unwrap())
.output()
.map_err(|e| XmlGitInfoError::io_error(e, "git describe"))?;
let describe = if out_describe.status.success() {
String::from_utf8_lossy(&out_describe.stdout)
.trim()
.to_owned()
} else {
return Err(XmlGitInfoError::CommandFailed {
msg: "git describe",
stderr: String::from_utf8_lossy(&out_describe.stderr).into_owned(),
});
};
describe
}
}; };
let timestamp = process::Command::new("git") let timestamp = match env::var(ENVVAR_XML_GIT_TIMESTAMP) {
.args(["log", "-1", "--pretty=format:'%cI'"]) Ok(timestamp) => timestamp,
.current_dir(xml_path.parent().unwrap()) Err(env::VarError::NotUnicode(s)) => {
.output() return Err(XmlGitInfoError::NotUnicodeEnvVar {
.map_err(|e| XmlGitInfoError::io_error(e, "git log (timestamp)"))?; var: ENVVAR_XML_GIT_TIMESTAMP,
let timestamp = if timestamp.status.success() { s,
String::from_utf8_lossy(&timestamp.stdout).trim().to_owned() });
} else { }
return Err(XmlGitInfoError::CommandFailed { Err(env::VarError::NotPresent) => {
msg: "git log (timestamp)", let timestamp_out = process::Command::new("git")
stderr: String::from_utf8_lossy(&timestamp.stderr).into_owned(), .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_out.status.success() {
String::from_utf8_lossy(&timestamp_out.stdout)
.trim()
.to_owned()
} else {
return Err(XmlGitInfoError::CommandFailed {
msg: "git log (timestamp)",
stderr: String::from_utf8_lossy(&timestamp_out.stderr).into_owned(),
});
};
timestamp
}
}; };
let sha = process::Command::new("git") let git_sha = match env::var(ENVVAR_XML_GIT_SHA) {
.args(["rev-parse", "HEAD"]) Ok(sha) => sha,
.current_dir(xml_path.parent().unwrap()) Err(env::VarError::NotUnicode(s)) => {
.output() return Err(XmlGitInfoError::NotUnicodeEnvVar {
.map_err(|e| XmlGitInfoError::io_error(e, "git rev-parse (sha)"))?; var: ENVVAR_XML_GIT_SHA,
let git_sha = if sha.status.success() { s,
String::from_utf8_lossy(&sha.stdout).trim().to_owned() });
} else { }
return Err(XmlGitInfoError::CommandFailed { Err(env::VarError::NotPresent) => {
msg: "git rev-parse (sha)", let sha = process::Command::new("git")
stderr: String::from_utf8_lossy(&sha.stderr).into_owned(), .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(),
});
};
git_sha
}
}; };
Ok(XmlGitInfo { Ok(XmlGitInfo {
describe, describe,

View file

@ -3,11 +3,16 @@ use std::path;
use anyhow::Result; use anyhow::Result;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
/// Generate register interface from register map xml. /// Validate the register map xml and generate register interface from register map xml.
/// See `help` with each commands to see detailed explanations.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about)] #[command(version, about, long_about)]
struct Args { struct Args {
/// Input XML register map. /// Input XML register map.
///
/// The path must be a valid git repository to get git metadata.
/// You can also force these metadata with environmental variables `XML_GIT_DESCRIBE`,
/// `XML_GIT_TIMESTAMP` and `XML_GIT_SHA`.
xml: path::PathBuf, xml: path::PathBuf,
#[command(subcommand)] #[command(subcommand)]
command: Commands, command: Commands,
@ -23,6 +28,8 @@ enum Commands {
out: path::PathBuf, out: path::PathBuf,
}, },
/// Generate flattened register map in CSV. /// Generate flattened register map in CSV.
///
/// Also run validation before generation.
#[cfg(feature = "flatmap")] #[cfg(feature = "flatmap")]
Flatmap { Flatmap {
/// Flattened csv out path. /// Flattened csv out path.