JAR diff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import os | |
import sets | |
import subprocess | |
import sys | |
import tempfile | |
""" | |
Assumes procyon: | |
https://bitbucket.org/mstrobel/procyon/downloads/ | |
Sample usage: | |
python jardiff.py --procyon ~/gg/procyon-decompiler-0.5.36.jar ~/gg/fe ~/gg/bf | |
""" | |
args = None | |
def main(): | |
global args | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--procyon", help="location of procyon JAR") | |
parser.add_argument("first") | |
parser.add_argument("second") | |
args = parser.parse_args() | |
if os.path.isdir(args.first): | |
dir1 = args.first | |
else: | |
if not(args.first.endswith(".jar")): | |
print "Expected either a JAR or dir as first argument" | |
sys.exit(1) | |
raise Exceptino("TODO unjar") | |
if os.path.isdir(args.second): | |
dir2 = args.second | |
else: | |
if not(args.second.endswith(".jar")): | |
print "Expected either a JAR or dir as first argument" | |
sys.exit(1) | |
raise Exceptino("TODO unjar") | |
compare_dirs(dir1, dir2) | |
def walker(files, dirname, fnames): | |
for fname in fnames: | |
abs_fname = os.path.join(dirname, fname) | |
if os.path.isdir(abs_fname): | |
os.path.walk(abs_fname, walker, files) | |
else: | |
files.append(abs_fname) | |
def get_all_files(dir): | |
print "Getting files from %s" % dir | |
files = [] | |
os.path.walk(dir, walker, files) | |
# Make them relative | |
files = [f[len(dir)+1:] for f in files] | |
return files | |
def compare_dirs(dir1, dir2): | |
print "Comparing %s vs %s" % (dir1, dir2) | |
files1 = get_all_files(dir1) | |
files2 = get_all_files(dir2) | |
in2only = sets.Set(files2) - sets.Set(files1) | |
if in2only: | |
print "Files in %s but not in %s" % (dir2, dir1) | |
print "\n\t".join(list(in2only)) | |
for f in files1: | |
if f not in files2: | |
print "%s not in %s" % (f, dir2) | |
continue | |
f1 = os.path.join(dir1, f) | |
f2 = os.path.join(dir2, f) | |
# TODO really this should check checksum, not size | |
s1 = os.stat(f1).st_size | |
s2 = os.stat(f2).st_size | |
if s1 != s2: | |
print "Different: %s (%s vs %s)" % (f, s1, s2) | |
if f.endswith(".class"): | |
f1java = tempfile.NamedTemporaryFile(suffix='.java', delete=False) | |
f1java.write("") | |
f1java.close() | |
cmd = "java -jar %s %s > %s" % (args.procyon, f1, f1java.name) | |
# print cmd | |
subprocess.check_call(cmd, shell=True) | |
f2java = tempfile.NamedTemporaryFile(suffix='.java', delete=False) | |
f2java.write("") | |
f2java.close() | |
cmd = "java -jar %s %s > %s" % (args.procyon, f2, f2java.name) | |
# print cmd | |
subprocess.check_call(cmd, shell=True) | |
diff_cmd = ["diff","-Z",f1java.name, f2java.name] | |
print "Executing %s" % " ".join(diff_cmd) | |
try: | |
subprocess.check_output(diff_cmd) | |
except subprocess.CalledProcessError, cpe: | |
if cpe.returncode == 1: | |
# diff will return 1 if files are different | |
diff = cpe.output | |
print diff | |
else: | |
# we already know it will not return 0 because they are different | |
# so it can only be 2 - trouble | |
raise | |
os.unlink(f1java.name) | |
os.unlink(f2java.name) | |
else: | |
print "\tDo not know how to diff" | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment