From 5fb73f6c0b1e21685ab11828e3f6054482753191 Mon Sep 17 00:00:00 2001 From: Raphael Roberts Date: Mon, 9 Sep 2019 22:41:08 -0500 Subject: [PATCH] Finished setup.py and nearly done with compile/execute stages --- .gitignore | 2 + android_java/__init__.py | 29 ++++++++++++++ android_java/compile.py | 50 +++++++++++++++++++++++++ android_java/exceptions.py | 13 +++++++ android_java/execute.py | 18 +++++++++ android_java/{analyse.py => install.py} | 0 requirements.txt | 0 setup.py | 32 +++++++--------- 8 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 .gitignore create mode 100644 android_java/exceptions.py rename android_java/{analyse.py => install.py} (100%) create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..958dabe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.venv +/android_java/temp.py diff --git a/android_java/__init__.py b/android_java/__init__.py index e69de29..97ee4a6 100644 --- a/android_java/__init__.py +++ b/android_java/__init__.py @@ -0,0 +1,29 @@ +import argparse + + +def do_compile(args): + pass + + +def do_run(args): + pass + + +def main(): + parser = argparse.ArgumentParser(prog="droid") + subparsers: argparse._SubParsersAction = parser.add_subparsers(dest="mode") + compile_parser = subparsers.add_parser("compile", help="Compile source file") + compile_parser.add_argument( + "SourceFile.java", help="The source file to compile/create dex for" + ) + + java_parser = subparsers.add_parser( + "run", + help="Run main method of class. Ensure you are in the same directory as the source file", + ) + java_parser.add_argument("MainClass", help="The class to run.") + args = parser.parse_args() + if args.mode == "compile": + do_compile(args) + elif args.mode == "run": + do_run(args) diff --git a/android_java/compile.py b/android_java/compile.py index e69de29..408e438 100644 --- a/android_java/compile.py +++ b/android_java/compile.py @@ -0,0 +1,50 @@ +import os +import subprocess + +os.mkdir + + +def make_droid_dir(root): + droid_dir = os.path.join(root, ".droid") + os.makedirs(droid_dir, exist_ok=True) + return droid_dir + + +class CompilerStage: + def __init__(self, source_root): + self.source_root = source_root + self.droid_dir = make_droid_dir(source_root) + + def create_ecj_command(self): + cmdline = ["ecj"] + cmdline += ["-d", self.droid_dir] + return cmdline + + def compile(self, class_file): + command = self.create_ecj_command() + command.append(class_file) + subprocess.check_call(command) + + def dx_command_batches(self): + i = 0 + current_batch_template = [ + "dx", + "--dex", + "--output={}".format(os.path.join(self.droid_dir, "classes.dex")), + ] + current_batch = current_batch_template.copy() + for root, _, files in os.walk(self.droid_dir): + for file in (os.path.join(root, file) for file in files): + if file.endswith(".class"): + current_batch.append(file) + i += 1 + if i == 100: + yield current_batch + current_batch = current_batch_template.copy() + i = 0 + if i != 100: + yield current_batch + + def compile_dex(self): + for batch in self.dx_command_batches(): + subprocess.check_call(batch) diff --git a/android_java/exceptions.py b/android_java/exceptions.py new file mode 100644 index 0000000..a30ab3d --- /dev/null +++ b/android_java/exceptions.py @@ -0,0 +1,13 @@ +class DroidError(Exception): + def __init__(self, root): + self.root = root + + +class CompilationError(DroidError): + pass + + +class NoClassesFoundError(DroidError): + def __init__(self, root): + super().__init__(self, root) + self.message = "No classes.dex file found in {}".format(self.root) diff --git a/android_java/execute.py b/android_java/execute.py index e69de29..324ccf1 100644 --- a/android_java/execute.py +++ b/android_java/execute.py @@ -0,0 +1,18 @@ +import os +import subprocess +from android_java.exceptions import NoClassesFoundError + + +class ExecutionStatge: + def __init__(self, source_root): + self.source_root = source_root + self.droid_dir = os.path.join(source_root, ".droid") + + def execute_main_class(self, classname): + classes_dex_file = os.path.join(self.droid_dir, "classes.dex") + if not os.path.exists(classes_dex_file): + raise NoClassesFoundError(self.source_root) + + dalvik_vm_args = ["dalvikvm", "-cp", classes_dex_file] + dalvik_vm_args.append(classname) + subprocess.check_call(dalvik_vm_args) diff --git a/android_java/analyse.py b/android_java/install.py similarity index 100% rename from android_java/analyse.py rename to android_java/install.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index 70a7139..e6d1684 100644 --- a/setup.py +++ b/setup.py @@ -1,26 +1,22 @@ from setuptools import setup, find_packages -with open('requirements.txt') as file: - INSTALL_REQUIRES = file.read().rstrip().split('\n') +with open("requirements.txt") as file: + INSTALL_REQUIRES = file.read().rstrip().split("\n") setup( - name='ctabus', - version='2.1.3', - description='Python package for tracking cta bus times', + name="android_java", + version="1.0", + description="Python module to compile, dex, and run java programs", install_requires=INSTALL_REQUIRES, - author='rlbr', - author_email='raphael.roberts48@gmail.com', + author="Raphael Roberts", + author_email="raphael.roberts48@gmail.com", packages=find_packages(), - entry_points={ - 'console_scripts': ['ctabus=ctabus:main'] - }, + entry_points={"console_scripts": ["droid=android_java:main"]}, classifiers=[ - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - - ] - + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + ], )