Skip to content

Instantly share code, notes, and snippets.

@mpacer
Last active May 16, 2018 16:45
Show Gist options
  • Save mpacer/b3dc71db53d74de8e51de4a74119073f to your computer and use it in GitHub Desktop.
Save mpacer/b3dc71db53d74de8e51de4a74119073f to your computer and use it in GitHub Desktop.
diff files quickly in subdirs
#!/usr/bin/env python3
import os
import glob
import itertools
import sys
import argparse
from subprocess import Popen, PIPE
def parseargs():
parser = argparse.ArgumentParser(description='quickly diff files in subdirs')
parser.add_argument('filename', help="this is the file that you're looking for")
parser.add_argument('--exclude', dest="excluded", action="append",
help="pass in a string to exclude dirs with that string")
parser.add_argument('--only', dest="only", action="append",
help="pass in a string to include only dirs with that string")
return parser.parse_args()
def gen_dirs(fn, exclude_list=None, only_list=None):
if exclude_list is None:
exclude_list =[]
if only_list is None:
only_list =[]
return (d for d in glob.iglob('*')
if os.path.isdir(d)
and filter_dir_names(d, exclude_list, only_list)
and os.path.exists(os.path.join('.', d, fn)))
def filter_dir_names(d, exclude_list=None, only_list=None):
if exclude_list is None:
exclude_list =[]
if only_list is None:
only_list =['']
only = any(s in d for s in only_list) if only_list else True
exclude = any(s in d for s in exclude_list) if exclude_list else True
return only and not exclude
def filename_writer(fn, excluded=None, only=None):
if excluded is None:
excluded = []
if only is None:
only = []
exclude_str = ('-'.join(['','excluding',*excluded])) if excluded else ''
include_str = ('-'.join(['','including', *only])) if only else ''
return f"diff-{fn}-report{include_str}{exclude_str}.txt"
def filter_list_to_str(f_list):
ret_str = ""
if len(f_list)==1:
ret_str+=f_list[0]
elif len(f_list)==2:
ret_str+=" and ".join(f_list)
elif len(f_list)>2:
ret_str+=f"{', '.join(f_list[:-1])}, and {f_list[-1]}"
return ret_str
def main():
parser = parseargs()
fn = parser.filename
excluded = parser.excluded
only = parser.only
dir_gen = gen_dirs(fn, exclude_list=excluded, only_list=only)
output_file = filename_writer(fn, excluded, only)
if os.path.exists(output_file):
os.remove(output_file)
to_write = []
no_diff_dict = {}
for d in itertools.combinations(dir_gen, 2):
f1, f2 = map(lambda x: os.path.join(x, fn), d)
d1, d2 = map(str, d)
header = f"{f1} compared to {f2} is different as follows:"
diff_cmd =['diff', f'{f1}', f'{f2}']
p = Popen(diff_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate()
if output:
to_write.extend([header, f"{'-'*len(header)}"])
to_write.append(f"{output.decode('utf-8')}\n")
else:
if d1 in no_diff_dict:
no_diff_dict[d1].append(d2)
elif d2 in no_diff_dict:
no_diff_dict[d2].append(d1)
else:
no_diff_dict[d1] = [d2]
no_diff_str = "\n".join([f" {', '.join(v)}, and {k}"
if len(v)>1 else f" {k} and {v[0]}"
for k, v in no_diff_dict.items()])
no_diff_str= "There is no difference between:\n" + no_diff_str
with open(output_file, 'a') as f:
f.write(f"This is a report on the differences between the different files named {fn}.\n\n")
if to_write:
f.write(no_diff_str+"\n\n")
f.write("\n".join(to_write))
else:
f.write(f"Are you sure that you meant to search for {fn}, "
f"{'including only ' +filter_list_to_str(only) + ' ' if only else ''}"
f"{'excluding ' +filter_list_to_str(excluded) if excluded else ''}?\n"
"There are no such files!")
if __name__=="__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment