[PATCH] config: Consolidate the version information into a single configuration file

chrisj at rtems.org chrisj at rtems.org
Wed Oct 3 01:41:02 UTC 2018


From: Chris Johns <chrisj at rtems.org>

---
 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 at rtems.org)
+# Copyright 2016-2018 Chris Johns (chrisj at 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 at rtems.org)
+# Copyright 2010-2018 Chris Johns (chrisj at 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 = <version-string>
+#
+#  The `<version-string>` 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 at 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:
-- 
2.15.1



More information about the devel mailing list