I had this idea of generating version information for a Python script that uses ArgParse. The code is a little more than I was expecting but I think it works well. Here is the code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
import os | |
import re | |
import sys | |
import logging | |
import argparse | |
import datetime | |
import subprocess | |
def run(cmd): | |
(rc, stdout, stderr) = (None, '', '') | |
if isinstance(cmd, basestring): | |
cmd = cmd.split() | |
try: | |
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
except Exception as e: | |
log.debug('Ignoring `{e!s}` from {cmd}'.format(**locals())) | |
else: | |
(stdout, stderr) = p.communicate() | |
rc = p.wait() | |
log.debug('{cmd}: {rc}, {stdout!r}, {stderr!r}'.format(**locals())) | |
if (rc == 0) and (not stdout): | |
rc = None | |
return (rc, stdout, stderr) | |
def get_version(): | |
git_used = False | |
ret = '?' | |
dir = os.path.dirname(sys.argv[0]) | |
base = os.path.basename(sys.argv[0]) | |
cwd = os.getcwd() | |
try: | |
os.chdir(dir) | |
except: | |
pass | |
else: | |
(rc, stdout, stderr) = run(['git', 'log', '-1', base]) | |
""" | |
commit {SHA1} | |
Author: {FIRST_NAME} {LAST_NAME} <{EMAIL_ADDRESS}> | |
Date: Wed Jan 16 09:32:03 2019 -0500 | |
. | |
. | |
. | |
""" | |
match = re.search(r'^commit\s+(\S+).*\nDate:\s+(([A-Z][a-z]{2} ){2}[ 0123]\d (\d{2}:){2}\d{2} \d{4})', stdout, re.DOTALL) | |
log.debug('`git log 0` search groups: {groups}'.format(groups=match.groups() if match else None)) | |
if match: | |
commit = match.group(1)[:6] | |
timestamp = datetime.datetime.strptime(match.group(2), '%a %b %d %H:%M:%S %Y') | |
log.debug('timestamp: {timestamp!s}'.format(**locals())) | |
(rc, stdout, stderr) = run('git branch') | |
match = re.search(r'\*\s(\S+)', stdout, re.DOTALL) | |
log.debug('`git branch` search groups: {groups}'.format(groups=match.groups() if match else None)) | |
if match: | |
branch = match.group(1) | |
(rc, stdout, stderr) = run('git remote -v') | |
""" | |
origin https://github.com/pfuntner/gists.git (fetch) | |
""" | |
hits = list(re.finditer(r'(\S+)\s(https?://\S+)\s\(fetch\)', stdout)) | |
log.debug('`git remote -v` hits: {hits}'.format(hits=[hit.groups() for hit in hits])) | |
if hits: | |
hits = ['{name}:{url}'.format(name=hit.group(1), url=hit.group(2)) for hit in hits] | |
ret = '{commit}, {branch}, {timestamp!s}, {hits}'.format(**locals()) | |
git_used = True | |
os.chdir(cwd) | |
if not git_used: | |
ret = str(datetime.datetime.fromtimestamp(os.path.getmtime(sys.argv[0]))) | |
return ret | |
logging.basicConfig(format='%(asctime)s %(levelname)s %(pathname)s:%(lineno)d %(msg)s') | |
log = logging.getLogger() | |
log.setLevel(logging.WARNING) | |
parser = argparse.ArgumentParser(description='Example of doing a nifty --version') | |
parser.add_argument('-v', '--verbose', dest='verbose', action='count', help='Print more messages') | |
parser.add_argument('--version', action='version', version=get_version(), help='See wonderful version information') | |
args = parser.parse_args() | |
log.setLevel(logging.WARNING - (args.verbose or 0) * 10) | |
# print get_version() |
Usage
Here is an example of its usage if the script is part of a git repository:
$ ./version-example --version b92798, master, 2019-01-18 10:35:02, ['origin:https://github.com/pfuntner/gists.git'] $
It contains:
- The SHA1 of last git commit that changed the script
- The current branch of the repository
- The date of the commit - I think the timezone element is present in this but I didn't want to deal with timezones so I'm ignoring it
- A list of the remote repositories
This is printed on two lines but that's something that ArgParse is doing, not me.
Here is an example of its usage if the script is not part of a git repository - we don't have much information to work from but we can at least get the timestamp of the script:
$ ~/tmp/version-example --version 2019-01-18 11:07:33.873846 $
You'll also get this output if the script is in the repository directory but hasn't been committed to it.
Comments
Post a Comment