blob: c226313395143dfc6d229c5487e6f59773be8fed [file] [log] [blame]
#!/usr/bin/env python3
#--------------------------------------------------------------------
#
# save_commit_refs.py
#
# This file is used to annotate a standard tech information JSON
# file. Each JSON file should have a section called "reference"
# (if not, this script exits without doing anything). The
# "reference" section contains the commit hashes of repositories
# used by the developer for generating the PDK, creating a
# reference against which issues can be compared. The "reference"
# section is fixed and is not modified by replacement like the
# rest of the JSON file. It is the duty of the PDK developer to
# update the references section periodically by running "make
# reference".
#
#--------------------------------------------------------------------
# Usage:
#
# save_commit_refs.py <filename> [-D<variable> ...]
#
# Where <filename> is the name of a technology JSON file, and
# <variable> may be a <keyword>=<hash_value> pair only.
# <keyword> corresponds to the variable name in a technology Makefile
# for a commit hash that appears somewhere in <filename>. <value>
# is the commit hash value corresponding to <keyword>.
#
# The JSON file "reference" section is expected to have entries of
# the form
# "<name>": "<commit_hash>"
#
# where <name> must also appear elsewhere in <filename> in an entry
# of the form
# "<name>": "<keyword>"
#
# Then, where "-D<keyword>=<hash_value>" has been passed to the
# script on the command line, the entry in the "reference" section
# is changed by replacing "<commit_hash>" with "<hash_value>".
#
# The output of the script overwrites <filename> with the modified
# contents.
#
# Example:
# sky130.json has an entry in "reference":
# "magic": "fe2eb6d3906ed15ade0e7a51daea80dd4e3846e2"
# reflecting the git commit number of the program "magic" at
# the time the developer last ran save_commit_refs.py.
# Elsewhere in sky130.json, the following line appears:
# "magic": "MAGIC_COMMIT"
# If save_commit_refs.py is called as:
# save_commit_refs.py sky130.json -DMAGIC_COMMIT=abcdef
# then the line in "reference" will be changed to:
# "magic": "abcdef"
#
#--------------------------------------------------------------------
import os
import re
import sys
def runsubs(keys, defines, inputfile, outputfile):
ifile = False
ifile = open(inputfile, 'r')
if not ifile:
print("Error: Cannot open file " + inputfile + " for reading.\n", file=sys.stderr)
return
indist = False
filetext = ifile.readlines()
lastline = []
# Input file has been read, so close it.
ifile.close()
# Open output file
if not outputfile:
outputfile = inputfile
ofile = open(outputfile, 'w')
if not ofile:
print("Error: Cannot open file " + outputfile + " for writing.\n", file=sys.stderr)
return
keyrex = re.compile('[ \t]*"([^"]+)":[ \t]*"[^"]+"')
valuerex = re.compile('[ \t]*"[^"]+":[ \t]*"([a-z0-9]+)"')
distdefs = {}
defs = []
for line in filetext:
newline = line
if indist == False:
if '"reference":' in line:
indist = True
else:
# Find values matching keywords
for key in keys:
if key in line:
kmatch = keyrex.match(line)
if kmatch:
print('Found match "' + kmatch.group(1) + '" for key "' + key + '"')
distdefs[kmatch.group(1)] = defines[key]
defs.append(kmatch.group(1))
else:
# Find definitions matching keywords
for defx in defs:
if defx in line:
vmatch = valuerex.match(line)
if vmatch:
value = distdefs[defx]
newline = line.replace(vmatch.group(1), value)
print(newline, file=ofile, end='')
ofile.close()
return
def printusage(progname):
print('Usage: ' + progname + ' filename [-options]')
print(' Options are:')
print(' -help Print this help text.')
print(' -quiet Stop without error if input file is not found.')
print(' -ccomm Remove C comments in /* ... */ delimiters.')
print(' -D<def> Define word <def> and set its value to 1.')
print(' -D<def>=<val> Define word <def> and set its value to <val>.')
print(' -I<dir> Add <dir> to search path for input files.')
return
if __name__ == '__main__':
# Parse command line for options and arguments
options = []
arguments = []
for item in sys.argv[1:]:
if item.find('-', 0) == 0:
options.append(item)
else:
arguments.append(item)
if len(arguments) > 0:
inputfile = arguments[0]
if len(arguments) > 1:
outputfile = arguments[1]
else:
outputfile = []
else:
printusage(sys.argv[0])
sys.exit(0)
defines = {}
keys = []
for item in options:
result = item.split('=')
if result[0] == '-help':
printusage(sys.argv[0])
sys.exit(0)
elif result[0][0:2] == '-D':
keyword = result[0][2:]
value = result[1]
defines[keyword] = value
keys.append(keyword)
else:
print('Bad option ' + item + ', options are -help, -D<def>\n')
sys.exit(1)
if not os.path.isfile(inputfile):
if not quiet:
print("Error: No input file " + inputfile + " found.")
else:
sys.exit(0)
runsubs(keys, defines, inputfile, outputfile)
# Set mode of outputfile to be equal to that of inputfile (if not stdout)
if outputfile:
statinfo = os.stat(inputfile)
mode = statinfo.st_mode
os.chmod(outputfile, mode)
sys.exit(0)