#!/usr/bin/python
import re
import os
import sys
import getopt
import marshal
import logging
from subprocess import Popen, PIPE, STDOUT
#######################################################################
#### MODIFY THESE VARIABLES AS APPROPRIATE
p4port="localhost:1666"
p4user="p4admin"
p4="/p4/common/bin/p4"
passfile="/p4/common/bin/adminpass"
triggerFile="/p4/common/bin/triggers/SubmitTagger.py"
#######################################################################
#to make a re pattern we use a string
tagPattern = "#[A-Za-z0-9_-]+"
## GLOBALS
g_currentClient = None
g_changeId = 0
# usage
def usage():
PROGRAM_USAGE = """\
Usage: SubmitTagger.py [-h] [-l logfile] [-v] -c changelist_number
-h = show help (this message)
-v = verbose (debug mode)
-l logfile = specify logfile (default is STDOUT)
-c changelist_number = the changelist to check -- this should be a submitted changelist
To install as a trigger, add the following to your triggers table:
SUBMIT.tagger change-commit //... \"{0} -c %change%\"
""".format(triggerFile)
print(PROGRAM_USAGE)
sys.exit(0)
# errorExit
# Exit with error messages
def errorExit(*msg):
logging.error(*msg)
exit()
# exit
# exit with error
def exit(*msg):
for m in msg:
logging.info(m)
logging.info("*** SUBMIT_TRIGGER FINISHED ***")
raise SystemExit()
# p4MarshalCmd
# executes the p4 command, results sent to a list
def p4MarshalCmd(cmd,quiet=False):
if not quiet:
logging.debug("p4 {0}".format(" ".join(cmd)))
list = []
pipe = Popen([p4, "-p", p4port, "-u", p4user, "-G"] + cmd, stdout=PIPE).stdout
try:
while 1:
record = marshal.load(pipe)
list.append(record)
except EOFError:
pass
pipe.close()
return list
# p4InputCmd
# executes the p4 command with input
def p4InputCmd(data,cmd,quiet=False):
if not quiet:
logging.debug("p4 {0}".format(" ".join(cmd)))
list = []
proc = Popen([p4, "-p", p4port, "-u", p4user, "-G"] + cmd, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
result = proc.communicate(input=data)[0]
return result
# p4Cmd
# executes a p4 command, returns results
def p4Cmd(cmd,quiet=False):
if not quiet:
logging.debug("p4 {0}".format(" ".join(cmd)))
proc = Popen([p4, "-p", p4port, "-u", p4user] + cmd,stdout=PIPE)
result = proc.communicate()[0]
return result
# containsError
# utility function to check for any error code in the results array
def containsError(results=[],logError=True):
foundError = False
for r in results:
if 'code' in r:
if r['code'] == 'error':
foundError = True
if logError:
logging.error(r['data'].strip())
elif r['code'] == 'info':
#code info output can be important in troubleshooting
logging.debug(r['data'])
return foundError
def addTag(depotPath, revision, tag):
# first get the current tags (if any)
results = p4MarshalCmd(["fstat", "-Oa", "{0}#{1}".format(depotPath, revision)])
if containsError(results):
errorExit("error while running fstat")
fstat = results[0]
tags = []
# check for the tags attribute on the file
if "attr-tags" in fstat:
tags = fstat['attr-tags'].split(',')
# check to see if the tag is already there, and add it if not
if not tag in tags:
tags.append(tag)
else:
tags.append(tag)
p4Cmd(["attribute", "-f", "-n", "tags", "-v", ",".join(tags), "{0}#{1}".format(depotPath, revision)])
def checkForTags():
results = p4MarshalCmd(["change","-o", g_changeId])
if containsError(results):
errorExit("error while retrieving change")
changeSpec = results[0]
tags = re.findall(tagPattern, changeSpec['Description'])
if(len(tags) > 0):
for tag in tags:
results = p4MarshalCmd(["describe", g_changeId])
changeDesc = results[0]
for k in sorted(changeDesc.keys()):
if(k.startswith("depotFile")):
r = re.search(r'\d+', k).group()
addTag(changeDesc[k], changeDesc["rev" + r], tag.replace("#",""))
else:
logging.debug("no tags found in changelist")
# checkLogin
# check the login ticket on the server
def checkLogin(username=""):
cmd = ["login","-s"]
result = p4MarshalCmd(cmd,quiet=True)
if containsError(result, False):
return False
else:
return True
def login():
if passfile is not None and os.path.isfile(passfile):
f = open(passfile)
lines = f.readlines()
f.close()
adminpass = lines[0].strip()
logging.debug("adminpass = " + adminpass)
cmd = ["login"]
result = p4InputCmd(adminpass, cmd)
if(containsError(result)):
return False
else:
return True
else:
return False
###########################################################################
##### MAIN PROGRAM STARTS HERE
#####
def main(argv=None):
global g_changeId
verbose = False
logFile = None
try:
opts, args = getopt.getopt(argv, "hl:c:v")
for opt, arg in opts:
if opt == "-v":
verbose = True
elif opt == "-h":
usage()
elif opt == "-l":
logFile = arg
elif opt == "-c":
g_changeId = arg
if(g_changeId == 0):
print("ERROR: changelist is required\n")
usage()
sys.exit(3)
logLevel = logging.WARN
if verbose:
logLevel = logging.DEBUG
if logFile is not None:
logging.basicConfig(filename=logFile, format='%(asctime)s [%(levelname)s] %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logLevel)
else:
logging.basicConfig(format='[%(levelname)s] %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logLevel)
if not checkLogin():
if not login():
errorExit("Not logged in")
checkForTags()
sys.exit(0)
except getopt.GetoptError:
print("ERROR: unknown argument\n")
usage()
sys.exit(2)
if __name__ == '__main__':
main(sys.argv[1:])