From 9a4778186b47149cddc5f3223ddcadb65a333abb Mon Sep 17 00:00:00 2001 From: Shane Stafford Date: Fri, 10 Oct 2014 11:53:40 -0600 Subject: [PATCH] Add detailed version info for Apps and framework. Addresses issue #4026. Finds detailed version information for repos in SVN, git, or git-svn. Auto-generates revision header files for the apps and framework. Prints framework revision. (Apps can print their own version info using the generated header.) --- .gitignore | 2 +- framework/app.mk | 9 +- framework/moose.mk | 13 +- framework/scripts/get_repo_revision.py | 183 ++++++++++++------------- framework/src/utils/SystemInfo.C | 6 +- 5 files changed, 106 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index 9f9b58979d8c..80126d6768a0 100644 --- a/.gitignore +++ b/.gitignore @@ -115,7 +115,7 @@ peacock_run_tmp.i yaml_dump* # Generated header file -HerdRevision.h +MooseRevision.h # Precompiled headers moose/include/base/Precompiled.h.gch diff --git a/framework/app.mk b/framework/app.mk index dfc747446c21..df186847d942 100644 --- a/framework/app.mk +++ b/framework/app.mk @@ -72,10 +72,17 @@ app_DIRS += $(APPLICATION_DIR) # dependencies -include $(app_deps) +# Write a revision header only if the app supplies the location. +app_revision: +ifdef APP_REV_HEADER + $(shell $(FRAMEWORK_DIR)/scripts/get_repo_revision.py $(APPLICATION_DIR) \ + $(APP_REV_HEADER) $(APPLICATION_NAME)) +endif + ############################################################################### # Build Rules: # -all:: $(app_LIB) +all:: app_revision $(app_LIB) ifeq ($(BUILD_EXEC),yes) all:: $(app_EXEC) endif diff --git a/framework/moose.mk b/framework/moose.mk index b6cbb861362b..674a7506ca81 100644 --- a/framework/moose.mk +++ b/framework/moose.mk @@ -49,20 +49,19 @@ moose_deps := $(patsubst %.C, %.$(obj-suffix).d, $(moose_srcfiles)) \ # clang static analyzer files moose_analyzer := $(patsubst %.C, %.plist.$(obj-suffix), $(moose_srcfiles)) -# revision header -revision_header = $(FRAMEWORK_DIR)/include/base/HerdRevision.h - app_INCLUDES := $(moose_INCLUDE) app_LIBS := $(moose_LIBS) app_DIRS := $(FRAMEWORK_DIR) -all:: herd_revision moose +all:: moose_revision moose -herd_revision: - $(shell $(FRAMEWORK_DIR)/scripts/get_repo_revision.py $(FRAMEWORK_DIR)) +# revision header +moose_revision_header = $(FRAMEWORK_DIR)/include/base/MooseRevision.h +moose_revision: + $(shell $(FRAMEWORK_DIR)/scripts/get_repo_revision.py $(FRAMEWORK_DIR) \ + $(moose_revision_header) MOOSE) moose: $(moose_LIB) - # [JWP] With libtool, there is only one link command, it should work whether you are creating # shared or static libraries, and it should be portable across Linux and Mac... $(pcre_LIB): $(pcre_objects) diff --git a/framework/scripts/get_repo_revision.py b/framework/scripts/get_repo_revision.py index a32f1a47773b..8ba13885171b 100755 --- a/framework/scripts/get_repo_revision.py +++ b/framework/scripts/get_repo_revision.py @@ -5,109 +5,104 @@ import subprocess, os, sys, re -def findRepoRevision(moose_dir): - apps_file = '.gitignore' - revision = "" - vcs = 'SVN' - - # Locate the .build_apps file - found_it = False - apps_dir = os.getcwd() - - # Search at most 4 directories up from where we are located - for i in range(4): - if os.path.exists(os.path.join(apps_dir, apps_file)): - found_it = True - break - apps_dir = os.path.join(apps_dir, '..') - - if not found_it: - # We need to see if we are in a git repo - p = subprocess.Popen('git rev-parse --show-cdup', stdout=subprocess.PIPE, stderr=None, shell=True) - p.wait() - if p.returncode == 0: - git_dir = p.communicate()[0] - app_dir = os.path.abspath(os.path.join(os.getcwd(), git_dir)) - - return revision # blank string - - # At this point apps_dir should contain the root of the repository - - # See if this is an SVN checkout - regex = '' - if os.path.exists(os.path.join(apps_dir, '.git')): - # See if this git project has a SVN remote - saved_dir = os.getcwd() - os.chdir(apps_dir) - srre=re.compile('svn-remote') - p = subprocess.Popen('git config -l', stdout=subprocess.PIPE, shell=True, stderr=None) - buffer = p.communicate()[0] - os.chdir(saved_dir) - m = srre.search(str(buffer)) - if m != None: - # It has a SVN remote -- get the ID from the svn commit - command = 'git svn log --limit 1' - regex = re.compile(r'r(\d+)') - else: - # It doesn't have a SVN remote -- get the git commit id - command = 'git log -n 1 --pretty="%h"' - regex = re.compile(r'^(\S+)') - vcs = 'GIT' - elif os.path.exists(apps_dir + '.svn'): - command = 'svnversion .' - regex = re.compile(r'(\d+)\w*$') - else: - return revision # blank string - - saved_dir = os.getcwd() - # Change current working directory (this is necessary for braindead SVN) - os.chdir(apps_dir) - # Get the revision from the log - p = subprocess.Popen([command], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - buffer = p.communicate()[0] - # Restore current working directory - os.chdir(saved_dir) - - # find the revision - m = regex.search(str(buffer)) - if m != None: - revision = m.group(1) - if vcs == 'GIT': - revision = '"'+revision+'"' - return revision - - -def writeRevision(moose_dir, revision): - # see if the revision is different - revision_file = moose_dir + '/include/base/HerdRevision.h' - # We have to have something listed as a revision if we didn't find one (i.e revision is blank) - if revision == "": - revision = '"N/A"'; +def shellCommand( command, cwd=None ): + return subprocess.check_output( command, shell=True, stderr=subprocess.STDOUT, cwd=cwd ) + + +def gitVersionString( cwd=None ): + SHA1 = '' + date = '' + try: + # The SHA1 and date should always be available if we have a git repo. + SHA1 = shellCommand( 'git show -s --format=%h', cwd ).strip() + date = shellCommand( 'git show -s --format=%ci', cwd ).split()[0] + except subprocess.CalledProcessError: + return None + + # The tag check will always succeed if the repo starts with a v0.0 tag. To find only tags that + # were part of the first parent, use --first-parent. + tag = '' + try: + description = shellCommand( 'git describe --tags --long --match "v[0-9]*"', cwd ).rsplit('-',2) + tag = description[0] + ', ' + commitsSinceTag = description[1] + if commitsSinceTag != '0': + tag = 'derived from ' + tag + except subprocess.CalledProcessError: + pass + return tag + "git commit " + SHA1 + " on " + date + + +def gitSvnVersionString( cwd=None ): + try: + date = shellCommand( 'git show -s --format=%ci', cwd ).split()[0] + revision = shellCommand( 'git svn find-rev $(git log --max-count 1 --pretty=format:%H)', cwd ).strip() + if len( revision ) > 0 and len( revision ) < 10: + return 'svn revision ' + revision + " on " + date + except subprocess.CalledProcessError: + pass + return None + + +def svnVersionString( cwd=None ): + try: + revisionString = shellCommand( 'svnversion .', cwd ) + matchingRevision = re.search( r'\d+', revisionString ) + if matchingRevision is not None: + return 'svn revision ' + matchingRevision.group(0) + except subprocess.CalledProcessError: + pass + return None + + +def repoVersionString( cwd=None ): + version = svnVersionString( cwd ) + if version is None: + version = gitSvnVersionString( cwd ) + if version is None: + version = gitVersionString( cwd ) + if version is None: + version = "unknown" + return version + + +def writeRevision( app_name, app_revision, revision_header ): + # Use all caps for app name (by convention). + app_definition = app_name.upper() + '_REVISION' - revision_changed = True - if os.path.exists(revision_file): - f = open(revision_file, "r") + # see if the revision is different + revision_changed = False + if os.path.exists(revision_header): + f = open(revision_header, "r") buffer = f.read() - m = re.search(r'HERD_REVISION (\S+)', buffer) - existing_revision = "" - if m != None: - existing_revision = m.group(1) + m = re.search( re.escape( app_definition) + r' "([^"]*)"',buffer ) + if m is not None and m.group(1) != app_revision: + revision_changed = True - if revision == existing_revision: - revision_changed = False f.close() + else: + # Count it as changed if the header does not exist. + revision_changed = True if revision_changed: - f = open(revision_file, "w") - f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n") - f.write("#ifndef HERDREVISION_H\n#define HERDREVISION_H\n\n#define HERD_REVISION " + revision + "\n\n#endif //HERDREVISION_H\n") + f = open(revision_header, "w") + f.write( '/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n' \ + '\n' + '#ifndef ' + app_definition + '_H\n' + '#define ' + app_definition + '_H\n' + '\n' + '#define ' + app_definition + ' "' + app_revision + '"\n' + '\n' + '#endif // ' + app_definition + '_H\n') f.close() # Entry point -if len(sys.argv) == 2: - moose_dir = sys.argv[1] - revision = findRepoRevision(moose_dir) +if len(sys.argv) == 4: + repo_location = sys.argv[1] + header_file = sys.argv[2] + app_name = sys.argv[3] - writeRevision(moose_dir, revision) + revision = repoVersionString( repo_location ) + writeRevision( app_name, revision, header_file ) diff --git a/framework/src/utils/SystemInfo.C b/framework/src/utils/SystemInfo.C index d843ef647fb7..7bd3a093c9d8 100644 --- a/framework/src/utils/SystemInfo.C +++ b/framework/src/utils/SystemInfo.C @@ -14,7 +14,7 @@ #include "SystemInfo.h" #include "ExecutablePath.h" -#include "HerdRevision.h" ///< This file is auto-generated and contains the revisions +#include "MooseRevision.h" ///< This file is auto-generated and contains the revision #include "libmesh/libmesh_config.h" @@ -37,10 +37,8 @@ SystemInfo::getInfo() { std::stringstream oss; oss << std::left; - - // Repository Revision oss << "Framework Information:\n"; - oss << std::setw(25) << "Version: " << HERD_REVISION << "\n"; + oss << std::setw(25) << "MOOSE version: " << MOOSE_REVISION << "\n"; #ifdef LIBMESH_DETECTED_PETSC_VERSION_MAJOR oss << std::setw(25) << "PETSc Version: " << LIBMESH_DETECTED_PETSC_VERSION_MAJOR << '.'