Last active
March 22, 2017 05:05
-
-
Save csm10495/b912286f477211fe6b3862b331fe97bc to your computer and use it in GitHub Desktop.
A Python based folder extractor. Save a folder to a .py or .exe, use the result to extract anywhere, even if you don't have Python!
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
""" | |
Brief: | |
This script makes a self-extracting .py/,exe of a given folder | |
Author: | |
Charles Machalow | |
""" | |
import argparse | |
import base64 | |
import os | |
import subprocess | |
import sys | |
import shutil | |
FILE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
# Get correct executable extension per the OS | |
if os.name == 'nt': | |
EXE = '.exe' | |
else: | |
EXE = '' | |
selfExtractScript=\ | |
"""binaryData=b'''''' | |
''' | |
Brief: | |
This binary file was created by the selfExtractorMakerPyinstaller.py script. | |
When run, it will extract the enclosed zip file to a given location. | |
If no location is given as a parameter, uses the current working directory. | |
Author: | |
Charles Machalow | |
''' | |
import zipfile | |
import sys | |
import os | |
import base64 | |
import argparse | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser(description="Creates a self extracting exe via Pyinstaller") | |
parser.add_argument("-e", "--extraction_directory", help="Location to extract contents to") | |
args = parser.parse_args() | |
if not args.extraction_directory: | |
args.extraction_directory = os.getcwd() | |
print ("Decoding the Base64 Compressed Format...") | |
# todo: come up with piecewise way to create b64 since this won't fit in RAM always. | |
# probably write binaryData to a file then decode the file itself then unzip, etc. | |
b64 = base64.b64decode(binaryData) | |
print ("Completed Decoding") | |
print ("Writing Temp Zip File...") | |
with open('tmp2.zip', 'wb') as f: | |
f.write(b64) | |
print ("Completed Writing Zip File") | |
print ("Getting a File Pointer...") | |
with open('tmp2.zip', 'rb') as f: | |
z = zipfile.ZipFile(f) | |
print ("Extracting to %s" % args.extraction_directory) | |
z.extractall(args.extraction_directory) | |
print ("Closing the File Pointer") | |
os.remove('tmp2.zip') | |
print ("Deleting Temp Zip File") | |
print ("Done!") | |
""" | |
class CwdRecursionError(Exception): | |
pass | |
def checkForCwdRecursionError(folderToLookFor): | |
folderToLookFor = os.path.abspath(folderToLookFor) | |
cwd = os.path.abspath(os.getcwd()) | |
for root, dirs, files in os.walk(folderToLookFor): | |
for name in dirs: | |
testDirectory = os.path.join(root, name) | |
if os.path.abspath(testDirectory) == cwd: | |
raise CwdRecursionError(("The given path (%s) to turn into an extractable file includes where" + | |
" the zip would go! This would lead to an infinite loop!") % folderToLookFor) | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser(description="Creates a self extracting exe via Pyinstaller") | |
parser.add_argument("-f", "--folder", required=True, help="Choose folder to grab") | |
parser.add_argument("-p", "--pyinstaller", action='store_true', default=False, help="Choose folder to grab") | |
parser.add_argument("-n", "--name", help="Output file base name") | |
args = parser.parse_args() | |
directory = args.folder | |
if not os.path.isdir(directory): | |
print ('%s is not a valid directory' % directory) | |
sys.exit(1) | |
checkForCwdRecursionError(directory) # Will throw on infinite recursion error | |
if not args.name: | |
args.name = "autoExtract" | |
print ("Making Temp Zip...") | |
shutil.make_archive('tmp','zip', directory) | |
print ("Creating base64 encode of data...") | |
# Create base64 of file | |
with open('tmp.zip', 'rb') as tz: | |
with open('tmp.base64', 'wb') as t64: | |
base64.encode(tz, t64) | |
# At this point we have tmp.base64 which is the base64 of the raw data | |
with open('%s.py' % args.name, 'w') as f: | |
afterZip = selfExtractScript[15:] | |
beforeZip = selfExtractScript[:15] | |
print ("Writing Python header...") | |
f.write(beforeZip) | |
print ("Beginning piecewise write of base64 data...") | |
with open('tmp.base64', 'r') as t64: | |
# piecewise write to not have all in RAM at once | |
while True: | |
rawBase64Data = str(t64.read(8092)).replace("\r\n", "").replace("\n", "") | |
if len(rawBase64Data) == 0: | |
break | |
f.write(rawBase64Data) | |
print ("Completed piecewise write of base64 data...") | |
print ("Writing Python completer...") | |
f.write(afterZip) | |
if args.pyinstaller: | |
delPyFile = True | |
print ("Beginning pyinstaller build...") | |
try: | |
try: | |
output = subprocess.check_output("pyinstaller %s.py --onefile --log-level=ERROR" % args.name, shell=True, stderr=subprocess.STDOUT).decode() | |
except Exception as ex: | |
output = ex.output.decode() | |
print ("Failed to use pyinstaller to create the exe") | |
if 'MemoryError' in output: | |
raise MemoryError("The pyinstaller system call led to a MemoryError") | |
else: | |
sys.exit(1) | |
print ("Pyinstaller build completed successfully") | |
shutil.copy(FILE_DIR + '/dist/%s%s' % (args.name, EXE), FILE_DIR + '/%s%s' % (args.name, EXE)) | |
except MemoryError as ex: | |
print ("E" * 60) | |
print ("Pyinstaller ran into a MemoryError: %s" % str(ex)) | |
print ("It's quite possible that this file is too large for Pyinstaller to turn into an exe!") | |
print ("Will leave behind the .py file as opposed to deleting since we couldn't generate an exe.") | |
print ("E" * 60) | |
delPyFile = False | |
finally: | |
# Cleanup | |
print ("Cleaning up after pyinstaller") | |
shutil.rmtree(FILE_DIR + '/dist/') | |
shutil.rmtree(FILE_DIR + '/build/') | |
os.remove('%s.spec' % args.name) | |
if delPyFile: | |
os.remove('%s.py' % args.name) | |
print ("Cleaning up tmps...") | |
os.remove('tmp.zip') | |
os.remove("tmp.base64") | |
print ("Done!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment