#! /usr/bin/env python # # Copyright 2011-2014 by Ben Key # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # import getopt import locale import os import stat import sys if "nt" == os.name.lower(): import win32api import win32console import p4clean_utils __version__ = 1.6 __doc__ = """ p4cleandir version %(version)s, Copyright 2011-2014 by Ben Key. p4cleandir is a simple utility designed to remove all files from a Perforce client directory that are not included in the Perforce depot. The Perforce client directory to be cleaned can either be specified via the first command line argument or, if no directory is specified, the current working directory will be used. Usage: p4cleandir.py [options] [directory] Options: --version, --VERSION, -v, -V Print version information and exit successfully. --help, --HELP, -h, -H, -? Print this help message and exit successfully. --list, --LIST, -l, -L List the files only, do not delete them. --client, --CLIENT, -c, -C {lient_name} The name of the Perforce client that you wish to clean. This parameter is useful if you use multiple Perforce clients on one system. """ __version_info__ = """ p4cleandir version %(version)s, Copyright 2011-2014 by Ben Key. p4cleandir is a simple utility designed to remove all files from a Perforce client directory that are not included in the Perforce depot. p4cleandir comes with ABSOLUTELY NO WARRANTY. This program is free software; your freedom to use, change and distribute this program is covered by the 2-Clause BSD License. """ def usage(): """Prints the usage information for p4cleandir.""" print(__doc__ % {'version' : __version__}) def version(): """Prints the version information for p4cleandir.""" print(__version_info__ % {'version' : __version__}) def IsDirectoryInPerforce(workspace, dir): """Determines whether or not the specified directory is included in the Perforce depot.""" codePage = p4clean_utils.GetCurrentCodepage()() commandString = "p4 -s fstat \"%s\\...\"" % (dir,) if (workspace != None): commandString = "p4 -c %s -s fstat \"%s\\...\"" % (workspace, dir) command = p4clean_utils.Command(commandString).run(False) if 0 == command.returncode: output = command.output.decode(codePage) errorPos = output.find("error:") if -1 != errorPos: return False return True def CleanDirectory(workspace, dir, listOnly): """Iterates through the specified directory recursively finding all files that are not included in the Perforce depot. Returns a list of the files that were found. If listOnly is false, the files that are not included in the Perforce depot will be deleted as well.""" codePage = p4clean_utils.GetCurrentCodepage()() dirInPerforce = IsDirectoryInPerforce(workspace, dir) filesNotInDepot = [] for item in os.listdir(dir): fileName = os.path.join(dir, item) if os.path.isfile(fileName): if dirInPerforce: if os.access(fileName, os.W_OK): commandString = "p4 -s fstat \"%s\"" % (fileName,) if (workspace != None): commandString = "p4 -c %s -s fstat \"%s\"" % (workspace, fileName) command = p4clean_utils.Command(commandString).run(False) if 0 == command.returncode: output = command.output.decode(codePage) errorPos = output.find("error:") deleteActionPos = output.find("headAction delete") if -1 != errorPos or -1 != deleteActionPos: filesNotInDepot.append(fileName) if listOnly: print("Found non depot file: %s" % (fileName,)) else: print("Removing file: %s" % (fileName,)) try: os.chmod(fileName, stat.S_IWRITE) os.remove(fileName) except PermissionError: pass else: filesNotInDepot.append(fileName) if listOnly: print("Found non depot file: %s" % (fileName,)) else: print("Removing file: %s" % (fileName,)) os.chmod(fileName, stat.S_IWRITE) os.remove(fileName) else: filesNotInDepot.extend(CleanDirectory(workspace, fileName, listOnly)) if False == dirInPerforce and False == listOnly: print("Removing directory: %s" % (dir,)) try: os.rmdir(dir) except OSError: pass return filesNotInDepot def main(argv = sys.argv): """The main entry point for p4cleandir.""" p4clean_utils.InitLocale() parser = p4clean_utils.CommandLineArgumentsParser(argv) parser.parse_command_line() if parser.should_display_usage(): usage() sys.exit(0) elif parser.should_display_version(): version() sys.exit(0) listOnly = parser.should_list_only() workspaceName = parser.get_client() dir = os.getcwd() if 0 != len(parser.get_args()): dir = parser.get_args()[0] filesNotInDepot = CleanDirectory(workspaceName, dir, listOnly) if (0 == len(filesNotInDepot)): sys.exit(1) sys.exit(0) if __name__ == "__main__": sys.exit(main(sys.argv))