From 27e2e32f7ec43a63491ff4c8a860b008e018d034 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 May 2014 15:37:57 -0600 Subject: [PATCH] Added the basic script. --- p4RemoveUnversioned.py | 122 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 p4RemoveUnversioned.py diff --git a/p4RemoveUnversioned.py b/p4RemoveUnversioned.py new file mode 100644 index 0000000..81f357f --- /dev/null +++ b/p4RemoveUnversioned.py @@ -0,0 +1,122 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- + +# todo: have a backup feature, make sure files are moved to the recycle bin or a temporary file. +# todo: switch to faster method of calling p4 fstat on an entire directory and parsing it's output +# todo: add option of using send2trash + +import inspect, os, re, subprocess, sys, traceback + + +modules_path = os.path.normpath( os.path.realpath( __file__ ) ) + + +re_remove_comment = re.compile( "#.*$" ) +def remove_comment( s ): + return re.sub( re_remove_comment, "", s ) + + +try: input = raw_input +except: pass + +def PressEnter( ): + print( "\nPress ENTER to continue..." ) + s=input( "" ) + +def main( ): + # check requirement + if os.system( 'p4 > Nul' ) != 0: + print 'Perforce Command-line Client(p4) is required for this script.' + sys.exit( 1 ) + + # Files are added from .p4ignore + # Key is the file root, the value is the table of file regexes for that directory. + files_to_ignore = {} + + def get_ignore_list( path ): + # have to split path and test top directory + dirs = path.split( os.sep ) + + ignore_list = [ ] + + for i, val in enumerate( dirs ): + path_to_find = os.sep.join( dirs[ : i + 1] ) + + if path_to_find in files_to_ignore: + ignore_list = ignore_list + files_to_ignore[ path_to_find ] + + # ignore_list = [ r for p in [ os.sep.join( dirs[ : i + 1] ) for i, val in enumerate( dirs ) ] if p in files_to_ignore for r in files_to_ignore[ p ] ] + + return ignore_list + + def match_in_ignore_list( path, ignore_list ): + for r in ignore_list: + if re.match( r, path ): + return True + return False + + + p4_ignore = ".p4ignore" + + for root, dirs, files in os.walk( '.' ): + + print ("\nChecking '" + root + "' ...") + + if p4_ignore in files: + file_regexes = [] + + # Should automatically ignore .p4ignore even if it's not specified, otherwise it'll be deleted. + + path = os.path.join( root, p4_ignore ) + with open( path ) as f: + for line in f: + new_line = remove_comment( line.strip( ) ) + if len( new_line ) > 0: + file_regexes.append( re.compile( os.path.join( re.escape( root + os.sep ), new_line ) ) ) + + print( " appending ignores from " + path ) + files_to_ignore[ root ] = file_regexes + + + ignore_list = get_ignore_list( root ) + + for file in files: + path = os.path.join( root, file ) + + if match_in_ignore_list( path, ignore_list ): + print( " ignoring " + path ) + continue + + proc = subprocess.Popen( "p4 fstat \"" + path + "\"", stdout=subprocess.PIPE, stderr=subprocess.PIPE ) + (out, err) = proc.communicate() + + if len( err ) > 0: + print( " " + file + " is unversioned, removing it." ) + os.remove( path ) + + dirs_copy = dirs + for d in dirs_copy: + path = os.path.join( root, d ) + if match_in_ignore_list( path, ignore_list ): + # add option of using send2trash + print( " ignoring " + d ) + dirs.remove( d ) + + # remove empty directories + for root, dirs, files in os.walk( '.', topdown=False ): + for d in dirs: + try: + os.rmdir(d) + print( " " + d + " was removed." ) + except OSError: + # Fails on non-empty directory + pass + +if __name__ == "__main__": + try: + main( ) + except: + print( "Unexpected error!" ) + traceback.print_exc( file = sys.stdout ) + + PressEnter() \ No newline at end of file