mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-11-26 22:50:40 +00:00
217b1b6f54
exception errrors such as when a pyc file is not found uncompyle6: Hook in --grammar option to showing grammar. rules. Default now does not show timestamp.
214 lines
6.5 KiB
Python
Executable File
214 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Mode: -*- python -*-
|
|
#
|
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
|
# Copyright (c) 2015 by Rocky Bernstein
|
|
|
|
"""
|
|
Usage: uncompyle6 [OPTIONS]... [ FILE | DIR]...
|
|
|
|
Examples:
|
|
uncompyle6 foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
|
|
uncompyle6 -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
|
|
uncompyle6 -o /tmp /usr/lib/python1.5 # decompile whole library
|
|
|
|
Options:
|
|
-o <path> output decompiled files to this path:
|
|
if multiple input files are decompiled, the common prefix
|
|
is stripped from these names and the remainder appended to
|
|
<path>
|
|
uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc
|
|
-> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis
|
|
uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc
|
|
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
|
uncompyle6 -o /tmp /usr/lib/python1.5
|
|
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
|
|
-c <file> attempts a disassembly after compiling <file>
|
|
-d print timestamps
|
|
-p <integer> use <integer> number of processes
|
|
-r recurse directories looking for .pyc and .pyo files
|
|
--verify compare generated source with input byte-code
|
|
(requires -o)
|
|
--help show this message
|
|
|
|
Debugging Options:
|
|
--asm -a include byte-code (disables --verify)
|
|
--grammar -g show matching grammar
|
|
--treee -t include syntax tree (disables --verify)
|
|
|
|
Extensions of generated files:
|
|
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
|
+ '_unverified' successfully decompile but --verify failed
|
|
+ '_failed' decompile failed (contact author for enhancement)
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
import sys, os, getopt, time
|
|
|
|
program = os.path.basename(__file__)
|
|
|
|
from uncompyle6 import verify, check_python_version
|
|
from uncompyle6.main import main, status_msg
|
|
|
|
def usage():
|
|
print("""usage:
|
|
%s [--help] [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
|
|
""" % program)
|
|
sys.exit(1)
|
|
|
|
|
|
check_python_version(program)
|
|
|
|
showasm = showast = do_verify = recurse_dirs = False
|
|
numproc = 0
|
|
outfile = '-'
|
|
out_base = None
|
|
codes = []
|
|
timestamp = False
|
|
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
|
|
|
try:
|
|
opts, files = getopt.getopt(sys.argv[1:], 'hagtdro:c:p:',
|
|
'help asm grammar recurse timestamp tree verify '
|
|
'showgrammar'.split(' '))
|
|
except getopt.GetoptError as e:
|
|
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
|
sys.exit(-1)
|
|
|
|
options = {}
|
|
for opt, val in opts:
|
|
if opt in ('-h', '--help'):
|
|
print(__doc__)
|
|
sys.exit(0)
|
|
elif opt == '--verify':
|
|
options['do_verify'] = True
|
|
elif opt in ('--asm', '-a'):
|
|
options['showasm'] = True
|
|
options['do_verify'] = False
|
|
elif opt in ('--tree', '-t'):
|
|
options['showast'] = True
|
|
options['do_verify'] = False
|
|
elif opt in ('--grammar', '-g'):
|
|
options['showgrammar'] = True
|
|
elif opt == '-o':
|
|
outfile = val
|
|
elif opt == ('--timestamp', '-d'):
|
|
timestamp = True
|
|
elif opt == '-c':
|
|
codes.append(val)
|
|
elif opt == '-p':
|
|
numproc = int(val)
|
|
elif opt == ('--recurse', '-r'):
|
|
recurse_dirs = True
|
|
else:
|
|
print(opt, file=sys.stderr)
|
|
usage()
|
|
|
|
# expand directory if specified
|
|
if recurse_dirs:
|
|
expanded_files = []
|
|
for f in files:
|
|
if os.path.isdir(f):
|
|
for root, _, dir_files in os.walk(f):
|
|
for df in dir_files:
|
|
if df.endswith('.pyc') or df.endswith('.pyo'):
|
|
expanded_files.append(os.path.join(root, df))
|
|
files = expanded_files
|
|
|
|
# argl, commonprefix works on strings, not on path parts,
|
|
# thus we must handle the case with files in 'some/classes'
|
|
# and 'some/cmds'
|
|
src_base = os.path.commonprefix(files)
|
|
if src_base[-1:] != os.sep:
|
|
src_base = os.path.dirname(src_base)
|
|
if src_base:
|
|
sb_len = len( os.path.join(src_base, '') )
|
|
files = [f[sb_len:] for f in files]
|
|
del sb_len
|
|
|
|
if not files:
|
|
print("No files given", file=sys.stderr)
|
|
usage()
|
|
|
|
|
|
if outfile == '-':
|
|
outfile = None # use stdout
|
|
elif outfile and os.path.isdir(outfile):
|
|
out_base = outfile; outfile = None
|
|
elif outfile and len(files) > 1:
|
|
out_base = outfile; outfile = None
|
|
|
|
if timestamp:
|
|
print(time.strftime(timestampfmt))
|
|
|
|
if numproc <= 1:
|
|
try:
|
|
result = main(src_base, out_base, files, codes, outfile,
|
|
**options)
|
|
if len(files) > 1:
|
|
mess = status_msg(do_verify, *result)
|
|
print('# ' + mess)
|
|
pass
|
|
except (KeyboardInterrupt):
|
|
pass
|
|
except verify.VerifyCmpError:
|
|
raise
|
|
else:
|
|
from multiprocessing import Process, Queue
|
|
|
|
try:
|
|
from Queue import Empty
|
|
except ImportError:
|
|
from Queue import Empty
|
|
|
|
fqueue = Queue(len(files)+numproc)
|
|
for f in files:
|
|
fqueue.put(f)
|
|
for i in range(numproc):
|
|
fqueue.put(None)
|
|
|
|
rqueue = Queue(numproc)
|
|
|
|
def process_func():
|
|
try:
|
|
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
|
while 1:
|
|
f = fqueue.get()
|
|
if f is None:
|
|
break
|
|
(t, o, f, v) = \
|
|
main(src_base, out_base, [f], codes, outfile, **options)
|
|
tot_files += t
|
|
okay_files += o
|
|
failed_files += f
|
|
verify_failed_files += v
|
|
except (Empty, KeyboardInterrupt):
|
|
pass
|
|
rqueue.put((tot_files, okay_files, failed_files, verify_failed_files))
|
|
rqueue.close()
|
|
|
|
try:
|
|
procs = [Process(target=process_func) for i in range(numproc)]
|
|
for p in procs:
|
|
p.start()
|
|
for p in procs:
|
|
p.join()
|
|
try:
|
|
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
|
while True:
|
|
(t, o, f, v) = rqueue.get(False)
|
|
tot_files += t
|
|
okay_files += o
|
|
failed_files += f
|
|
verify_failed_files += v
|
|
except Empty:
|
|
pass
|
|
print('# decompiled %i files: %i okay, %i failed, %i verify failed' %
|
|
(tot_files, okay_files, failed_files, verify_failed_files))
|
|
except (KeyboardInterrupt, OSError):
|
|
pass
|
|
|
|
|
|
if timestamp:
|
|
print(time.strftime(timestampfmt))
|