From 0ba6255522d02230dfa8627f936b503eb90bd517 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Mon, 22 Jan 2024 16:52:54 +0000 Subject: [PATCH] [util] Make version information a class Instead of treating version_stamp like a dictionary with specific name entries, turn it into a class with proper accessors so that the particular representation of the version information is abstracted. Signed-off-by: Amaury Pouly --- util/reggen/gen_tock.py | 23 ++++++++++----------- util/regtool.py | 2 +- util/rom_chip_info.py | 6 ++++-- util/topgen.py | 2 +- util/topgen/rust.py | 41 ++++++++++++-------------------------- util/version_file.py | 44 +++++++++++++++++++++++++---------------- 6 files changed, 56 insertions(+), 62 deletions(-) diff --git a/util/reggen/gen_tock.py b/util/reggen/gen_tock.py index 009de52b09dbf4..0d2a09d005e962 100644 --- a/util/reggen/gen_tock.py +++ b/util/reggen/gen_tock.py @@ -10,8 +10,7 @@ import sys import textwrap import warnings -from datetime import datetime -from typing import Any, Dict, Optional, Set, TextIO +from typing import Any, Optional, Set, TextIO from reggen.ip_block import IpBlock from reggen.multi_register import MultiRegister @@ -19,6 +18,8 @@ from reggen.register import Register from reggen.window import Window +from version_file import VersionInformation + REG_VISIBILITY = 'pub(crate)' FIELD_VISIBILITY = 'pub(crate)' @@ -327,7 +328,7 @@ def gen_const_interrupts(fieldout: TextIO, block: IpBlock, component: str, def gen_tock(block: IpBlock, outfile: TextIO, src_file: Optional[str], src_lic: Optional[str], src_copy: str, - version_stamp: Dict[str, str]) -> int: + version: VersionInformation) -> int: rnames = block.get_rnames() paramout = io.StringIO() @@ -397,16 +398,12 @@ def gen_tock(block: IpBlock, outfile: TextIO, src_file: Optional[str], genout(outfile, '\n') genout(outfile, '// Generated register constants for {}.\n', block.name) - if 'BUILD_GIT_VERSION' in version_stamp: - genout(outfile, '// Built for {}\n', version_stamp['BUILD_GIT_VERSION']) - if 'BUILD_SCM_REVISION' in version_stamp: - genout(outfile, '// https://github.com/lowRISC/opentitan/tree/{}\n', version_stamp['BUILD_SCM_REVISION']) - if 'BUILD_SCM_STATUS' in version_stamp: - genout(outfile, '// Tree status: {}\n', version_stamp['BUILD_SCM_STATUS']) - if 'BUILD_TIMESTAMP' in version_stamp: - tm = int(version_stamp['BUILD_TIMESTAMP']) - dt = datetime.utcfromtimestamp(tm) - genout(outfile, '// Build date: {}\n\n', dt.isoformat()) + if version.scm_version() is not None: + genout(outfile, '// Built for {}\n', version.scm_version()) + if version.scm_revision() is not None: + genout(outfile, '// https://github.com/lowRISC/opentitan/tree/{}\n', version.scm_revision()) + if version.scm_status() is not None: + genout(outfile, '// Tree status: {}\n', version.scm_status()) if src_file: genout(outfile, '// Original reference file: {}\n', src_file) diff --git a/util/regtool.py b/util/regtool.py index 769518f93bb36d..4ac0ba5af14b65 100755 --- a/util/regtool.py +++ b/util/regtool.py @@ -229,7 +229,7 @@ def main(): sys.exit(1) # Extract version stamp from file - version_stamp = version_file.parse_version_file(args.version_stamp) + version_stamp = version_file.VersionInformation(args.version_stamp) if fmt == 'doc': with outfile: diff --git a/util/rom_chip_info.py b/util/rom_chip_info.py index bec65aab4dbc22..65325bfc2bd61b 100755 --- a/util/rom_chip_info.py +++ b/util/rom_chip_info.py @@ -52,7 +52,9 @@ def read_version_file(version_info) -> int: if the variable is not found. """ - version = version_info.get('BUILD_SCM_REVISION', "8badF00d") + # If there is no revision information, we still need some + # number to encode in chip_info: choose a recognizable one. + version = version_info.scm_revision("8badf00d") return int(version, base=16) @@ -84,7 +86,7 @@ def main(): args = parser.parse_args() # Extract version stamp from file - version = read_version_file(version_file.parse_version_file(args.ot_version_file)) + version = read_version_file(version_file.VersionInformation(args.ot_version_file)) log.info("Version: %x" % (version, )) generated_source = generate_chip_info_c_source(version) diff --git a/util/topgen.py b/util/topgen.py index ab6785237d2266..ccf1fef167f0a5 100755 --- a/util/topgen.py +++ b/util/topgen.py @@ -1127,7 +1127,7 @@ def main(): raise SystemExit(sys.exc_info()[1]) # Extract version stamp from file - version_stamp = version_file.parse_version_file(args.version_stamp) + version_stamp = version_file.VersionInformation(args.version_stamp) # Initialize RNG for compile-time netlist constants. # If specified, override the seed for random netlist constant computation. diff --git a/util/topgen/rust.py b/util/topgen/rust.py index 8dbb3a59225ca6..cf56960e0505d0 100644 --- a/util/topgen/rust.py +++ b/util/topgen/rust.py @@ -4,13 +4,14 @@ """This contains a class which is used to help generate `top_{name}.rs`.""" from collections import OrderedDict, defaultdict from typing import Dict, List, Optional, Tuple -from datetime import datetime from mako.template import Template from reggen.ip_block import IpBlock from .lib import Name, get_base_and_size +from version_file import VersionInformation + RUST_FILE_EXTENSIONS = (".rs") @@ -188,35 +189,19 @@ def render_definition(self): class RustFileHeader(object): - def __init__(self, name: str, version_stamp: Dict[str, str], skip: bool): - self.name = name + def __init__(self, version_stamp: VersionInformation): self.data = version_stamp - self.skip = skip - tm = int(version_stamp.get('BUILD_TIMESTAMP', 0)) - self.tstamp = datetime.utcfromtimestamp(tm) if tm else datetime.utcnow() - - def build(self) -> str: - return self.data.get('BUILD_GIT_VERSION', '') - - def scm_sha(self) -> str: - return self.data.get('BUILD_SCM_REVISION', '') - - def scm_status(self) -> str: - return self.data.get('BUILD_SCM_STATUS', '') - - def time_stamp(self) -> str: - return self.tstamp.isoformat() def render(self): - if self.skip: - return Template(("")).render(header=self) - else: - template = ("\n" - "// Built for ${header.build()}\n" - "// https://github.com/lowRISC/opentitan/tree/${header.scm_sha()}\n" - "// Tree status: ${header.scm_status()}\n" - "// Build date: ${header.time_stamp()}\n") - return Template(template).render(header=self) + template = "\n" + if self.data.scm_version() is not None: + template += "// Built for ${header.data.scm_version()}\n" + if self.data.scm_revision() is not None: + template += ("// https://github.com/lowRISC/opentitan/tree/" + "${header.data.scm_revision()}\n") + if self.data.scm_status() is not None: + template += "// Tree status: ${header.data.scm_status()}\n" + return Template(template).render(header=self) class TopGenRust: @@ -225,7 +210,7 @@ def __init__(self, top_info, name_to_block: Dict[str, IpBlock], version_stamp: D self._top_name = Name(["top"]) + Name.from_snake_case(top_info["name"]) self._name_to_block = name_to_block self.regwidth = int(top_info["datawidth"]) - self.file_header = RustFileHeader("foo.tpl", version_stamp, len(version_stamp) == 0) + self.file_header = RustFileHeader(version_stamp) self._init_plic_targets() self._init_plic_mapping() diff --git a/util/version_file.py b/util/version_file.py index 6c0e86d28f165f..15136194bd0868 100644 --- a/util/version_file.py +++ b/util/version_file.py @@ -4,22 +4,32 @@ # SPDX-License-Identifier: Apache-2.0 import sys +from typing import Union -def parse_version_file(path): - """ - Parse a bazel version file and return a dictionary of the values. - If `path` is None, an empty dictionary is returned. - If an error occurs during parsing, an exception is raised. - """ - if path is None: - return {} - version_stamp = {} - try: - with open(path, 'rt') as f: - for line in f: - k, v = line.strip().split(' ', 1) - version_stamp[k] = v - except ValueError: - raise SystemExit(sys.exc_info()[1]) - return version_stamp +class VersionInformation(): + def __init__(self, path: str): + """ + Parse a bazel version file and store a dictionary of the values. + If `path` is None, an empty dictionary will be created. + If an error occurs during parsing, an exception is raised. + """ + self.version_stamp = {} + if path is None: + return + try: + with open(path, 'rt') as f: + for line in f: + k, v = line.strip().split(' ', 1) + self.version_stamp[k] = v + except ValueError: + raise SystemExit(sys.exc_info()[1]) + + def scm_version(self, default: Union[str, None] = None) -> Union[str, None]: + return self.version_stamp.get('BUILD_GIT_VERSION', default) + + def scm_revision(self, default: Union[str, None] = None) -> Union[str, None]: + return self.version_stamp.get('BUILD_SCM_REVISION', default) + + def scm_status(self, default: Union[str, None] = None) -> Union[str, None]: + return self.version_stamp.get('BUILD_SCM_STATUS', default)