#!/bin/env python3
# FindCaseClash.py
# Given an input file with a list of files from case senstive p4d
# Output the dir and file clashses.
# The input file should be the output of:
# sort -f filelist | uniq -Di > filedups.txt
# So all files are in case insensitive sort order
# Python 2.7/3.3 compatibility.
from __future__ import print_function
import sys
from os.path import basename, splitext
from collections import defaultdict
class ClashFinder:
"Finds new directories in paths - seperate class for ease of testing"
def __init__(self):
self.dupCount = defaultdict(int)
self.lpaths = defaultdict(list)
def findCommonPartInd(self, parts1, parts2):
# Returns index for common part
i = 1
while i <= len(parts1):
p1 = "/".join(parts1[:i])
p2 = "/".join(parts2[:i])
if p1 != p2:
return i-1
i += 1
return 0
def checkCommonDirs(self, parts1, parts2):
# We know parts aren't the same - just confirm equal lengths
if len(parts1) != len(parts2):
print("Problem: '%s' '%s'" % ("/".join(parts1), "/".join(parts2)))
return
ind = self.findCommonPartInd(parts1, parts2)
if ind == 0 or ind == len(parts1):
print("/".join(parts1))
print("/".join(parts2))
return
# Want one more than common part
p1 = "/".join(parts1[:ind+1])
p2 = "/".join(parts2[:ind+1])
self.dupCount[p1] += 1
self.dupCount[p2] += 1
self.lpaths[p1.lower()].append(p1)
self.lpaths[p1.lower()].append(p2)
# This method returns None if no new directory found, or the directory name
def checkClash(self, paths):
if len(paths) != 2:
print("Error Not2: %s" % ",".join(paths))
return
self.checkCommonDirs(paths[0][2:].split("/"), paths[1][2:].split("/"))
def printClashes(self):
seen = {}
for k in self.lpaths.keys():
for j in self.lpaths[k]:
if self.dupCount[j] == 1 and j not in seen:
print("%s" % (j))
seen[j] = 1
elif j not in seen:
print("%d %s/" % (self.dupCount[j], j))
seen[j] = 1
if __name__ == '__main__':
cf = ClashFinder()
with open(sys.argv[1]) as f:
lastline = None
paths = []
for line in f:
line = line.rstrip()
if line.lower() == lastline:
paths.append(line)
else:
if paths:
cf.checkClash(paths)
lastline = line.lower()
paths = [line]
cf.printClashes()