Skip to content

Instantly share code, notes, and snippets.

@justinhj
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinhj/db03284a0446eddf2846 to your computer and use it in GitHub Desktop.
Save justinhj/db03284a0446eddf2846 to your computer and use it in GitHub Desktop.
backup your p$ change list files to a dated folder
# Copies a changelist (any files open for edit or add) to a directory you specify
# (C)2011 Justin Heyes-Jones
# TODO
# Allow user to pass in PORT setting
# Or at least check that it is set before doing perforce interactions
# P4 set P4PORT=servername:port
import subprocess, sys, marshal, string, os, time, datetime
# Get a list of client file names, the files that you currently have open
# by calling p4 opened, and parsing the input into a list of strings.
# I also strip the client name off the file path
def P4GetClientFiles(matchText=None):
clientFiles = []
print 'Locating client files'
try:
# P4 has output in Python marshal format; a cross platform binary serialization
# of Python data, enabled by the -G option above
p = subprocess.Popen("p4 -G opened", stdout=subprocess.PIPE, stderr=subprocess.PIPE)
done = 0
while done == 0:
try:
dict = marshal.load(p.stdout)
if dict['action'] == 'delete':
print "Skipping file open for delete: %s" % clientFile
continue
clientFile = dict['clientFile']
# filter out files that don't contain the matchText
if matchText and string.find(clientFile, matchText) < 0:
continue
# Find the path using p4 where
command = "p4 -G where %s" % clientFile
p2 = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
dict = marshal.load(p2.stdout)
clientFile = dict['path']
if os.path.exists(clientFile):
clientFiles.append(clientFile)
else:
print 'Skipping file I couldn\'t find: ', clientFile
sys.stdout.write(".")
except EOFError, e:
done = 1
except WindowsError, e:
print >>sys.stderr, "Error running command:", e
print
print 'Done locating client files'
return clientFiles
# Strip the drive extension off of the source path and stick the new one in its place
# so Z:\path\file.txt with new path of c:/test/ becomes c:/test/path/file.txt
def MakeDestPath(oldPath, newPath):
colonIndex = string.find(oldPath, ":")
lastSlash = string.rfind(oldPath, "\\")
newPath = newPath + oldPath[colonIndex+1:lastSlash+1]
return newPath
def Main():
# Handle arguments
if len(sys.argv) < 2:
print "Usage: python backupchangelist.py [-d] targetdirectory"
print "Options: -d Make a subdirectory in targetdirectory named after the date and time (useful for automated backup)"
sys.exit(1)
# Check for options and find target path
if sys.argv[1][0] == '-' and sys.argv[1][1] == 'd':
targetDirectory = sys.argv[2] + "/" + time.strftime("%Y_%m_%d_%H%M")
else:
targetDirectory = sys.argv[1]
files = P4GetClientFiles()
numFiles = len(files)
numCopied = 0
for file in files:
output = MakeDestPath(file, targetDirectory)
# TODO if this used the python file copy commands this would be portable
cmd = "xcopy \"%s\" \"%s\" /I /Y" % (file, output)
print "cmd is " + cmd
try:
retcode = subprocess.call(cmd, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
elif retcode == 0:
numCopied = numCopied + 1
except OSError, e:
print >>sys.stderr, "Execution failed:", e
print "\n%d/%d files copied succesfully" % (numCopied, numFiles)
Main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment