#!/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 <filename>
#
# 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 <filename>
#
# label: suzuki-label-1
# Options: unlocked
# Owner: niranjan
# Update: 1056050312
# Description: Created by niranjan.
# code: stat
# Access: 1057108998
#
#
# Sample dictionary from p4 -G files <filename>@<label1> <filename>@<label2>...
#
# 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