From 651f1f83394daf88bb3939f7e6ca989f45e3ad3e Mon Sep 17 00:00:00 2001 From: Theofilos Manitaras Date: Wed, 18 Dec 2019 13:24:03 +0100 Subject: [PATCH 1/2] Add function to get the git commit hash --- reframe/utility/os_ext.py | 26 ++++++++++++++++++++++++-- unittests/test_utility.py | 7 +++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/reframe/utility/os_ext.py b/reframe/utility/os_ext.py index dc8387fbd5..824d468ed7 100644 --- a/reframe/utility/os_ext.py +++ b/reframe/utility/os_ext.py @@ -11,6 +11,7 @@ import shlex import shutil import signal +import sys import subprocess import tempfile from urllib.parse import urlparse @@ -67,9 +68,15 @@ def run_command_async(cmd, shell=False, **popen_args): # Import logger here to avoid unnecessary circular dependencies - from reframe.core.logging import getlogger + # FIXME: Will be fixed when a version to execute commands without logging + # becomes available. + modulename = 'logging' + if modulename not in sys.modules: + import reframe.core.logging as logging + else: + logging = sys.modules['logging'] - getlogger().debug('executing OS command: ' + cmd) + logging.getLogger().debug('executing OS command: ' + cmd) if not shell: cmd = shlex.split(cmd) @@ -291,6 +298,21 @@ def is_url(s): return parsed.scheme != '' and parsed.netloc != '' +def git_branch_hash(branch='HEAD', short=True): + '''Gets the SHA1 hash of the given git branch.''' + try: + completed = run_command( + 'git rev-parse %s %s' % ('--short' if short else '', branch), + check=True) + except SpawnedProcessError: + return 'N/A' + + if completed.stdout: + return completed.stdout.strip() + + return 'N/A' + + def git_clone(url, targetdir=None): '''Clone git repository from a URL.''' if not git_repo_exists(url): diff --git a/unittests/test_utility.py b/unittests/test_utility.py index be11774fa7..f90a4db274 100644 --- a/unittests/test_utility.py +++ b/unittests/test_utility.py @@ -174,6 +174,13 @@ def test_is_url(self): self.assertTrue(os_ext.is_url(repo_https)) self.assertFalse(os_ext.is_url(repo_ssh)) + def test_git_branch_hash(self): + # A git branch hash consists of 8(short) or 40 characters. + assert len(os_ext.git_branch_hash()) == 8 + assert len(os_ext.git_branch_hash(short=False)) == 40 + assert os_ext.git_branch_hash(branch='invalid') == 'N/A' + assert os_ext.git_branch_hash(branch='') == 'N/A' + def test_git_repo_exists(self): self.assertTrue(os_ext.git_repo_exists( 'https://github.com/eth-cscs/reframe.git', timeout=3)) From 8a582d2cffc399b465f4b6f114291720d23fe37c Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Thu, 19 Dec 2019 13:01:58 +0100 Subject: [PATCH 2/2] Improve function for retrieving the Git repo hash - Retrieve repo hash from ReFrame's install prefix always. This will print the hash even in cases that you call reframe from an unrelated directory. - Add function for retrieving the framework's version that appends the hash if this can also be determined. - Adapt `version` logging variable to use also the repo hash if available. --- reframe/core/logging.py | 2 +- reframe/frontend/cli.py | 2 +- reframe/utility/os_ext.py | 64 +++++++++++++++++++++++++++++---------- unittests/test_utility.py | 10 +++--- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/reframe/core/logging.py b/reframe/core/logging.py index 1b021246cf..909bbd742b 100644 --- a/reframe/core/logging.py +++ b/reframe/core/logging.py @@ -384,7 +384,7 @@ def __init__(self, logger=None, check=None): 'osuser': os_ext.osuser() or '', 'osgroup': os_ext.osgroup() or '', 'check_tags': None, - 'version': reframe.VERSION, + 'version': os_ext.reframe_version(), } ) self.check = check diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py index c3a1a0815d..c0ed56e9f4 100644 --- a/reframe/frontend/cli.py +++ b/reframe/frontend/cli.py @@ -246,7 +246,7 @@ def main(): '(default format "%%FT%%T")' ) misc_options.add_argument('-V', '--version', action='version', - version=reframe.VERSION) + version=os_ext.reframe_version()) misc_options.add_argument('-v', '--verbose', action='count', default=0, help='Increase verbosity level of output') diff --git a/reframe/utility/os_ext.py b/reframe/utility/os_ext.py index e35ad18830..74cee1a614 100644 --- a/reframe/utility/os_ext.py +++ b/reframe/utility/os_ext.py @@ -16,6 +16,7 @@ import tempfile from urllib.parse import urlparse +import reframe from reframe.core.exceptions import (ReframeError, SpawnedProcessError, SpawnedProcessTimeout) @@ -294,22 +295,6 @@ def is_url(s): return parsed.scheme != '' and parsed.netloc != '' -def git_branch_hash(branch='HEAD', short=True): - '''Return the SHA1 hash of the given git branch. - - Current working directory must be a git repository. - ''' - try: - completed = run_command( - 'git rev-parse %s %s' % ('--short' if short else '', branch), - check=True - ) - except SpawnedProcessError: - return 'N/A' - - return completed.stdout.strip() - - def git_clone(url, targetdir=None): '''Clone git repository from a URL.''' if not git_repo_exists(url): @@ -331,6 +316,53 @@ def git_repo_exists(url, timeout=5): return True +def git_repo_hash(branch='HEAD', short=True, wd=None): + '''Return the SHA1 hash of a git repository. + + :arg branch: The branch to look at. + :arg short: Return a short hash. This always corresponds to the first 8 + characters of the long hash. We don't rely on Git for the short hash, + since depending on the version it might return either 7 or 8 + characters. + :arg wd: Change to this directory before retrieving the hash. If ``None``, + ReFrame's install prefix will be used. + :returns: The repository has or ``None`` if the hash could not be + retrieved. + + ''' + try: + wd = wd or reframe.INSTALL_PREFIX + with change_dir(wd): + # Do not log this command, since we need to call this function + # from the logger + completed = run_command('git rev-parse %s' % branch, + check=True, log=False) + + except SpawnedProcessError: + return None + + hash = completed.stdout.strip() + if hash: + return hash[:8] if short else hash + else: + return None + + +def reframe_version(): + '''Return ReFrame version. + + If ReFrame's installation contains the repository metadata, the + repository's hash will be appended to the actual version. + + ''' + version = reframe.VERSION + repo_hash = git_repo_hash() + if repo_hash: + return '%s (rev: %s)' % (version, repo_hash) + else: + return version + + def expandvars(path): '''Expand environment variables in ``path`` and perform any command substitution diff --git a/unittests/test_utility.py b/unittests/test_utility.py index f90a4db274..e465885a1b 100644 --- a/unittests/test_utility.py +++ b/unittests/test_utility.py @@ -174,12 +174,12 @@ def test_is_url(self): self.assertTrue(os_ext.is_url(repo_https)) self.assertFalse(os_ext.is_url(repo_ssh)) - def test_git_branch_hash(self): + def test_git_repo_hash(self): # A git branch hash consists of 8(short) or 40 characters. - assert len(os_ext.git_branch_hash()) == 8 - assert len(os_ext.git_branch_hash(short=False)) == 40 - assert os_ext.git_branch_hash(branch='invalid') == 'N/A' - assert os_ext.git_branch_hash(branch='') == 'N/A' + assert len(os_ext.git_repo_hash()) == 8 + assert len(os_ext.git_repo_hash(short=False)) == 40 + assert os_ext.git_repo_hash(branch='invalid') is None + assert os_ext.git_repo_hash(branch='') is None def test_git_repo_exists(self): self.assertTrue(os_ext.git_repo_exists(