Skip to content

Instantly share code, notes, and snippets.

@bbengfort
Last active June 7, 2018 11:58
Show Gist options
  • Save bbengfort/d747ea6806366c21cd34 to your computer and use it in GitHub Desktop.
Save bbengfort/d747ea6806366c21cd34 to your computer and use it in GitHub Desktop.
Scans the local directory if it's a git repository and adds the ID line to all header comments.
#!/usr/bin/env python
# ID: versid.py [] benjamin@bengfort.com $
import re
import os
import git
import fileinput
IDRE = re.compile(r'^#\s*ID:\s+([\w\.\-]+)\s+\[([a-f0-8]*)\]\s+([\w\@\.\+\-]*)\s+\$\s*$', re.I)
def versionize(path, branch='master', num_lines=20, modify=False):
"""
Primary utility for performing the versionization.
"""
try:
path = os.path.abspath(path)
if not os.path.isdir(path):
raise Exception("'{}' is not a directory!".format(path))
repo = git.Repo(path)
except git.InvalidGitRepositoryError:
raise Exception("'{}' is not a Git repository!".format(path))
# Construct the path version tree.
versions = {}
for commit in repo.iter_commits(branch):
for blob in commit.tree.traverse():
versions[blob.abspath] = commit
# Track required modifications
output = []
# Walk the directory path
for root, dirs, files in os.walk(path):
# Ignore hidden directories (.git)
dirs[:] = [d for d in dirs if not d.startswith('.')]
for name in files:
name = os.path.join(root, name)
if name not in versions: continue
output.append(
read_head(name, versions[name], maxlines=num_lines)
)
# Remove any non-matched files.
output = filter(None, output)
# Make the modifications if the args specifies to
if modify:
for path, vers in output:
modify_inplace(path, vers)
# Return the output
return [
"{} {}".format(path, vers)
for path, vers in output
] if output else ["No files require an ID header."]
def read_head(path, commit, maxlines=None):
"""
Reads the first maxlines of the file (or all lines if None) and looks
for the version string. If it exists, it replaces it with the commit
and author information.
"""
with open(path, 'r') as f:
for idx, line in enumerate(f.readlines()):
if maxlines and idx >= maxlines:
break
match = IDRE.match(line)
if match and not match.groups()[1]:
vers = "# ID: {} [{}] {} $".format(
os.path.basename(path), commit.hexsha[:7], commit.author.email
)
return path, vers
def modify_inplace(path, vers):
"""
Modifies the ID line by writing all lines except the match line.
"""
matched = False
for line in fileinput.input(path, inplace=1):
if not matched and IDRE.match(line):
matched = True
sys.stdout.write(vers + "\n")
else:
sys.stdout.write(line)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment