#!/usr/local/bin/python """A perforce trigger to verify changes against a regular expression. Usage: checkfor.py pattern %changelist% %serverport% [ %user% user|group ... ] The basic test is to list each opened file being submitted, and see if it matches against the given pattern. If any files fail to match, the submit is failed and the failing files are listed in the results. If %user% is given, it is checked against the list of group|users. If a match occurs, then the test of opened files is skipped. If no match is found, then the list of of group|user names is checked for groups, and each group found is checked to see if %user% is a member. If %user% is a member of any group, the again, the test of opened files is skipped. This allows the trigger mechanism to enhance the protection mechanism. Simple policy enforcement wouldn't use the use facilities. To require that any changes to some set of files be integrations, you can do: checkfor.py ' - (integrate|branch) change ' %changelist% %serverport% Using the user facilities lets you extend the protection mechanisms provided by Perforce. For example, to allow only people in the group publishers to add files to a set of files, while anyone can edit existing files, you can do: checkfor.py '- edit change ' %changelist% %serverport% %user% publishers There are two potential problems. 1) A change that includes files outside the area you want to check may fail when it shouldn't. Checkfor doesn't know what files it should apply to, so it just checks them all. 2) That users & groups are overloaded creates some security holes. Copyright 1999, Mike Meyer. All Rights Reserved See the comment in the source for redistribution permission. """ # License: # This file and any derivatives or translations of it may be freely # copied and redistributed so long as: # 1) This license and copyright notice are not changed. # 2) Any fixes or enhancements are reported back to either the # author (mwm@phone.net). # and any of: # a) The source is redistributed with it. # b) The source is compiled unmodified, and instructions for finding # the original source are included. # c) The source is made available by some other means. import sys, string, re from P4Client import P4Client class config: "A place to hang config info" user = 'Perforce' # Perforce user name to use class checker: "ClientUser class to test each info call against a pattern" def __init__(my): "Init the object with a list of files that failed." my.bad = [] my.good = [] my.error = "" def Set_Pattern(my, test): "Init the pattern for the test." my.test = re.compile(test) def OutputInfo(my, text, level): "Test the incoming line, saving it if it's bad." if not my.test.search(text): my.bad.append(text) else: my.good.append(text) def HandleError(my, text, level = None): "Save error messages as well." my.error = my.error + text OutputError = HandleError if __name__ == '__main__': (name, test, change, port) = sys.argv[:4] userlist = sys.argv[4:] user = None if userlist: user = userlist[0] del userlist[0] for name in userlist: if name == user: sys.exit(0) # privileged user check = checker() p4 = P4Client(check, User = user or config.user, Port = port) p4.Init() if userlist: check.Set_Pattern('^#') p4.SetArgv(()) p4.Run('groups') groups = check.bad check.bad = [] check.Set_Pattern(r'(?m)^\t%s$' % user) for group in userlist: if not group in groups: continue if p4.Dropped(): break p4.SetArgv(('-o', group)) p4.Run('group') if check.error or check.good or p4.Dropped(): if check.error or check.good: p4.Final() if check.error: print check.error if check.good: sys.exit(0) # privileged group sys.exit(1) check.bad = [] check.Set_Pattern(test) p4.SetArgv(('-a', '-c', change)) p4.Run('opened') p4.Final() if check.error: print check.error sys.exit(1) if check.bad: print "The following files were not a", test print string.join(check.bad, '\n') sys.exit(1) sys.exit(0)