#!/usr/bin/python2.2 #^--- change the above line to point to your installation of Python # $Id: //guest/mitch_stuart/perforce/utils/delta/p4Util.py#1 $ """ Perforce utility module This module provides functions to invoke Perforce commands and perform other Perforce-related tasks. Use p4Util.execP4Marshal to invoke a Perfoce command. This executes the p4 command-line client with the -G global option. The -G option is used to tell Perforce to output the results as marshalled Python dictionary objects, instead of as text. See: http://www.perforce.com/perforce/doc.022/manuals/cmdref/o.gopts.html """ # # # Sample output from the p4 -G command # # Sample dictionary from p4 -G changes -i -l # # desc: Split StringMapper utility class into its own file # change: 3913 # time: 1057100582 # client: mitchws-devsrv3 # user: mstuart # code: stat # status: submitted # # # Sample dictionary from p4 -G labels # # label: suzuki-label-1 # Options: unlocked # Owner: niranjan # Update: 1056050312 # Description: Created by niranjan. # code: stat # Access: 1057108998 # # # Sample dictionary from p4 -G files @ @... # # change: 3755 # depotFile: //depot/dev/console/suzuki/build.sh # rev: 7 # action: edit # time: 1055969144 # code: stat # type: text+klx # # import marshal import os import sys import time # Classes class p4Exception(Exception): pass # Constants DEFAULT_DATE_FORMAT = "%m/%d/%y %H:%M" # Globals g_debugFlag = 0 def checkDirectoryExists(dir): """ If the directory exists, return silently. If not, raise p4Exception with an error message. """ if not directoryExists(dir): raise p4Exception("No such directory: %s" % dir) def cmpLabelTimestampReverse(label1, label2): """ Compare the update timestamps of two Perforce labels. This comparison is for reverse chronological order sorting. Returns 0 if equal, -1 if label1 > label2, 1 if label1 < label2 (this is the opposite of the usual sorting order). """ return -cmp(label1["Update"], label2["Update"]) def directoryExists(dir): """ Return 1 if the directory exists, else return 0. """ dirs = execP4Marshal("dirs " + dir) if len(dirs) == 1: return 1 else: return 0 def execP4Marshal(p4Command): """ Execute the given p4 command and return the marshaled Python result. Uses the Perforce -G flag. See: http://www.perforce.com/perforce/doc.022/manuals/cmdref/o.gopts.html. The p4Command parameter is prefixed with "p4 -G " and then executed, so you can also include any global options you need. For example: execP4Marshal("-c myclient files //depot/mydir/...") executes the command: p4 -G -c myclient files //depot/mydir/... """ command = "p4 -G " + p4Command result = [] popenMode = "r" # On Windows, we need to read the p4 process stdout in binary mode; # otherwise Python will translate the LFs to CR/LF which will throw # off the marshalled objects. if sys.platform.startswith('win'): popenMode = "rb" p4stdout = os.popen(command, popenMode) try: while 1: dict = marshal.load(p4stdout) result.append(dict) except EOFError: pass if g_debugFlag: print "Command: %s" % command print "Loaded %d dictionaries" % len (result) for dict in result: for key in dict.keys(): print "%s: %s" % (key, dict[key]) return result def getDebugFlag(): return g_debugFlag def getDepotPath(dirspec): """ dirspec can be in Perforce syntax (depot or client), or in local syntax. Say we have a file //depot/dev/foo/bar/myfile.c, which has the client path //mitchws/dev/foo/bar/myfile.c and the local path R:\dev\foo\bar\myfile.c. This function will return //depot/dev/foo as the rootDepotPath in any of the following cases: - dirspec is //depot/dev/foo - dirspec is //mitchws/dev/foo - dirspec is R:\dev\foo - dirspec is foo and the current directory is R:\dev - dirspec is dev\foo and the current directory is R: - dirspec is . and the current directory is R:\dev\foo CAUTION: This function will not work if the depot path to dirspec (or dirspec itself) contains spaces. """ where = execP4Marshal("where " + dirspec) # The where command returns a key "data" with a line containing the # following: (1) the path in depot syntax; (2) the path in depot syntax; # (3) the path in local syntax. # # There is a single space between each path. # CAUTION: This function will not work if any of the paths have spaces # in them. # # Example value for "data" key: # # //depot/dev/console/suzuki //mitchws-devsrv3/dev/console/suzuki r:\dev\console\suzuki paths = where[0]["data"].split(" ") return paths[0] def getDisplayDateString(secs, format=DEFAULT_DATE_FORMAT): """ Format the date with the given format. If the format is not passed as an argument, the DEFAULT_DATE_FORMAT is used. """ return time.strftime(format, time.localtime(int(secs))) def isPathInLocalSyntax(path): """ Returns the opposite of isPathInPerforceSyntax """ return not isPathInPerforceSyntax(path) def isPathInPerforceSyntax(path): """ Returns 1 if the path is in Perforce "depot" or "client" syntax, 0 if the path is in local filesystem syntax. This is determined by looking at the first two characters; if they are "//" then the path is considered to be in Perforce syntax. """ if path.startswith("//"): return 1 return 0 def joinPathAndFilename(path, filename): """ Returns the concatenation of the path and the filename, separated by a separator character. If the path is in depot syntax, the separator is a "/". Otherwise, the separator is the file separator for the current platform. For example, joinPathAndFilename("//depot/dev", "myfile.c") returns "//depot/dev/myfile.c". joinPathAndFile("C:\dev", "myfile.c") returns "C:\dev\myfile.c". """ if isPathInPerforceSyntax(path): separator = "/" else: separator = os.sep return path + separator + filename def setDebugFlag(debugFlag): global g_debugFlag g_debugFlag = debugFlag