Perforce is a wily beast. A lot of companies use it, but I feel few outside of the IT department really have to deal with it much. As I work myself deeper and deeper into the damp hole that is asset validation, I have really been writing a lot of python to deal with certain issues; but always scripts that work from the outside.
Perforce has a system that allows you to write scripts that are run, server side, when any number of events are triggered. You can use many scripting languages, but I will only touch on Python.
To follow along here, you should set up a test environment. Perforce is freely downloadable, and free to use with 2 users. Of course you are going to need python, and p4python. So get your server running and add two users, a user and an administrator.
Your First Trigger
Let’s create the simplest python script. It will be a submit trigger that says ‘Hello World’ then passes or fails. If it passes, the item will be checked in to perforce, if it fails, it will not. exiting while returning a ’1′ is considered a fail, ’0′ a pass.
print 'Hello World!' print 'No checkin for you!' sys.exit(1)
Ok, so save this file as hello_trigger.py. Now go to a command line and enter ‘p4 triggers’ this will open a text document, edit that document to point to your trigger, like so (but point to the location of your script on disk):
Triggers: hello_trigger change-submit //depot/... "python X:/projects/2010/p4/hello_trigger.py"
Close/save the trigger TMP file, you should see ‘Triggers saved.’ echo’d at the prompt. Now, when we try to submit a file to the depot, we will get this:
So: awesome, you just DENIED your first check-in!
Connecting to Perforce from Inside a Trigger
So we are now denying check-ins, but let’s try to do some other things, let’s connect to perforce from inside a trigger.
from P4 import P4, P4Exception p4 = P4() try: #use whatever your admin l/p was #this isn't the safest, but it works at this beginner level p4.user = "admin" p4.password = "admin" p4.port = "1666" p4.connect() info = p4.run("info") print info sys.exit(1) #this will return any errors except P4Exception: for e in p4.errors: print e sys.exit(1)
So now when you try to submit a file to depot you will get this:
Passing Info to the Trigger
Now we are running triggers, accepting or denying checkins, but we really don’t know much about them. Let’s try to get enough info to where we could make a decision about whether or not we want the file to pass validation. Let’s make another python trigger, trigger_test.py, and let’s query something from the perforce server in the submit trigger. To do this we need to edit our trigger file like so:
Triggers: test change-submit //depot/... "python X:/projects/2010/p4/test_trigger.py %user% %changelist%"
This will pass the user and changelist number into the python script as an arg, the same way dragging/dropping passed args to python in my previous example. So let’s set that up, save the script from before as ‘test_trigger.py’ as shown above, and add the following:
import sys from P4 import P4, P4Exception p4 = P4() describe =  try: p4.user = "admin" p4.password = "admin" p4.port = "1666" p4.connect() except P4Exception: for e in p4.errors: print e sys.exit(1) print str(sys.argv) describe = p4.run('describe',sys.argv) print str(describe) p4.disconnect() sys.exit(1)
So, as you can see, it has returned the user and changelist number:
However, for this changelist to be useful, we query p4, asking the server to describe the changelist. This returns a lot of information about the changelist.
Where to Go From here
The few simple things shown here really give you the tools to do many more things. Here are some examples of triggers that can be created with the know-how above:
- Deny check-ins of a certain filetype (like deny compiled source files/assets)
- Deny check-ins whose hash digest matches an existing file on the server
- Deny/allow a certain type of file check-in from a user in a certain group
- Email a lead any time a file in a certain folder is updated
Did you find this helpful? What creative triggers have you written?