def generate_keys(interface): set_property("key.alias", "android") set_property("key.store.password", "android") set_property("key.alias.password", "android") default_keystore = plat.path("android.keystore").replace("\\", "/") set_property("key.store", default_keystore) if get_property("key.store") != default_keystore: interface.info(__("You set the keystore yourself, so I'll assume it's how you want it.")) return if os.path.exists(plat.path("android.keystore")): interface.info(__("You've already created an Android keystore, so I won't create a new one for you.")) return if not interface.yesno(__("I can create an application signing key for you. Signing an application with this key allows it to be placed in the Android Market and other app stores.\n\nDo you want to create a key?")): return if not interface.yesno(__("I will create the key in the android.keystore file.\n\nYou need to back this file up. If you lose it, you will not be able to upgrade your application.\n\n\You also need to keep the key safe. If evil people get this file, they could make fake versions of your application, and potentially steal your users' data.\n\nWill you make a backup of android.keystore, and keep it in a safe place?")): return org = interface.input(__("Please enter your name or the name of your organization.")) dname = "CN=" + org if not run(interface, plat.keytool, "-genkey", "-keystore", "android.keystore", "-alias", "android", "-keyalg", "RSA", "-keysize", "2048", "-keypass", "android", "-storepass", "android", "-dname", dname, "-validity", "20000", use_path=True): interface.fail(__("Could not create android.keystore. Is keytool in your path?")) interface.success(__("I've finished creating android.keystore. Please back it up, and keep it in a safe place."))
def copy_presplash(directory, name, default): """ Copies the presplash file. """ for ext in [".png", ".jpg"]: fn = os.path.join(directory, name + ext) if os.path.exists(fn): break else: fn = default ext = os.path.splitext(fn)[1] shutil.copy(fn, plat.path("project/app/src/main/assets/" + name + ext)) for lang in ["en", "jp", "zh"]: for ext in [".png", ".jpg"]: fn = os.path.join(directory, name + "-" + lang + ext) if os.path.exists(fn): shutil.copy( fn, plat.path("project/app/src/main/assets/" + name + "-" + lang + ext)) break
def unpack_ant(interface): if os.path.exists(plat.path("apache-ant")): interface.success("Apache ANT has already been unpacked.") return archive = "apache-ant-1.8.4-bin.tar.gz" unpacked = "apache-ant-1.8.4" url = "http://archive.apache.org/dist/ant/binaries/" + archive interface.info("I'm downloading Apache Ant. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting Apache Ant.") def extract(): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() interface.background(extract) plat.rename(plat.path(unpacked), plat.path("apache-ant")) interface.success("I've finished unpacking Apache Ant.")
def make_tree(src, dest): src = plat.path(src) dest = plat.path(dest) def ignore(dir, files): rv = [ ] for basename in files: fn = os.path.join(dir, basename) relfn = os.path.relpath(fn, src) ignore = False if blacklist.match(relfn): ignore = True if whitelist.match(relfn): ignore = False if ignore: rv.append(basename) return rv shutil.copytree(src, dest, ignore=ignore)
def check_java(interface): """ Checks for the presence of a minimally useful java on the user's system. """ interface.info( __("I'm compiling a short test program, to see if you have a working JDK on your system." )) if not run_slow(interface, plat.javac, plat.path("buildlib/CheckJDK8.java"), use_path=True): interface.fail( __("I was unable to use javac to compile a test file. If you haven't installed the Java Development Kit yet, please download it from:\n\nhttp://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html\n\nThe JDK is different from the JRE, so it's possible you have Java without having the JDK. Without a working JDK, I can't continue." )) if not run_slow(interface, plat.java, "-classpath", plat.path("buildlib"), "CheckJDK8", use_path=True): interface.fail( __("The version of Java on your computer does not appear to be JDK 8, which is the only version supported by the Android SDK. If you need to install JDK 8, you can download it from:\n\nhttp://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html\n\nYou can also set the JAVA_HOME environment variable to use a different version of Java." )) interface.success(__("The JDK is present and working. Good!"))
def make_tree(src, dest): src = plat.path(src) dest = plat.path(dest) def ignore(dir, files): rv = [] for basename in files: fn = os.path.join(dir, basename) relfn = os.path.relpath(fn, src) ignore = False if blacklist.match(relfn): ignore = True if whitelist.match(relfn): ignore = False if ignore: rv.append(basename) return rv shutil.copytree(src, dest, ignore=ignore)
def get_packages(interface): packages = [ ] if not os.path.exists(plat.path("android-sdk/build-tools/" + plat.build_version)): packages.append("build-tools-" + plat.build_version) if not os.path.exists(plat.path("android-sdk/platforms/" + plat.target)): packages.append(plat.target) if not os.path.exists(plat.path("android-sdk/platform-tools/")): packages.append("platform-tools") if packages: interface.info("I'm about to download and install the required Android packages. This might take a while.") if not run_slow(interface, plat.android, "update", "sdk", "-u", "-f", "-a", "-t", ",".join(packages), yes=True): interface.fail("I was unable to install the required Android packages.") interface.info("I'm updating the library packages.") run(interface, plat.android, "update", "project", "-p", plat.path("extras/google/market_licensing/library"), "--target", plat.target) run(interface, plat.android, "update", "project", "-p", plat.path("extras/google/market_apk_expansion/downloader_library"), "--target", plat.target) interface.success("I've finished installing the required Android packages.")
def make_expansion(): zf = zipfile.ZipFile(plat.path(expansion_file), "w", zipfile.ZIP_STORED) zip_directory(zf, "assets") zf.close() # Delete and re-make the assets directory. shutil.rmtree(plat.path("assets")) os.mkdir(plat.path("assets"))
def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) zf.extractall(plat.path(".")) zf.close()
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_{}-windows.zip".format(plat.sdk_version) unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_{}-macosx.zip".format(plat.sdk_version) unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_{}-linux.tgz".format(plat.sdk_version) unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has a old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall(".") os.chdir(old_cwd) zf.close() interface.background(extract) plat.rename(plat.path(unpacked, replace=False), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def generate_keys(interface): # Change this method to allow for custom keystore passwords update_properties = True if os.path.exists(plat.path("local.properties")): with open(plat.path("local.properties")) as f: for l in f: if l.startswith("key.store"): update_properties = False if update_properties: f = file(plat.path("local.properties"), "a") print >>f, "key.alias=android" print >>f, "key.store.password=android" print >>f, "key.alias.password=android" print >>f, "key.store=android.keystore" f.close() if os.path.exists(plat.path("android.keystore")): interface.info("You've already created an Android keystore, so I won't create a new one for you.") return if not interface.yesno("""\ I can create an application signing key for you. Signing an application with this key allows it to be placed in the Android Market and other app stores. Do you want to create a key?"""): return if not interface.yesno("""\ I will create the key in the android.keystore file. You need to back this file up. If you lose it, you will not be able to upgrade your application. You also need to keep the key safe. If evil people get this file, they could make fake versions of your application, and potentially steal your users' data. Will you make a backup of android.keystore, and keep it in a safe place?"""): return org = interface.input("Please enter your name or the name of your organization.") dname = "CN=" + org if not run(interface, plat.keytool, "-genkey", "-keystore", "android.keystore", "-alias", "android", "-keyalg", "RSA", "-keysize", "2048", "-keypass", "android", "-storepass", "android", "-dname", dname, "-validity", "20000", use_path=True): interface.fail("Could not create android.keystore. Is keytool in your path?") interface.success("""I've finished creating android.keystore. Please back it up, and keep it in a safe place.""")
def install_sdk(interface): check_java(interface) unpack_ant(interface) unpack_sdk(interface) if plat.macintosh or plat.linux: os.chmod(plat.path("android-sdk/tools/android"), 0755) os.chmod(plat.path("android-sdk/tools/zipalign"), 0755) get_packages(interface) generate_keys(interface) interface.final_success("It looks like you're ready to start packaging games.")
def generate_keys(interface): update_properties = True if os.path.exists(plat.path("local.properties")): with open(plat.path("local.properties")) as f: for l in f: if l.startswith("key.store"): update_properties = False if update_properties: f = file(plat.path("local.properties"), "a") print >>f, "key.alias=android" print >>f, "key.store.password=android" print >>f, "key.alias.password=android" print >>f, "key.store=android.keystore" f.close() if os.path.exists(plat.path("android.keystore")): interface.info("You've already created an Android keystore, so I won't create a new one for you.") return if not interface.yesno("""\ I can create an application signing key for you. Signing an application with this key allows it to be placed in the Android Market and other app stores. Do you want to create a key?"""): return if not interface.yesno("""\ I will create the key in the android.keystore file. You need to back this file up. If you lose it, you will not be able to upgrade your application. You also need to keep the key safe. If evil people get this file, they could make fake versions of your application, and potentially steal your users' data. Will you make a backup of android.keystore, and keep it in a safe place?"""): return org = interface.input("Please enter your name or the name of your organization.") dname = "CN=" + org if not run(interface, plat.keytool, "-genkey", "-keystore", "android.keystore", "-alias", "android", "-keyalg", "RSA", "-keysize", "2048", "-keypass", "android", "-storepass", "android", "-dname", dname, "-validity", "20000", use_path=True): interface.fail("Could not create android.keystore. Is keytool in your path?") interface.success("""I've finished creating android.keystore. Please back it up, and keep it in a safe place.""")
def extract(): zf = FixedZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has very long filenames. old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall("Sdk") os.chdir(old_cwd) zf.close()
def check_java(interface): """ Checks for the presence of a minimally useful java on the user's system. """ interface.info(__("I'm compiling a short test program, to see if you have a working JDK on your system.")) if not run_slow(interface, plat.javac, plat.path("buildlib/CheckJDK8.java"), use_path=True): interface.fail(__("I was unable to use javac to compile a test file. If you haven't installed the Java Development Kit yet, please download it from:\n\nhttp://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html\n\nThe JDK is different from the JRE, so it's possible you have Java without having the JDK. Without a working JDK, I can't continue.")) if not run_slow(interface, plat.java, "-classpath", plat.path("buildlib"), "CheckJDK8", use_path=True): interface.fail(__("The version of Java on your computer does not appear to be JDK 8, which is the only version supported by the Android SDK. If you need to install JDK 8, you can download it from:\n\nhttp://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html\n\nYou can also set the JAVA_HOME environment variable to use a different version of Java.")) interface.success(__("The JDK is present and working. Good!"))
def copy_libs(): """ This copies updated libraries from the prototype to the project each time a build occurs. """ for i in COPIED: project = plat.path("project/" + i) prototype = plat.path("prototype/" + i) if os.path.exists(project): shutil.rmtree(project) shutil.copytree(prototype, project)
def snarf(fn): fn = plat.path(fn) if os.path.exists(fn): return open(fn, "r").read().strip() else: return None
def distclean(interface): """ Cleans everything back to as it was when RAPT was first distributed. """ if os.path.exists(plat.path("build_renpy.sh")): raise Exception("Can't clean android directory!") def rmdir(name): path = plat.path(name) if os.path.isdir(path): shutil.rmtree(path) def rm(name): path = plat.path(name) if os.path.exists(path): os.unlink(path) rm("buildlib/CheckJDK8.class") rmdir("project") rmdir("bin") try: rmdir("Sdk") except: rm("Sdk")
def rmdir(name, make): path = plat.path(name) if os.path.isdir(path): shutil.rmtree(path) if make: os.mkdir(path)
def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has a old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall(".") os.chdir(old_cwd) zf.close()
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_{}-windows.zip".format(plat.sdk_version) unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_{}-macosx.zip".format(plat.sdk_version) unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_{}-linux.tgz".format(plat.sdk_version) unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) zf.extractall(plat.path(".")) zf.close() interface.background(extract) plat.rename(plat.path(unpacked, replace=False), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def unpack_sdk(interface): if os.path.exists(plat.path("android-sdk")): interface.success("The Android SDK has already been unpacked.") return if "PGS4A_NO_TERMS" not in os.environ: interface.terms("http://developer.android.com/sdk/terms.html", "Do you accept the Android SDK Terms and Conditions?") if plat.windows: archive = "android-sdk_r20-windows.zip" unpacked = "android-sdk-windows" elif plat.macintosh: archive = "android-sdk_r20-macosx.zip" unpacked = "android-sdk-macosx" elif plat.linux: archive = "android-sdk_r20-linux.tgz" unpacked = "android-sdk-linux" url = "http://dl.google.com/android/" + archive interface.info("I'm downloading the Android SDK. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting the Android SDK.") def extract(): if archive.endswith(".tgz"): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() else: zf = zipfile.ZipFile(plat.path(archive)) zf.extractall(plat.path(".")) zf.close() interface.background(extract) plat.rename(plat.path(unpacked), plat.path("android-sdk")) interface.success("I've finished unpacking the Android SDK.")
def get_packages(interface): packages = [ ] if not os.path.exists(plat.path("android-sdk/platforms/android-8")): packages.append("android-8") if not os.path.exists(plat.path("android-sdk/platforms/android-15")): packages.append("android-15") if not os.path.exists(plat.path("android-sdk/platform-tools/")): packages.append("platform-tools") if not os.path.exists(plat.path("android-sdk/extras/google/play_licensing")): packages.append("extra-google-play_licensing") if not os.path.exists(plat.path("android-sdk/extras/google/play_apk_expansion")): packages.append("extra-google-play_apk_expansion") if not packages: interface.success("The required Android packages are already installed.") return interface.info("I'm about to download and install the required Android packages. This might take a while.") if not run_slow(interface, plat.android, "update", "sdk", "-u", "-a", "-t", ",".join(packages)): interface.fail("I was unable to install the required Android packages.") interface.info("I'm updating the library packages.") if "extra-google-play_apk_expansion" in packages: with open(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/project.properties"), "r") as f: data = f.read() data = data.replace("../market_licensing", "../../play_licensing/library") with open(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/project.properties"), "w") as f: f.write(data) run(interface, plat.android, "update", "project", "-p", "android-sdk/extras/google/play_licensing/library") run(interface, plat.android, "update", "project", "-p", "android-sdk/extras/google/play_apk_expansion/downloader_library") if os.path.exists(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/res/values-v9")): shutil.rmtree(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/res/values-v9")) interface.success("I've finished installing the required Android packages.")
def distclean(interface): """ Cleans everything back to as it was when RAPT was first distributed. """ if os.path.exists(plat.path("build_renpy.sh")): raise Exception("Can't clean android directory!") def rmdir(name, make): path = plat.path(name) if os.path.isdir(path): shutil.rmtree(path) if make: os.mkdir(path) def rm(name): path = plat.path(name) if os.path.exists(path): os.unlink(path) rm("android.keystore") rm("AndroidManifest.xml") rmdir("assets", True) rmdir("bin", True) rm("default.properties") rm("build.xml") rmdir("gen", False) rm("local.properties") rm("proguard-project.txt") rm("project.properties") rmdir("android-sdk", False) rmdir("apache-ant", False) for i in os.listdir(plat.path('.')): if i.endswith(".tgz") or i.endswith(".tar.gz") or i.endswith(".zip"): os.unlink(plat.path(i, replace=False))
def make_assets(): if assets_dir is not None: make_tree(assets_dir, plat.path("assets")) else: os.mkdir(plat.path("assets")) # If we're Ren'Py, rename things. if os.path.exists(plat.path("assets/renpy")): # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(plat.path("assets"), topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new)
def zip_directory(zf, dn): """ Zips up the directory `dn`. `zf` is the file to place the contents of the directory into. """ base_dirname = plat.path(dn) for dirname, dirs, files in os.walk(base_dirname): for fn in files: fn = os.path.join(dirname, fn) archive_fn = os.path.join(dn, os.path.relpath(fn, base_dirname)) zf.write(fn, archive_fn)
def render(template, dest, **kwargs): """ Using jinja2, render `template` to the filename `dest`, supplying the keyword arguments as template parameters. """ dest = plat.path(dest) template = environment.get_template(template) text = template.render(**kwargs) f = file(dest, "wb") f.write(text.encode("utf-8")) f.close()
def copy_project(update_always=False): """ This updates the project, if necessary. """ def snarf(fn): fn = plat.path(fn) if os.path.exists(fn): return open(fn, "r").read().strip() else: return None project = plat.path("project") prototype = plat.path("prototype") update = False if not os.path.exists(project): update = True elif update_always: if snarf("project/build.txt") != snarf("prototype/build.txt"): update = True if not update: return lp = snarf("project/local.properties") if os.path.exists(project): shutil.rmtree(project) shutil.copytree(prototype, project) if lp is not None: with open(plat.path("project/local.properties"), "w") as f: f.write(lp + "\n")
def check_java(interface): """ Checks for the presence of a minimally useful java on the user's system. """ interface.info("""\ I'm compiling a short test program, to see if you have a working JDK on your system. """) SOURCE = """\ class test { public static void main(String args[]) { } } """ f = file(plat.path("test.java"), "w") f.write(SOURCE) f.close() if not run_slow(interface, plat.javac, "test.java", use_path=True): interface.fail("""\ I was unable to use javac to compile a test file. If you haven't installed the Java Development Kit yet, please download it from: http://www.oracle.com/technetwork/java/javase/downloads/index.html The JDK is different from the JRE, so it's possible you have Java without having the JDK. Without a working JDK, I can't continue. """) interface.success("The JDK is present and working. Good!") os.unlink(plat.path("test.java")) os.unlink(plat.path("test.class"))
def unpack_ant(interface): if os.path.exists(plat.path("apache-ant")): interface.success("Apache ANT has already been unpacked.") return archive = "apache-ant-1.9.3-bin.tar.gz" unpacked = "apache-ant-1.9.3" url = "http://archive.apache.org/dist/ant/binaries/" + archive interface.info("I'm downloading Apache Ant. This might take a while.") interface.download(url, plat.path(archive)) interface.info("I'm extracting Apache Ant.") def extract(): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close() interface.background(extract) interface.success("I've finished unpacking Apache Ant.")
def copy_presplash(directory, name, default): """ Copies the presplash file. """ for ext in [ ".png", ".jpg" ]: fn = os.path.join(directory, name + ext) if os.path.exists(fn): break else: fn = default ext = os.path.splitext(fn)[1] shutil.copy(fn, plat.path("assets/" + name + ext))
def unpack_sdk(interface): if os.path.exists(plat.sdkmanager): interface.success(__("The Android SDK has already been unpacked.")) return if "RAPT_NO_TERMS" not in os.environ: interface.terms( "https://developer.android.com/studio/terms", __("Do you accept the Android SDK Terms and Conditions?")) if plat.windows: archive = "sdk-tools-windows-{}.zip".format(plat.sdk_version) elif plat.macintosh: archive = "sdk-tools-darwin-{}.zip".format(plat.sdk_version) elif plat.linux: archive = "sdk-tools-linux-{}.zip".format(plat.sdk_version) url = "https://dl.google.com/android/repository/" + archive interface.info( __("I'm downloading the Android SDK. This might take a while.")) interface.download(url, plat.path(archive)) interface.info(__("I'm extracting the Android SDK.")) def extract(): zf = FixedZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has very long filenames. old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall("Sdk") os.chdir(old_cwd) zf.close() interface.background(extract) interface.success(__("I've finished unpacking the Android SDK."))
def unpack_sdk(interface): if os.path.exists(plat.sdkmanager): interface.success(__("The Android SDK has already been unpacked.")) return if "RAPT_NO_TERMS" not in os.environ: interface.terms("https://developer.android.com/studio/terms", __("Do you accept the Android SDK Terms and Conditions?")) if plat.windows: archive = "sdk-tools-windows-{}.zip".format(plat.sdk_version) elif plat.macintosh: archive = "sdk-tools-darwin-{}.zip".format(plat.sdk_version) elif plat.linux: archive = "sdk-tools-linux-{}.zip".format(plat.sdk_version) url = "https://dl.google.com/android/repository/" + archive interface.info(__("I'm downloading the Android SDK. This might take a while.")) interface.download(url, plat.path(archive)) interface.info(__("I'm extracting the Android SDK.")) def extract(): zf = FixedZipFile(plat.path(archive)) # We have to do this because Python has a small (260?) path length # limit on windows, and the Android SDK has very long filenames. old_cwd = os.getcwd() os.chdir(plat.path(".")) zf.extractall("Sdk") os.chdir(old_cwd) zf.close() interface.background(extract) interface.success(__("I've finished unpacking the Android SDK."))
def edit_file(fn, pattern, line): """ Replaces lines in `fn` that begin with `pattern` with `line`. `line` should not end with a newline - we add it. """ fn = plat.path(fn) lines = [] with open(fn, "r") as f: for l in f: if re.match(pattern, l): l = line + "\n" lines.append(l) with open(fn, "w") as f: f.write(''.join(lines))
def edit_file(fn, pattern, line): """ Replaces lines in `fn` that begin with `pattern` with `line`. `line` should not end with a newline - we add it. """ fn = plat.path(fn) lines = [ ] with open(fn, "r") as f: for l in f: if re.match(pattern, l): l = line + "\n" lines.append(l) with open(fn, "w") as f: f.write(''.join(lines))
def __init__(self, *args): self.patterns = [] for i in args: self.load(plat.path(i))
def get_packages(interface): packages = [ ] if not os.path.exists(plat.path("android-sdk/build-tools/19.0.3")): packages.append("build-tools-19.0.3") if not os.path.exists(plat.path("android-sdk/platforms/android-8")): packages.append("android-8") if not os.path.exists(plat.path("android-sdk/platforms/android-15")): packages.append("android-15") if not os.path.exists(plat.path("android-sdk/platform-tools/")): packages.append("platform-tools") if not os.path.exists(plat.path("android-sdk/extras/google/play_licensing")): packages.append("extra-google-play_licensing") if not os.path.exists(plat.path("android-sdk/extras/google/play_apk_expansion")): packages.append("extra-google-play_apk_expansion") if not packages: interface.success("The required Android packages are already installed.") return interface.info("I'm about to download and install the required Android packages. This might take a while.") if not run_slow(interface, plat.android, "update", "sdk", "-u", "-f", "-a", "-t", ",".join(packages), yes=True): interface.fail("I was unable to install the required Android packages.") interface.info("I'm updating the library packages.") if "extra-google-play_apk_expansion" in packages: with open(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/project.properties"), "r") as f: data = f.read() data = data.replace("../market_licensing", "../../play_licensing/library") with open(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/project.properties"), "w") as f: f.write(data) run(interface, plat.android, "update", "project", "-p", plat.path("android-sdk/extras/google/play_licensing/library")) run(interface, plat.android, "update", "project", "-p", plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library")) if os.path.exists(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/res/values-v9")): shutil.rmtree(plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library/res/values-v9")) interface.success("I've finished installing the required Android packages.")
pattern = pattern[1:] pattern = pattern[1:] regexp += ']' else: regexp += re.escape(pattern[0]) pattern = pattern[1:] regexp += "$" return re.compile(regexp, re.I) # Used by render. environment = jinja2.Environment(loader=jinja2.FileSystemLoader(plat.path(''))) def render(always, template, dest, **kwargs): """ Using jinja2, render `template` to the filename `dest`, supplying the keyword arguments as template parameters. """ dest = plat.path(dest) if (not always) and os.path.exists(dest): return template = environment.get_template(template) text = template.render(**kwargs)
def make_tar(iface, fn, source_dirs): """ Make a zip file `fn` from the contents of source_dis. """ source_dirs = [plat.path(i) for i in source_dirs] def include(fn): rv = True if blacklist.match(fn): rv = False if whitelist.match(fn): rv = True return rv # zf = zipfile.ZipFile(fn, "w") tf = tarfile.open(fn, "w:gz", format=tarfile.USTAR_FORMAT) added = set() def add(fn, relfn): adds = [] while relfn: adds.append((fn, relfn)) fn = os.path.dirname(fn) relfn = os.path.dirname(relfn) adds.reverse() for fn, relfn in adds: if relfn not in added: added.add(relfn) tf.add(fn, relfn, recursive=False) for sd in source_dirs: if PYTHON and not RENPY: compile_dir(iface, sd) sd = os.path.abspath(sd) for dir, dirs, files in os.walk(sd): # @ReservedAssignment for _fn in dirs: fn = os.path.join(dir, _fn) relfn = os.path.relpath(fn, sd) if include(relfn): add(fn, relfn) for fn in files: fn = os.path.join(dir, fn) relfn = os.path.relpath(fn, sd) if include(relfn): add(fn, relfn) tf.close()
def extract(): tf = tarfile.open(plat.path(archive), "r:*") tf.extractall(plat.path(".")) tf.close()
def rm(name): path = plat.path(name) if os.path.exists(path): os.unlink(path)
def rmdir(name): path = plat.path(name) if os.path.isdir(path): shutil.rmtree(path)
def build(iface, directory, commands, launch=False, finished=None): # Are we doing a Ren'Py build? global RENPY if not os.path.isdir(directory): iface.fail(__("{} is not a directory.").format(directory)) if os.path.isdir(os.path.join(directory, "renpy")): RENPY = True else: RENPY = False if RENPY and not os.path.isdir(os.path.join(directory, "game")): iface.fail(__("{} does not contain a Ren'Py game.").format(directory)) config = configure.Configuration(directory) if config.package is None: iface.fail(__("Run configure before attempting to build the app.")) if (config.store == "play" or config.store == "all") and ((config.google_play_key is None) or (len(config.google_play_key) < 32)): iface.fail( __("Google Play support is enabled, but build.google_play_key is not defined." )) global blacklist global whitelist blacklist = PatternList("blacklist.txt") whitelist = PatternList("whitelist.txt") if RENPY: default_presplash = plat.path("templates/renpy-presplash.jpg") private_dir, assets_dir = split_renpy(directory) else: default_presplash = plat.path("templates/pygame-presplash.jpg") if config.layout == "internal": private_dir = directory assets_dir = None elif config.layout == "split": private_dir = join_and_check(directory, "internal") assets_dir = join_and_check(directory, "assets") versioned_name = config.name versioned_name = re.sub(r'[^\w]', '', versioned_name) versioned_name += "-" + config.version # Annoying fixups. config.name = config.name.replace("'", "\\'") config.icon_name = config.icon_name.replace("'", "\\'") if config.store not in ["play", "none"]: config.expansion = False iface.info(__("Updating project.")) copy_project(config.update_always) copy_libs() iface.info(__("Creating assets directory.")) assets = plat.path("project/app/src/main/assets") if os.path.isdir(assets): shutil.rmtree(assets) def make_assets(): if assets_dir is not None: make_tree(assets_dir, assets) else: os.mkdir(assets) # If we're Ren'Py, rename things. if RENPY: # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(assets, topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new) iface.background(make_assets) if not os.path.exists(plat.path("bin")): os.mkdir(plat.path("bin"), 0o777) if config.expansion: iface.info(__("Creating expansion file.")) expansion_file = "bin/main.{}.{}.obb".format(config.numeric_version, config.package) def make_expansion(): zf = zipfile.ZipFile(plat.path(expansion_file), "w", zipfile.ZIP_STORED) zip_directory(zf, "assets", assets) zf.close() # Delete and re-make the assets directory. shutil.rmtree(assets) os.mkdir(assets) iface.background(make_expansion) # Write the file size into DownloaderActivity. file_size = os.path.getsize(plat.path(expansion_file)) else: expansion_file = None file_size = 0 iface.info(__("Packaging internal data.")) private_dirs = ['project/renpyandroid/src/main/private'] if private_dir is not None: private_dirs.append(private_dir) # Really, a tar file with the private data in it. private_mp3 = os.path.join(assets, "private.mp3") private_version = [] def pack(): make_tar(iface, private_mp3, private_dirs) with open(private_mp3, "rb") as f: private_version.append(hashlib.md5(f.read()).hexdigest()) iface.background(pack) private_version = private_version[0] # Write out constants.java. if not config.google_play_key: config.google_play_key = "NOT_SET" if not config.google_play_salt: config.google_play_salt = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20" for always, template, i in GENERATED: render( always or config.update_always, template, i, private_version=private_version, file_size=file_size, config=config, sdkpath=plat.path("Sdk"), ) if config.update_icons: iconmaker.IconMaker(directory, config) # Copy the presplash files. copy_presplash(directory, "android-presplash", default_presplash) # Find and clean the apkdirs. apkdirs = [] if any(i.endswith("Debug") for i in commands): apkdirs.append(plat.path("project/app/build/outputs/apk/debug")) if any(i.endswith("Release") for i in commands): apkdirs.append(plat.path("project/app/build/outputs/apk/release")) for i in apkdirs: if os.path.exists(i): shutil.rmtree(i) # Build. iface.info(__("I'm using Gradle to build the package.")) # This is a list of generated files that need to be copied over to the # dists folder. files = [] try: iface.call([plat.gradlew, "--stacktrace", "-p", plat.path("project")] + commands, cancel=True) if (expansion_file is not None) and any( i.startswith("install") for i in commands): iface.info(__("Uploading expansion file.")) dest = "/storage/emulated/0/Android/obb/{}/{}".format( config.package, os.path.basename(expansion_file)) iface.call([plat.adb, "push", plat.path(expansion_file), dest], cancel=True) if expansion_file is not None: files.append(plat.path(expansion_file)) except subprocess.CalledProcessError: iface.fail(__("The build seems to have failed.")) # Copy everything to bin. for i in apkdirs: for j in os.listdir(i): if not j.endswith(".apk"): continue sfn = os.path.join(i, j) dfn = "bin/{}-{}".format(config.package, j[4:]) dfn = plat.path(dfn) shutil.copy(sfn, dfn) files.append(dfn) # Launch. if launch: iface.info(__("Launching app.")) if expansion_file: launch_activity = "DownloaderActivity" else: launch_activity = "PythonSDLActivity" iface.call([ plat.adb, "shell", "am", "start", "-W", "-a", "android.intent.action.MAIN", "{}/org.renpy.android.{}".format(config.package, launch_activity), ], cancel=True) if finished is not None: finished(files) iface.final_success( __("The build seems to have succeeded.") + "\n\n" + __("The arm64-v8a version works on newer Android devices, the armeabi-v7a version works on older devices, and the x86_64 version works on the simulator and chromebooks." ))
def pack(): make_tar(plat.path("assets/private.mp3"), private_dirs)
def build(iface, directory, commands): # Are we doing a Ren'Py build? global RENPY RENPY = plat.renpy if not os.path.isdir(directory): iface.fail("{} is not a directory.".format(directory)) if RENPY and not os.path.isdir(os.path.join(directory, "game")): iface.fail("{} does not contain a Ren'Py game.".format(directory)) config = configure.Configuration(directory) if config.package is None: iface.fail("Run configure before attempting to build the app.") global blacklist global whitelist blacklist = PatternList("blacklist.txt") whitelist = PatternList("whitelist.txt") if RENPY: manifest_extra = None default_icon = plat.path("templates/renpy-icon.png") default_presplash = plat.path("templates/renpy-presplash.jpg") public_dir = None private_dir = None assets_dir = directory else: manifest_extra = "" default_icon = plat.path("templates/pygame-icon.png") default_presplash = plat.path("templates/pygame-presplash.jpg") if config.layout == "internal": private_dir = directory public_dir = None assets_dir = None elif config.layout == "external": private_dir = None public_dir = directory assets_dir = None elif config.layout == "split": private_dir = join_and_check(directory, "internal") public_dir = join_and_check(directory, "external") assets_dir = join_and_check(directory, "assets") versioned_name = config.name.replace(" ", "").replace("'", "") + "-" + config.version # Annoying fixups. config.name = config.name.replace("'", "\\'") config.icon_name = config.icon_name.replace("'", "\\'") # Figure out versions of the private and public data. private_version = str(time.time()) if public_dir: public_version = private_version else: public_version = None # Render the various templates into control files. render( "AndroidManifest.tmpl.xml", "AndroidManifest.xml", config = config, manifest_extra = manifest_extra, ) render( "strings.xml", "res/values/strings.xml", public_version = public_version, private_version = private_version, config = config) try: os.unlink(plat.path("build.xml")) except: pass iface.info("Updating source code.") edit_file("src/org/renpy/android/DownloaderActivity.java", r'import .*\.R;', 'import {}.R;'.format(config.package)) iface.info("Updating build files.") # Update the project to a recent version. iface.call([plat.android, "update", "project", "-p", '.', '-t', 'android-8', '-n', versioned_name, # "--library", "android-sdk/extras/google/play_licensing/library", "--library", plat.path("android-sdk/extras/google/play_apk_expansion/downloader_library", relative=True), ]) iface.info("Creating assets directory.") if os.path.isdir(plat.path("assets")): shutil.rmtree(plat.path("assets")) def make_assets(): if assets_dir is not None: make_tree(assets_dir, plat.path("assets")) else: os.mkdir(plat.path("assets")) # If we're Ren'Py, rename things. if os.path.exists(plat.path("assets/renpy")): # Ren'Py uses a lot of names that don't work as assets. Auto-rename # them. for dirpath, dirnames, filenames in os.walk(plat.path("assets"), topdown=False): for fn in filenames + dirnames: if fn[0] == ".": continue old = os.path.join(dirpath, fn) new = os.path.join(dirpath, "x-" + fn) plat.rename(old, new) iface.background(make_assets) if config.expansion: iface.info("Creating expansion file.") expansion_file = "main.{}.{}.obb".format(config.numeric_version, config.package) def make_expansion(): zf = zipfile.ZipFile(plat.path(expansion_file), "w", zipfile.ZIP_STORED) zip_directory(zf, "assets") zf.close() # Delete and re-make the assets directory. shutil.rmtree(plat.path("assets")) os.mkdir(plat.path("assets")) iface.background(make_expansion) # Write the file size into DownloaderActivity. file_size = os.path.getsize(plat.path(expansion_file)) edit_file("src/org/renpy/android/DownloaderActivity.java", r' private int fileVersion =', ' private int fileVersion = {};'.format(config.numeric_version)) edit_file("src/org/renpy/android/DownloaderActivity.java", r' private int fileSize =', ' private int fileSize = {};'.format(file_size)) else: expansion_file = None # Update the GP key and salt. if config.google_play_key: edit_file("src/org/renpy/android/DownloaderService.java", r' private static final String BASE64_PUBLIC_KEY', ' private static final String BASE64_PUBLIC_KEY = "%s";' % config.google_play_key) if config.google_play_salt: edit_file("src/org/renpy/android/DownloaderService.java", r' private static final byte\[\] SALT', ' private static final byte[] SALT = new byte[] { %s };' % config.google_play_salt) iface.info("Packaging internal data.") private_dirs = [ 'private' ] if private_dir is not None: private_dirs.append(private_dir) if os.path.exists(plat.path("engine-private")): private_dirs.append(plat.path("engine-private")) def pack(): make_tar(plat.path("assets/private.mp3"), private_dirs) iface.background(pack) if public_dir is not None: iface.info("Packaging external data.") make_tar(plat.path("assets/public.mp3"), [ public_dir ]) # Copy over the icon and presplash files. copy_icon(directory, "icon.png", default_icon) copy_icon(directory, "presplash.jpg", default_presplash) # Copy over the OUYA icon. ouya_icon = join_and_check(directory, "ouya-icon.png") or join_and_check(directory, "ouya_icon.png") if ouya_icon: if not os.path.exists(plat.path("res/drawable-xhdpi")): os.mkdir(plat.path("res/drawable-xhdpi")) shutil.copy(ouya_icon, plat.path("res/drawable-xhdpi/ouya_icon.png")) # Build. iface.info("I'm using Ant to build the package.") try: # Clean is required, so we don't use old code. iface.call([plat.ant, "clean"] + commands, cancel=True) if (expansion_file is not None) and ("install" in commands): iface.info("Uploading expansion file.") dest = "/mnt/sdcard/{}".format(expansion_file) iface.call([ plat.adb, "push", plat.path(expansion_file), dest ], cancel=True) if expansion_file is not None: plat.rename(plat.path(expansion_file), plat.path("bin/" + expansion_file)) except subprocess.CalledProcessError: iface.fail("The build seems to have failed.") iface.final_success("The build seems to have succeeded.")
def pack(): make_tar(iface, plat.path("assets/private.mp3"), private_dirs)