-
-
Save AGulev/334e478580f648cb07a03770379d303b to your computer and use it in GitHub Desktop.
For building and deploying Defold projects directly to your phone
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
""" | |
Builder is built by wrapping adb and storing some data locally | |
I would recommend to add an alias to your ~.bash_profile to use it easier | |
alias builder="python3.5 ~/Documents/repo/builder/builder.py" | |
Usage: | |
builder.py [command] [arguments] | |
Available Commands: | |
build build [location of a project] | |
install install [path to APK] | |
uninstall uninstall [bundle id] | |
start start [bundle id] | |
listen listen | |
bob bob commands | |
In addition to specify the location or id you can chose "this project" or "latest project" when supplying arguments to | |
build, install, uninstall and start. By using "builder build ." you say "use this project" and with just "builder build" | |
you say "use latest project" | |
""" | |
import sys | |
assert sys.version_info >= (3, 2), "Requires a python version of 3.2 or higher" | |
from subprocess import call | |
import argparse | |
import os | |
import configparser | |
try: | |
import requests | |
except ImportError: | |
print("requests not found, install with `pip install requests`") | |
sys.exit(1) | |
__version__ = "2.0.1" | |
CACHE_DIR = os.path.join(os.path.expanduser("~"), ".builder", "cache") | |
def get_session_value(project, key): | |
session = get_session_file() | |
if project in session.sections(): | |
return session.get(project, key) if session.has_option(project, key) else None | |
def get_session_file(): | |
path = os.path.join(CACHE_DIR, "session") | |
if not os.path.exists(path): | |
if not os.path.exists(CACHE_DIR): | |
os.makedirs(CACHE_DIR, exist_ok=True) | |
config = configparser.RawConfigParser() | |
config.add_section('config') | |
config.set('config', 'latest', ".") | |
config.set('config', 'output', os.path.join(CACHE_DIR, "output")) | |
with open(path, 'w') as f: | |
config.write(f) | |
session = configparser.ConfigParser() | |
session.read(path) | |
return session | |
def get_project_file(folder): | |
for x in os.listdir(folder): | |
if x.endswith(".project"): | |
return os.path.join(folder, x) | |
print("Can not find project file in this location {}".format(folder)) | |
sys.exit(1) | |
def project_info(project_file): | |
config = configparser.ConfigParser() | |
config.read(project_file) | |
title = config.get("project", "title", fallback="Unnamed") | |
android_id = config.get("android", "package", fallback="com.example.todo") | |
return title, android_id | |
def _update_config(name, key, value): | |
path = os.path.join(CACHE_DIR, "session") | |
session = get_session_file() | |
if name not in session.sections(): | |
session.add_section(name) | |
session.remove_option(name, key) | |
session.set(name, key, value) | |
with open(path, 'w') as f: | |
session.write(f) | |
def this_project(args): | |
project = os.path.abspath(args.file[0]) | |
name, android_id = project_info(get_project_file(project)) | |
return name, project, android_id | |
def latest_project(_): | |
name = get_session_value("config", "latest") | |
project = get_session_value(name, "root") | |
android_id = get_session_value(name, "android_id") | |
if name and project and android_id: | |
return name, project, android_id | |
print("Project with name '{}' have never been built, try 'build .'".format(name)) | |
sys.exit(1) | |
# ------------------ B U I L D ------------------ # | |
def do_build(args): | |
bob_warning() | |
bob = get_session_value("config", "bob") | |
save_config = True | |
if not bob or not os.path.exists(bob): | |
print('Please update or set bob "builder bob --update"') | |
sys.exit(0) | |
output = get_session_value("config", "output") | |
if not args.file: | |
name, project, android_id = latest_project(args) | |
elif args.file[0] == ".": | |
name, project, android_id = this_project(args) | |
_update_config("config", "latest", name) | |
else: | |
save_config = False | |
project = args.file[0] | |
name, android_id = project_info(get_project_file(project)) | |
print("Building project '{}'".format(name)) | |
os.chdir(project) | |
call(["java", "-jar", bob, "--archive", "--platform", "armv7-android", "--bundle-output", output, | |
"--texture-compression", "true", "distclean", "build", "bundle"]) | |
if save_config: | |
title, android = project_info(get_project_file(project)) | |
_update_config(name, "root", project) | |
_update_config(name, "android_id", android) | |
_update_config(name, "build", os.path.join(output, title, "{}.apk".format(title))) | |
# ------------------ I N S T A L L ------------------ # | |
def do_install(args): | |
if args.force: | |
do_uninstall(args) | |
if not args.file: | |
name, _, _ = latest_project(args) | |
bundle = get_session_value(name, "build") | |
elif args.file[0] == ".": | |
name, _, _ = this_project(args) | |
bundle = os.path.join(get_session_value("config", "output"), name, "{}.apk".format(name)) | |
_update_config("config", "latest", name) | |
else: | |
bundle = args.file[0] | |
call(["adb", "install", bundle]) | |
# ------------------ L I S T E N ------------------ # | |
def do_listen(_): | |
call(["adb", "logcat", "-s", "defold"]) | |
# ------------------ S T A R T ------------------ # | |
def do_start(args): | |
if not args.file: | |
name, _, _ = latest_project(args) | |
android_id = get_session_value(name, "android_id") | |
elif args.file[0] == ".": | |
name, _, android_id = this_project(args) | |
_update_config("config", "latest", name) | |
else: | |
android_id = args.file[0] | |
call(["adb", "shell", "am", "start", "-n", "{}/com.dynamo.android.DefoldActivity".format(android_id)]) | |
# ------------------ U N I N S T A L L ------------------ # | |
def do_uninstall(args): | |
if not args.file: | |
name, _, android_id = latest_project(args) | |
elif args.file[0] == ".": | |
name, _, android_id = this_project(args) | |
_update_config("config", "latest", name) | |
else: | |
android_id = args.file[0] | |
if not android_id: | |
print("Please specify a bundle id to uninstall") | |
sys.exit(0) | |
call(["adb", "uninstall", android_id]) | |
# ------------------ B U I L D E R ------------------ # | |
def builder(): | |
parser = argparse.ArgumentParser(description='Builder') | |
sub_parsers = parser.add_subparsers() | |
sub_build = sub_parsers.add_parser("build") | |
sub_build.add_argument("file", help="working directory", nargs="?") | |
sub_build.set_defaults(func=do_build) | |
sub_install = sub_parsers.add_parser("install") | |
sub_install.add_argument("file", help="what to install", nargs="?") | |
sub_install.add_argument("--force", help="force installation by uninstalling first", action='store_true') | |
sub_install.set_defaults(func=do_install) | |
sub_uninstall = sub_parsers.add_parser("uninstall") | |
sub_uninstall.add_argument("file", help="which app to uninstall", nargs="?") | |
sub_uninstall.set_defaults(func=do_uninstall) | |
sub_start = sub_parsers.add_parser("start") | |
sub_start.add_argument("file", help="which app to start", nargs="?") | |
sub_start.set_defaults(func=do_start) | |
sub_listen = sub_parsers.add_parser("listen") | |
sub_listen.set_defaults(func=do_listen) | |
sub_bob = sub_parsers.add_parser("bob") | |
sub_bob.add_argument("--update", help="update bob", action='store_true') | |
sub_bob.add_argument("--force", help="force download of bob", action='store_true') | |
sub_bob.add_argument("--set", help="download a specific version of bob", nargs=1) | |
sub_bob.add_argument("--no-warning", help="stop builder from warning if bob is out of date", nargs=1) | |
sub_bob.set_defaults(func=do_bob) | |
input_args = parser.parse_args() | |
input_args.func(input_args) | |
# ------------------ B O B ------------------ # | |
def download_bob(sha): | |
print("Downloading new bob {}".format(sha)) | |
bob_url = "http://d.defold.com/archive/{}/bob/bob.jar".format(sha) | |
if not os.path.exists(os.path.join(CACHE_DIR, "bob")): | |
os.makedirs(os.path.join(CACHE_DIR, "bob"), exist_ok=True) | |
target = os.path.join(CACHE_DIR, "bob", "bob_{}.jar".format(sha)) | |
r = requests.get(bob_url, stream=True) | |
with open(target, "wb") as f: | |
total_size = int(r.headers.get('content-length', 0)) | |
if total_size: | |
dl = 0 | |
for data in r.iter_content(chunk_size=4096): | |
dl += len(data) | |
f.write(data) | |
# Progressbar | |
done = int(50 * dl / total_size) | |
sys.stdout.write("\r[%s%s]" % ('=' * done, ' ' * (50 - done))) | |
sys.stdout.flush() | |
else: | |
f.write(r.content) | |
_update_config("config", "bob", target) | |
def update_bob(sha, force): | |
target = os.path.join(CACHE_DIR, "bob", "bob_{}.jar".format(sha)) | |
if force or not os.path.exists(target): | |
download_bob(sha) | |
else: | |
_update_config("config", "bob", target) | |
def do_bob(args): | |
if args.no_warning: | |
if args.no_warning[0] in ["True", "true", True, 1]: | |
_update_config("config", "no_warning", True) | |
else: | |
_update_config("config", "no_warning", False) | |
if args.update: | |
latest = requests.get("http://d.defold.com/stable/info.json").json()["sha1"] | |
update_bob(latest, args.force) | |
elif args.set: | |
if not requests.head("http://d.defold.com/archive/{}/bob/bob.jar".format(args.set[-1])).status_code < 400: | |
print("Can't find specified bob version") | |
else: | |
update_bob(args.set[-1], args.force) | |
else: | |
v = get_session_value("config", "bob") | |
v = v.split("bob_")[-1] | |
v = v.split(".jar")[0] | |
print("Using version {}".format(v)) | |
def bob_warning(): | |
if get_session_value("config", "no_warning"): | |
return | |
latest = requests.get("http://d.defold.com/stable/info.json").json()["sha1"] | |
if latest not in get_session_value("config", "bob"): | |
print( | |
"bob is out of date update with 'builder bob --update'. Suppress this with builder 'bob --no-warning'") | |
if __name__ == '__main__': | |
try: | |
builder() | |
except KeyboardInterrupt: | |
sys.exit() | |
except: | |
raise |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment