p4Scripts/p4RemoveUnversioned.py

158 lines
5.0 KiB
Python
Raw Normal View History

2014-05-08 21:37:57 +00:00
#!/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, stat, subprocess, sys, traceback
2014-05-08 21:37:57 +00:00
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 ]
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
root_path = "."
root_full_path = os.getcwd( )
2014-05-08 21:37:57 +00:00
p4_ignore = ".p4ignore"
# make sure script doesn't delete itself
files_to_ignore[ root_path ] = [ re.compile( os.path.join( re.escape( root_path + os.sep ), os.path.basename( __file__ ) ) ) ]
2014-05-08 21:37:57 +00:00
for root, dirs, files in os.walk( root_path ):
print ( os.linesep + "Checking '" + root + "' ...")
2014-05-08 21:37:57 +00:00
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 ] = files_to_ignore[ root ] + file_regexes
2014-05-08 21:37:57 +00:00
ignore_list = get_ignore_list( root )
#command = "p4 have \"" + root + os.sep + "*\""
command = "p4 fstat *"
print("|" + command)
os.chdir( root )
proc = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
(out, err) = proc.communicate()
os.chdir( root_full_path )
# For ease we're doing a weird solution, rebuilding the file list. This is so we only need to parse unadded files.
files = []
for line in err.split( os.linesep ):
if len(line) == 0:
continue
# # dirty hack that grabs the filename from the ends of the printed out (not err) "depo_path - local_path"
# # I could use regex to verify the expected string, but that will just slow us down.
# basename = os.path.basename( line )
i = line.rfind( ' - ')
if i >= 0:
basename = line[ : i ]
if basename == "*":
# Directory is empty, we could delete it now
continue
path = os.path.join( root, basename )
if not os.path.isdir( path ):
files.append( basename )
2014-05-08 21:37:57 +00:00
for file in files:
path = os.path.join( root, file )
if match_in_ignore_list( path, ignore_list ):
print( "| Ignoring " + path )
2014-05-08 21:37:57 +00:00
continue
print( "| " + file + " is unversioned, removing it." )
os.chmod( path, stat.S_IWRITE )
os.remove( path )
2014-05-08 21:37:57 +00:00
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 )
2014-05-08 21:37:57 +00:00
dirs.remove( d )
print( "|Done." )
print( os.linesep + "Removing empty directories...")
2014-05-08 21:37:57 +00:00
# remove empty directories
for root, dirs, files in os.walk( root_path, topdown=False ):
2014-05-08 21:37:57 +00:00
for d in dirs:
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 )
2014-05-08 21:37:57 +00:00
try:
os.rmdir(path)
print( "| " + d + " was removed." )
2014-05-08 21:37:57 +00:00
except OSError:
# Fails on non-empty directory
pass
print( "|Done." )
2014-05-08 21:37:57 +00:00
if __name__ == "__main__":
try:
main( )
except:
print( "Unexpected error!" )
traceback.print_exc( file = sys.stdout )
PressEnter()