From 3bd8def2106f831d3af4fca61bb00881b3a6e2c0 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 3 Oct 2018 11:38:09 +1000 Subject: config: Consolidate the version information into a single configuration file --- config/rtems-version.ini | 8 ++ rtemstoolkit/check.py | 2 +- rtemstoolkit/options.py | 4 +- rtemstoolkit/rtems.py | 59 ++++++++++++-- rtemstoolkit/version.py | 196 +++++++++++++++++++++++++++++++++++++++++------ tester/rt/check.py | 33 ++++---- tester/rt/options.py | 2 +- tester/rt/run.py | 2 +- tester/rt/test.py | 2 +- wscript | 43 ++--------- 10 files changed, 258 insertions(+), 93 deletions(-) create mode 100644 config/rtems-version.ini diff --git a/config/rtems-version.ini b/config/rtems-version.ini new file mode 100644 index 0000000..98d0f0f --- /dev/null +++ b/config/rtems-version.ini @@ -0,0 +1,8 @@ +# +# RTEMS Tools Project (http://www.rtems.org/) +# +# RTEMS Version +# + +[version] +revision = 5.0.not_released diff --git a/rtemstoolkit/check.py b/rtemstoolkit/check.py index cbec3a3..c6549bf 100644 --- a/rtemstoolkit/check.py +++ b/rtemstoolkit/check.py @@ -168,7 +168,7 @@ def run(): try: _opts = options.command_line(argv = sys.argv) options.load(_opts) - log.notice('RTEMS Source Builder - Check, v%s' % (version.str())) + log.notice('RTEMS Source Builder - Check, v%s' % (version.string())) if host_setup(_opts): print('Environment is ok') else: diff --git a/rtemstoolkit/options.py b/rtemstoolkit/options.py index 98b5854..77d9593 100644 --- a/rtemstoolkit/options.py +++ b/rtemstoolkit/options.py @@ -289,7 +289,7 @@ class command_line(object): def help(self): print('%s: [options] [args]' % (self.command_name)) - print('RTEMS Tools Project (c) 2012-2015 Chris Johns') + print('RTEMS Tools Project, %s' % (version.string())) print('Options and arguments:') opts = list(self.long_opts_help.keys()) if self.optargs: @@ -559,7 +559,7 @@ def run(args): long_opts = long_opts, command_path = '.') load(opts) - log.notice('RTEMS Tools Project - Defaults, v%s' % (version.str())) + log.notice('RTEMS Tools Project - Defaults, v%s' % (version.string())) opts.log_info() log.notice('Options:') log.notice(str(opts)) diff --git a/rtemstoolkit/rtems.py b/rtemstoolkit/rtems.py index 13b1e7a..8aa22e5 100755 --- a/rtemstoolkit/rtems.py +++ b/rtemstoolkit/rtems.py @@ -1,6 +1,6 @@ # # RTEMS Tools Project (http://www.rtems.org/) -# Copyright 20162018 Chris Johns (chrisj@rtems.org) +# Copyright 2016-2018 Chris Johns (chrisj@rtems.org) # All rights reserved. # # This file is part of the RTEMS Tools package in 'rtems-tools'. @@ -33,26 +33,69 @@ from __future__ import print_function import copy import os import re +import sys import textwrap from rtemstoolkit import configuration as configuration_ from rtemstoolkit import error +from rtemstoolkit import path from rtemstoolkit import textbox -from rtemstoolkit import version +# +# The default path we install RTEMS under +# +_prefix_path = '/opt/rtems' + +def default_prefix(): + from rtemstoolkit import version + return path.join(_prefix_path, version.version()) def clean_windows_path(): - # - # On Windows MSYS2 prepends a path to itself to the environment - # path. This means the RTEMS specific automake is not found and which - # breaks the bootstrap. We need to remove the prepended path. Also - # remove any ACLOCAL paths from the environment. - # + '''On Windows MSYS2 prepends a path to itself to the environment path. This + means the RTEMS specific automake is not found and which breaks the + bootstrap. We need to remove the prepended path. Also remove any ACLOCAL + paths from the environment. + + ''' if os.name == 'nt': cspath = os.environ['PATH'].split(os.pathsep) if 'msys' in cspath[0] and cspath[0].endswith('bin'): os.environ['PATH'] = os.pathsep.join(cspath[1:]) +def configuration_path(): + '''Return the path the configuration data path for RTEMS. The path is relative + to the installed executable. Mangage the installed package and the in source + tree when running from within the rtems-tools repo. + + ''' + exec_name = os.path.abspath(sys.argv[0]) + for top in [os.path.dirname(exec_name), + os.path.dirname(os.path.dirname(exec_name))]: + config_path = path.join(top, 'share', 'rtems', 'config') + if path.exists(config_path): + break + config_path = path.join(top, 'config') + if path.exists(config_path): + break + config_path = None + return config_path + +def configuration_file(config): + '''Return the path to a configuration file for RTEMS. The path is relative to + the installed executable or we are testing and running from within the + rtems-tools repo. + + ''' + return path.join(configuration_path(), config) + +def bsp_configuration_file(): + '''Return the path to the BSP configuration file for RTEMS. The path is + relative to the installed executable or we are testing and running from + within the rtems-tools repo. + + ''' + return configuration_file('rtems-bsps.ini') + class configuration: def __init__(self): diff --git a/rtemstoolkit/version.py b/rtemstoolkit/version.py index 6c2e5e6..d538d2a 100644 --- a/rtemstoolkit/version.py +++ b/rtemstoolkit/version.py @@ -1,6 +1,6 @@ # # RTEMS Tools Project (http://www.rtems.org/) -# Copyright 2010-2016 Chris Johns (chrisj@rtems.org) +# Copyright 2010-2018 Chris Johns (chrisj@rtems.org) # All rights reserved. # # This file is part of the RTEMS Tools package in 'rtems-tools'. @@ -29,83 +29,229 @@ # # -# To release RTEMS Tools create a git archive and then add a suitable VERSION -# file to the top directory. +# Releasing RTEMS Tools +# --------------------- +# +# Format: +# +# The format is INI. The file requires a `[version`] section and a `revision` +# option: +# +# [version] +# revision = +# +# The `` has the `version` and `revision` delimited by a +# single `.`. An example file is: +# +# [version] +# revision = 5.0.not_released +# +# where the `version` is `5` and the revision is `0` and the package is not +# released. The label `not_released` is reversed to mean the package is not +# released. A revision string can contain extra characters after the +# `revision` number for example `5.0-rc1` or is deploying a package +# `5.0-nasa-cfs` +# +# Packages can optionally add specialised sections to a version configuration +# files. These can be accessed via the: +# +# load_release_settings: Return the items in a section +# load_release_setting: Return an item from a section +# +# User deployment: +# +# Create a git archive and then add a suitable VERSION file to the top +# directory of the package. The package assumes your python executable is +# location in `bin` directory which is one below the top of the package's +# install prefix. +# +# RTEMS Release: +# +# Set the values in the `rtems-version.ini` file. This is a shared file so +# packages and encouraged to add specific settings to other configuration +# files. +# +# Notes: +# +# This module uses os.apth for paths and assumes all paths are in the host +# format. # from __future__ import print_function +import itertools +import os import sys +try: + import configparser +except ImportError: + import ConfigParser as configparser + # -# Support to handle use in a package and as a unit test. +# Support to handle importing when installed in a package and as a unit test. # If there is a better way to let us know. # try: from . import error from . import git - from . import path + from . import rtems except (ValueError, SystemError): import error import git import path + import rtems # # Default to an internal string. # -_version = '5' +_version = 'undefined' _revision = 'not_released' _version_str = '%s.%s' % (_version, _revision) _released = False _git = False +_is_loaded = False + +def _top(): + top = os.path.dirname(sys.argv[0]) + if len(top) == 0: + top = '.' + return top -def _at(): - return path.dirname(__file__) +def _load_released_version_config(): + '''Local worker to load a configuration file.''' + top = _top() + for ver in [os.path.join(top, 'VERSION'), + os.path.join('..', 'VERSION'), + rtems.configuration_file('rtems-version.ini')]: + if os.path.exists(os.path.join(ver)): + v = configparser.SafeConfigParser() + try: + v.read(ver) + except Exception as e: + raise error.general('Invalid version config format: %s: %s' % (ver, + e)) + return ver, v + return None, None def _load_released_version(): + '''Load the release data if present. If not found the package is not released. + + A release can be made by adding a file called `VERSION` to the top level + directory of a package. This is useful for user deploying a package and + making custom releases. + + The RTEMS project reserves the `rtems-version.ini` file for it's + releases. This is the base release and should not be touched by users + deploying a package. + + ''' + global _version + global _revision global _released global _version_str - at = _at() - for ver in [at, path.join(at, '..')]: - if path.exists(path.join(ver, 'VERSION')): + global _is_loaded + + if not _is_loaded: + vc, v = _load_released_version_config() + if v is not None: try: - import configparser - except ImportError: - import ConfigParser as configparser - v = configparser.SafeConfigParser() - v.read(path.join(ver, 'VERSION')) - _version_str = v.get('version', 'release') - _released = True + ver_str = v.get('version', 'revision') + except Exception as e: + raise error.general('Invalid version file: %s: %s' % (vc, e)) + ver_split = ver_str.split('.') + if len(ver_split) < 2: + raise error.general('Invalid version release value: %s: %s' % (vc, + ver_str)) + ver = ver_split[0] + rev = '.'.join(ver_split[1:]) + try: + _version = int(ver) + except: + raise error.general('Invalid version config value: %s: %s' % (vc, + ver)) + try: + _revision = int(''.join(itertools.takewhile(str.isdigit, rev))) + except Exception as e: + raise error.general('Invalid revision config value: %s: %s: %s' % (vc, + rev, + e)) + if not 'not_released' in ver: + _released = True + _version_str = ver_str + _is_loaded = True return _released def _load_git_version(): + global _version + global _revision global _git global _version_str - repo = git.repo(_at()) + repo = git.repo(_top()) if repo.valid(): head = repo.head() if repo.dirty(): - modified = ' modified' + modified = 'modified' + sep = ' ' else: modified = '' - _version_str = '%s (%s%s)' % (_version, head[0:12], modified) + sep = '' + _revision = '%s-%s' % (head[0:12], modified) + _version_str = '%s (%s%s%s)' % (_version, head[0:12], sep, modified) _git = True return _git +def load_release_settings(section, error = False): + vc, v = _load_released_version_config() + items = [] + if v is not None: + try: + items = v.items(section) + except Exception as e: + if not isinstance(error, bool): + error(e) + elif error: + raise error.general('Invalid config section: %s: %s: %s' % (vc, + section, + e)) + return items + +def load_release_setting(section, option, raw = False, error = False): + vc, v = _load_released_version_config() + value = None + if v is not None: + try: + value = v.get(section, option, raw = raw) + except Exception as e: + if not isinstance(error, bool): + error(e) + elif error: + raise error.general('Invalid config section: %s: %s: %s.%s' % (vc, + section, + option, + e)) + return value + def released(): return _load_released_version() def version_control(): return _load_git_version() -def str(): - if not _released and not _git: - if not _load_released_version(): - _load_git_version() +def string(): + _load_released_version() + _load_git_version() return _version_str def version(): + _load_released_version() + _load_git_version() return _version +def revision(): + _load_released_version() + _load_git_version() + return _revision + if __name__ == '__main__': print('Version: %s' % (str())) diff --git a/tester/rt/check.py b/tester/rt/check.py index 0f9ee13..f2addbd 100755 --- a/tester/rt/check.py +++ b/tester/rt/check.py @@ -64,6 +64,9 @@ log_lock = threading.Lock() # max_build_label = 0 +def _now(): + return datetime.datetime.now() + def rtems_version(): return version.version() @@ -99,7 +102,7 @@ def comma_split(options): return [o.strip() for o in options.split(',')] def title(): - return 'RTEMS Tools Project - RTEMS Kernel BSP Builder, %s' % (version.str()) + return 'RTEMS Tools Project - RTEMS Kernel BSP Builder, %s' % (version.string()) def command_line(): return wrap(('command: ', ' '.join(sys.argv)), lineend = '\\') @@ -156,10 +159,10 @@ class arch_bsp_build: return self.arch, self.bsp def start(self): - self.start_time = datetime.datetime.now() + self.start_time = _now() def stop(self): - self.stop_time = datetime.datetime.now() + self.stop_time = _now() def duration(self): return self.stop_time - self.start_time @@ -988,8 +991,7 @@ class builder: with open(self.options['warnings-report'], 'w') as f: f.write(title() + os.linesep) f.write(os.linesep) - f.write('Date: %s%s' % (datetime.datetime.now().strftime('%c'), - os.linesep)) + f.write('Date: %s%s' % (_now().strftime('%c'), os.linesep)) f.write(os.linesep) f.write(command_line() + os.linesep) f.write(self.results.warnings_errors.warnings_report()) @@ -999,8 +1001,7 @@ class builder: with open(self.options['failures-report'], 'w') as f: f.write(title() + os.linesep) f.write(os.linesep) - f.write('Date: %s%s' % (datetime.datetime.now().strftime('%c'), - os.linesep)) + f.write('Date: %s%s' % (_now().strftime('%c'), os.linesep)) f.write(os.linesep) f.write(command_line() + os.linesep) f.write(self.results.failures_report()) @@ -1022,8 +1023,8 @@ class builder: if path.exists(self.build_dir): log.notice('Cleaning: %s' % (self.build_dir)) path.removeall(self.build_dir) - self.start = datetime.datetime.now() - self.end = datetime.datetime.now() + self.start = _now() + self.end = _now() self.duration = self.end - self.start self.average = self.duration env_path = os.environ['PATH'] @@ -1063,7 +1064,7 @@ class builder: except: pass raise - self.end = datetime.datetime.now() + self.end = _now() os.environ['PATH'] = env_path self.duration = self.end - self.start if self.jobs_completed == 0: @@ -1123,16 +1124,12 @@ def run_args(args): try: rtems.clean_windows_path() - start = datetime.datetime.now() - top = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) + start = _now() prefix = '/opt/rtems/%s' % (rtems_version()) tools = prefix build_dir = 'bsp-builds' - logf = 'bsp-build-%s.txt' % \ - (datetime.datetime.now().strftime('%Y%m%d-%H%M%S')) - config_file = path.join(top, 'config', 'rtems-bsps.ini') - if not path.exists(config_file): - config_file = path.join(top, 'share', 'rtems', 'config', 'rtems-bsps.ini') + logf = 'bsp-build-%s.txt' % (_now().strftime('%Y%m%d-%H%M%S')) + config_file = rtems.bsp_configuration_file() argsp = argparse.ArgumentParser() argsp.add_argument('--prefix', help = 'Prefix to build the BSP.', @@ -1249,7 +1246,7 @@ def run_args(args): else: what = 'Profile(s): %s' % (' '.join(profiles)) b.build_profiles(profiles) - end = datetime.datetime.now() + end = _now() # # Email the results of the build. diff --git a/tester/rt/options.py b/tester/rt/options.py index d41b721..da743c1 100644 --- a/tester/rt/options.py +++ b/tester/rt/options.py @@ -109,7 +109,7 @@ def load(args, optargs = None, def run(args): try: _opts = load(args = args, defaults = defaults_mc) - log.notice('RTEMS Test - Defaults, v%s' % (version.str())) + log.notice('RTEMS Test - Defaults, v%s' % (version.string())) _opts.log_info() log.notice('Options:') log.notice(str(_opts)) diff --git a/tester/rt/run.py b/tester/rt/run.py index cf8c4e5..1f4fa3a 100644 --- a/tester/rt/run.py +++ b/tester/rt/run.py @@ -114,7 +114,7 @@ def run(command_path = None): opts = options.load(sys.argv, optargs = optargs, command_path = command_path) - log.notice('RTEMS Testing - Run, %s' % (version.str())) + log.notice('RTEMS Testing - Run, %s' % (version.string())) if opts.find_arg('--list-bsps'): bsps.list(opts) opts.log_info() diff --git a/tester/rt/test.py b/tester/rt/test.py index 9214ad6..c5d61d8 100644 --- a/tester/rt/test.py +++ b/tester/rt/test.py @@ -250,7 +250,7 @@ def run(command_path = None): else: to_addr = 'build@rtems.org' output = log_capture() - log.notice('RTEMS Testing - Tester, %s' % (version.str())) + log.notice('RTEMS Testing - Tester, %s' % (version.string())) if opts.find_arg('--list-bsps'): bsps.list(opts) exe_filter = opts.find_arg('--filter') diff --git a/wscript b/wscript index c0286de..adbe766 100644 --- a/wscript +++ b/wscript @@ -40,43 +40,14 @@ subdirs = ['rtemstoolkit', 'tools/gdb/python'] def get_version(ctx): - version = '5' - revision = 'not_released' + from rtemstoolkit import version as rtemsversion + try: + version = rtemsversion.version() + revision = rtemsversion.revision() + except Exception as e: + ctx.fatal('invalid version file: %s' % (e)) release = '%s.%s' % (version, revision) - if os.path.exists('VERSION'): - try: - import configparser - except ImportError: - import ConfigParser as configparser - v = configparser.SafeConfigParser() - v.read('VERSION') - release = v.get('version', 'release') - else: - # - # waf after 1.9.9 does not place the current directory in Python's - # system path which means importing the RTEMS toolkit - # fails. Temporarily add it so we can import the git module. - # - import sys - current_sys_path = sys.path - try: - sys.path = [os.getcwd()] + sys.path - from rtemstoolkit import git - finally: - sys.path = current_sys_path - repo = git.repo('.') - if repo.valid(): - head = repo.head() - if repo.dirty(): - modified = '_modified' - else: - modified = '' - release = '%s.%s%s' % (version, head[0:12], modified) - last_dot = release.rfind('.') - if last_dot == -1: - ctx.fatal('invalid VERSION file') - revision = release[0:last_dot] - return revision, release + return version, release def recurse(ctx): for sd in subdirs: -- cgit v1.2.3