#!/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:])