Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion reframe/core/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def __init__(self, logger=None, check=None):
'osuser': os_ext.osuser() or '<unknown>',
'osgroup': os_ext.osgroup() or '<unknown>',
'check_tags': None,
'version': reframe.VERSION,
'version': os_ext.reframe_version(),
}
)
self.check = check
Expand Down
2 changes: 1 addition & 1 deletion reframe/frontend/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down
50 changes: 49 additions & 1 deletion reframe/utility/os_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
import shlex
import shutil
import signal
import sys
import subprocess
import tempfile
from urllib.parse import urlparse

import reframe
from reframe.core.exceptions import (ReframeError, SpawnedProcessError,
SpawnedProcessTimeout)

Expand Down Expand Up @@ -68,7 +70,6 @@ def run_command_async(cmd,
shell=False,
log=True,
**popen_args):
# Import logger here to avoid unnecessary circular dependencies
if log:
from reframe.core.logging import getlogger
getlogger().debug('executing OS command: ' + cmd)
Expand Down Expand Up @@ -315,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
Expand Down
7 changes: 7 additions & 0 deletions unittests/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_repo_hash(self):
# A git branch hash consists of 8(short) or 40 characters.
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(
'https://github.com/eth-cscs/reframe.git', timeout=3))
Expand Down