PKeH?t@android_debian_builder-1.1.0.data/scripts/android-debian-builder#!python # -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- from android_debian_builder.script import main if __name__ == "__main__": main() PK.eHL..oandroid_debian_builder/util.py# -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from contextlib import contextmanager import os import pkgutil import shutil import subprocess import sys import tempfile import time def call(args, *pos_args, **kwargs): """Run the command with `subprocess.check_call`. If the first element of `args` is not an absolute path, it is looked up using `shutil.which` and the resulting binary is run, if any. >>> call(["true"]) 0 >>> call(["this-does-not-exist"]) Traceback (most recent call last): ... OSError: `this-does-not-exist` not found """ cmd = args[0] binary = shutil.which(cmd) if not binary: raise OSError("`%s` not found" % cmd) copied_args = args[:] copied_args[0] = binary return subprocess.check_call(copied_args, *pos_args, **kwargs) def parse_size(size): """Parse a size specification, i.e. an int with a K, M, G suffix. >>> parse_size("1000") 1000 >>> parse_size("100K") 102400 >>> parse_size("1M") 1048576 >>> parse_size("5 g") 5368709120 >>> parse_size("") Traceback (most recent call last): ... ValueError >>> parse_size("test M") Traceback (most recent call last): ... ValueError: test M """ SUFFIXES = { "K": 1024, "M": 1024 * 1024, "G": 1024 * 1024 * 1024, } if not size: raise ValueError(size) s = size.strip() suffix = s[-1] try: mult = SUFFIXES[suffix.upper()] s = s[:-1] except KeyError: mult = 1 try: return int(s.strip()) * mult except ValueError: raise ValueError(size) def generate_zero_file(path, size): """Generate a file of a certain size filled with '\0'. Equivalent to `dd if=/dev/zero of=path count=size`. """ CHUNK_SIZE = 10 * 1024 data = b"\0" * CHUNK_SIZE with open(path, "wb") as f: for i in range(size // CHUNK_SIZE): f.write(data) f.write(b"\0" * (size % CHUNK_SIZE)) def create_fs(path, fs, extra_opts=["-F"]): """Run mkfs.""" args = ["mkfs", "-t", fs] args.extend(extra_opts) args.append(path) call(args) def umount(path, ntries=10, interval=1): """Run `umount` on the given path, retrying as necessary.""" for i in range(ntries): try: call(["umount", path]) return except Exception: print("-- umount failed, retrying in %s second(s)..." % interval) time.sleep(interval) raise OSError("failed umount %s times" % ntries, path) @contextmanager def mount_image(path): """Context manager to loop-mount a file to a temporary mount point. The absolute path of the mount point will be available for the `with` statement's `as` part. """ mounted = False tmp_dir = tempfile.mkdtemp() try: call(["mount", "-o", "loop", path, tmp_dir]) mounted = True yield tmp_dir finally: if mounted: umount(tmp_dir) os.rmdir(tmp_dir) def chroot_path(mount, path): """Join the base path of a chroot and an absolute path in the chroot. >>> chroot_path("/var/chroot", "/etc/debian.sh") '/var/chroot/etc/debian.sh' """ return os.path.join(mount, os.path.relpath(path, "/")) def load(path, encoding="utf-8"): """Load a string from a file or an internal package resource. If `path` starts with "builtin:", that prefix is stripped and the package resource with that name is loaded; if path is `-`, stdin is used; otherwise, it is interpreted as a file name. The contents of the file are returned as a string, decoded with the given encoding (if applicable). """ if path.startswith("builtin:"): res_path = path[8:] try: res_bin = pkgutil.get_data("android_debian_builder", res_path) except Exception: res_bin = None if res_bin is None: raise FileNotFoundError(path) return res_bin.decode(encoding) elif path == "-": return sys.stdin.read() else: with open(path, "r", encoding=encoding) as f: return f.read() PK.eH9#android_debian_builder/run_tests.py# -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import doctest from . import build from . import config from . import script from . import util def test(): doctest.testmod(build) doctest.testmod(config) doctest.testmod(script) doctest.testmod(util) if __name__ == "__main__": test() PK}eH>:  android_debian_builder/build.py# -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import os import tempfile from jinja2 import Template from .util import call, chroot_path def run_multistrap(path, config): """Run multistrap with `config`.""" with tempfile.NamedTemporaryFile(mode="w") as tmp: tmp.write(Template(config.multistrap_config).render(config=config)) tmp.flush() call(["multistrap", "-d", path, "-f", tmp.name]) def import_extra_keys(path, extra_keys): """Import more GPG keys for apt.""" gpg_dir = os.path.join(path, "etc", "apt", "trusted.gpg.d") os.makedirs(gpg_dir, exist_ok=True) with tempfile.TemporaryDirectory() as tmp_name: for key in extra_keys: call(["gpg", "--homedir", tmp_name, "--keyserver", "hkp://keyserver.ubuntu.com", "--recv-keys", key]) call(["gpg", "--homedir", tmp_name, "--keyserver", "hkp://keyserver.ubuntu.com", "--output", os.path.join(gpg_dir, "%s.gpg" % key), "--export", key]) def gen_script(path, template, config, mode=0o755): """Generate a script from a template.""" with open(path, "w") as f: f.write(Template(template).render(config=config)) os.chmod(path, mode) def store_config(mountpoint, config): """Dump the build configuration into the image.""" with open(chroot_path(mountpoint, config.embedded_config), "w") as f: config.dump(f) PK.eH"android_debian_builder/__init__.pyPKseHY android_debian_builder/script.py#!/usr/bin/python3 # -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import argparse from itertools import chain import sys from .build import gen_script, import_extra_keys, run_multistrap, store_config from .config import Config from .util import ( chroot_path, parse_size, generate_zero_file, create_fs, load, mount_image) DEFAULT_IMG_PATH = "debian.img" DEFAULT_SCRIPT_PATH = "deb" DEFAULT_CONFIG = "builtin:data/default-config" def build_image(image_path, config): """Build system image.""" print("++ creating %s file system in %s (%s)..." % (config.image_fs, image_path, config.image_size)) generate_zero_file(image_path, parse_size(config.image_size)) create_fs(image_path, config.image_fs) print("++ mounting image...") with mount_image(image_path) as mountpoint: print("++ running multistrap...") run_multistrap(mountpoint, config) print("++ adding extra GPG keys...") import_extra_keys(mountpoint, config.extra_gpg_keys) print("++ creating basic init script...") gen_script(chroot_path(mountpoint, config.init_script), load(config.init_script_template), config) print("++ creating extra files...") for scriptname, template in config.extra_scripts.items(): gen_script(chroot_path(mountpoint, scriptname), load(template), config) print("++ embedding effective configuration...") store_config(mountpoint, config) def build_script(script_path, config): """Build launcher script.""" print("++ creating launcher script...") gen_script(script_path, load(config.launcher_script_template), config) def parse_args(argv): """Parse arguments.""" parser = argparse.ArgumentParser(description="Generate Debian image.") parser.add_argument("--config", metavar="CFG", type=str, nargs="*", default=[], help="Specify a custom config file. May be used " "multiple times.") parser.add_argument("--image", metavar="IMAGE", type=str, default=DEFAULT_IMG_PATH, help="Use a different image path.") parser.add_argument("--script", metavar="SCRIPT", type=str, default=DEFAULT_SCRIPT_PATH, help="Use a different launcher script path.") parser.add_argument("--only-script", action="store_true", default=False, help="Only generate the launcher script.") parser.add_argument("--print-config", action="store_true", default=False, help="Print the configuration in effect and exit.") parser.add_argument("--no-default-config", action="store_true", default=False, help="Don't include the default configuration.") return parser.parse_args(argv) def main(): args = parse_args(sys.argv[1:]) if args.no_default_config: cfgpaths = args.config else: cfgpaths = chain([DEFAULT_CONFIG], args.config) cfg = Config(cfgpaths) if args.print_config: cfg.dump(sys.stdout) else: if not args.only_script: build_image(args.image, cfg) build_script(args.script, cfg) if __name__ == "__main__": main() PKeH android_debian_builder/config.py# -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from configparser import ConfigParser from .util import load def _split_lines(s): return list(filter(bool, s.strip().splitlines())) class Config: def __init__(self, cfgpaths): self._parser = ConfigParser(interpolation=None) for path in cfgpaths: self._parser.read_string(load(path), path) def dump(self, f): self._parser.write(f, True) @property def image_size(self): return self._parser["image"]["size"] @property def image_fs(self): return self._parser["image"]["fs_type"] @property def multistrap_config(self): return self._parser["bootstrap"]["multistrap-config"] @property def extra_gpg_keys(self): return self._parser["bootstrap"]["extra-gpg-keys"].split() @property def embedded_config(self): return self._parser["bootstrap"]["embedded-config"] @property def init_script(self): return self._parser["bootstrap"]["init-script"] @property def init_script_template(self): return self._parser["bootstrap"]["init-script-template"] @property def extra_scripts(self): return self._parser["extra-scripts"] @property def launcher_script_template(self): return self._parser["launcher"]["template"] @property def device_image_file(self): return self._parser["launcher"]["image-path"] @property def device_mount_point(self): return self._parser["launcher"]["mount-point"] @property def bind_mounts(self): return self._parser.items("bind-mounts") @property def extra_setup_commands(self): return _split_lines(self._parser["bootstrap"]["extra-setup-commands"]) @property def extra_teardown_commands(self): return _split_lines( self._parser["bootstrap"]["extra-teardown-commands"]) @property def extra_packages(self): return self._parser["bootstrap"]["extra-packages"] @property def architecture(self): return self._parser["bootstrap"]["architecture"] PK.eHZ1"android_debian_builder/__main__.py#!/usr/bin/python3 # -*- mode: python; tab-width: 4; indent-tabs-mode: nil -*- # Copyright (c) 2014 Felix Krull # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from .script import main if __name__ == "__main__": main() PK.eH=–"android_debian_builder/data/deb.sh#!/system/bin/sh # -*- mode: sh; tab-width: 4; indent-tabs-mode: nil -*- set -e if [ -z "$IMAGE" ]; then IMAGE="{{ config.device_image_file }}" fi if [ -z "$MOUNTPOINT" ]; then MOUNTPOINT="{{ config.device_mount_point }}" fi is_mounted() { mount | grep -q "$MOUNTPOINT" return $? } init_script_exists() { test -f "$MOUNTPOINT/{{ config.init_script }}" return $? } do_chroot() { chroot "$MOUNTPOINT" $* } mount_debian() { mkdir -p "$MOUNTPOINT" busybox mount -o loop "$IMAGE" "$MOUNTPOINT" {% for (mount, target) in config.bind_mounts %} mkdir -p "$MOUNTPOINT/{{ mount }}" busybox mount -o bind "{{ target }}" "$MOUNTPOINT/{{ mount }}" {% endfor %} } umount_debian() { {% for (mount, _) in config.bind_mounts|reverse %} umount "$MOUNTPOINT/{{ mount }}" {% endfor %} umount "$MOUNTPOINT" } start_debian() { if is_mounted; then true; else mount_debian if init_script_exists; then do_chroot "{{ config.init_script }}" start fi fi echo nameserver $(getprop net.dns1) > "$MOUNTPOINT/etc/resolv.conf" } stop_debian() { if init_script_exists; then do_chroot "{{ config.init_script }}" stop fi if is_mounted; then umount_debian fi } do_login() { if init_script_exists; then do_chroot "{{ config.init_script }}" login || do_chroot /bin/bash else do_chroot /bin/bash fi } status() { if is_mounted; then echo "+ Debian mounted." else echo "- Debian NOT mounted." fi } deploy() { mount -o remount,rw /system cp $0 /system/xbin/deb busybox chmod +x /system/xbin/deb mount -o remount,ro /system } case "$1" in ""|login) start_debian do_login ;; mount|m|start) start_debian ;; unmount|umount|u|stop) stop_debian ;; status) status ;; deploy) deploy ;; *) echo "Usage: deb [ login ]" echo " deb m | mount | start" echo " deb u | umount| unmount | stop" echo " deb status" echo " deb deploy" ;; esac PKݥeHYH*android_debian_builder/data/default-config# -*- mode: ini; tab-width: 4; indent-tabs-mode: nil -*- [image] size = 1G fs_type = ext4 [bootstrap] multistrap-config = [Debian] packages=apt {{ config.extra_packages }} source=http://ftp.debian.org/debian keyring=debian-archive-keyring suite=stable [Debian-Security] packages= source=http://security.debian.org keyring=debian-archive-keyring suite=stable/updates [General] arch={{ config.architecture or "armhf" }} cleanup=true bootstrap=Debian aptsources=Debian Debian-Security extra-packages = architecture = init-script = /etc/init.sh init-script-template = builtin:data/init.sh extra-setup-commands = extra-teardown-commands = embedded-config = /etc/android-debian-builder.config extra-gpg-keys = [extra-scripts] /first-time-setup.sh = builtin:data/first-time-setup.sh [launcher] image-path = /sdcard/debian.img mount-point = /data/local/debian template = builtin:data/deb.sh [bind-mounts] /proc = /proc /sys = /sys /dev = /dev /dev/pts = /dev/pts PK.eH#android_debian_builder/data/init.sh#!/bin/sh # -*- mode: sh; tab-width: 4; indent-tabs-mode: nil -*- set -e PATH=/bin:/usr/bin:/sbin:/usr/sbin do_start() { # Add your own setup commands here. For example: # /etc/init.d/ssh start echo "Starting Debian." {% for cmd in config.extra_setup_commands %} {{ cmd }} {% endfor %} } do_login() { # Take necessary steps to launch the desired shell environment. bash --login } do_stop() { # Add your own teardown commands here. For example: # /etc/init.d/ssh stop echo "Stopping Debian." {% for cmd in config.extra_teardown_commands %} {{ cmd }} {% endfor %} } case "$1" in start) do_start;; login) do_login;; stop) do_stop;; *) echo "Usage: init.rc start | stop";; esac PK.eHTV V /android_debian_builder/data/first-time-setup.sh#!/bin/sh # -*- mode: sh; tab-width: 4; indent-tabs-mode: nil -*- set -e export PATH=/bin:/usr/bin:/sbin:/usr/sbin export LC_ALL=C LANGUAGE=C LANG=C echo "Performing first-time setup..." echo "Running dash.preinst..." /var/lib/dpkg/info/dash.preinst install echo "Configuring all packages..." dpkg --configure -a echo "Adding Android users and groups..." # Note: most of this, the code for the config changes in particular, was taken # from the `andromize` package in the Debian Kit project: # http://sven-ola.dyndns.org/repo/debian-kit-en.html usergroupadd() { grep -q ^$2: /etc/group || groupadd -r -g $1 $2 grep -q ^$2: /etc/passwd || useradd -r -g $1 -u $1 -d / $2 } # See system/core/include/private/android_filesystem_config.h usergroupadd 1000 aid_system usergroupadd 1001 aid_radio usergroupadd 1002 aid_bluetooth usergroupadd 1003 aid_graphics usergroupadd 1004 aid_input usergroupadd 1005 aid_audio usergroupadd 1006 aid_camera usergroupadd 1007 aid_log usergroupadd 1008 aid_compass usergroupadd 1009 aid_mount usergroupadd 1010 aid_wifi usergroupadd 1011 aid_adb usergroupadd 1012 aid_install usergroupadd 1013 aid_media usergroupadd 1014 aid_dhcp usergroupadd 1015 aid_sdcard_rw usergroupadd 1016 aid_vpn usergroupadd 1017 aid_keystore usergroupadd 1018 aid_usb usergroupadd 1019 aid_drm usergroupadd 1020 aid_mdnsr usergroupadd 1021 aid_gps # usergroupadd 1022 aid_unused1 usergroupadd 1023 aid_media_rw usergroupadd 1024 aid_mtp # usergroupadd 1025 aid_unused2 usergroupadd 1026 aid_drmrpc usergroupadd 1027 aid_nfc usergroupadd 1028 aid_sdcard_r usergroupadd 1029 aid_clat usergroupadd 1030 aid_loop_radio usergroupadd 1031 aid_media_drm usergroupadd 1032 aid_package_info usergroupadd 1033 aid_sdcard_pics usergroupadd 1034 aid_sdcard_av usergroupadd 1035 aid_sdcard_all usergroupadd 1036 aid_logd usergroupadd 1037 aid_shared_relro usergroupadd 2000 aid_shell usergroupadd 2001 aid_cache usergroupadd 2002 aid_diag usergroupadd 3001 aid_net_bt_admin usergroupadd 3002 aid_net_bt usergroupadd 3003 aid_inet usergroupadd 3004 aid_net_raw usergroupadd 3005 aid_net_admin usergroupadd 3006 aid_net_bw_stats usergroupadd 3007 aid_net_bw_acct usergroupadd 3008 aid_net_bt_stack usergroupadd 9997 aid_everybody usergroupadd 9998 aid_misc usergroupadd 9999 aid_nobody sed -i -e ' s/^[[:space:]]*\([GU]ID_MIN[[:space:]]\+\)[[:digit:]]\+/\15000/ s/^[[:space:]]*\([GU]ID_MAX[[:space:]]\+\)[[:digit:]]\+/\18999/ ' /etc/login.defs sed -i -e ' s/^[[:space:]]*\(FIRST_[GU]ID[[:space:]]*=[[:space:]]*\)[[:digit:]]\+/\15000/ s/^[[:space:]]*\(LAST_[GU]ID[[:space:]]*=[[:space:]]*\)[[:digit:]]\+/\18999/ s/^[[:space:]]*#\?[[:space:]]*\(ADD_EXTRA_GROUPS[[:space:]]*=[[:space:]]*\)[[:digit:]]\+/\11/ s/^[[:space:]]*#\?[[:space:]]*\(EXTRA_GROUPS[[:space:]]*=[[:space:]]*\).*/\1"aid_inet aid_sdcard_rw aid_sdcard_r aid_media_rw"/ ' /etc/adduser.conf echo "Done." PKeH(9K0android_debian_builder/examples/jessie-armhf.cfg[image] size = 1G fs_type = ext4 [bootstrap] multistrap-config = [Debian] packages=apt source=http://ftp.debian.org/debian keyring=debian-archive-keyring suite=jessie [Debian-Security] packages= source=http://security.debian.org keyring=debian-archive-keyring suite=jessie/updates [General] arch=armhf cleanup=true bootstrap=Debian aptsources=Debian Debian-Security [bind-mounts] /media/storage = /data/media PKeHKx{VV6android_debian_builder-1.1.0.dist-info/DESCRIPTION.rst============================================================= android-debian-builder -- bootstrap a Debian system in a file ============================================================= This tool uses Multistrap_ to bootstrap a Debian (or Debian-based) system into an image file as well as adding an Android-targeted launcher script to chroot into the system. Installation ============ Requirements on the host system: * Python_ 3.3 or up * Jinja_ 2.7 or up * Multistrap_ * because of Multistrap: a Debian_ (or Debian-based) system Requirements on the target device: * root access * Busybox (this might be pre-installed on your system or you could use one of the various installers on the Play Store) * a kernel that supports loop mounts and whatever file system you wish to use Installation with *pip*:: # pip3 install android-debian-builder Installation from the source tarball:: # python3 setup.py install Usage ===== Simply running ``android-debian-builder`` (as root) will start building a Debian image in the current directory. To see possible command line options, run ``android-debian-builder --help``. Usually, you'll want to customise the configuration; the easiest way is to dump the default configuration with ``android-debian-builder --print-config`` and build your own based on that. Additional example configurations are included. These can be found in ``android_debian_builder/examples`` in the source distribution or in the ``examples` subdirectory of the installed package. To include one of these examples in your configuration setup, prefix the file name with ``builtin:examples/`` on the command line, like so:: # android-debian-builder --config builtin:examples/jessie-armhf.cfg .. _Multistrap: https://wiki.debian.org/Multistrap .. _Python: https://python.org .. _Jinja: http://jinja.pocoo.org/ .. _Debian: https://debian.org PKeHYOO7android_debian_builder-1.1.0.dist-info/entry_points.txt[console_scripts] android-debian-builder = android_debian_builder.script:main PKeH1u4android_debian_builder-1.1.0.dist-info/metadata.json{"classifiers": ["Environment :: Console", "License :: OSI Approved :: MIT License", "Operating System :: Android", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Topic :: System :: Installation/Setup"], "extensions": {"python.commands": {"wrap_console": {"android-debian-builder": "android_debian_builder.script:main"}}, "python.details": {"contacts": [{"email": "f_krull@gmx.de", "name": "Felix Krull", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://bitbucket.org/fk/android-debian-builder"}}, "python.exports": {"console_scripts": {"android-debian-builder": "android_debian_builder.script:main"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "license": "MIT", "metadata_version": "2.0", "name": "android-debian-builder", "platform": "Debian", "run_requires": [{"requires": ["Jinja2 (>=2.7)"]}], "summary": "Bootstrap a Debian system in a file, mostly for deploying to Android.", "version": "1.1.0"}PKeHX4android_debian_builder-1.1.0.dist-info/top_level.txtandroid_debian_builder PKeH}\\,android_debian_builder-1.1.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py3-none-any PKeH~ /android_debian_builder-1.1.0.dist-info/METADATAMetadata-Version: 2.0 Name: android-debian-builder Version: 1.1.0 Summary: Bootstrap a Debian system in a file, mostly for deploying to Android. Home-page: https://bitbucket.org/fk/android-debian-builder Author: Felix Krull Author-email: f_krull@gmx.de License: MIT Platform: Debian Classifier: Environment :: Console Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: Android Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 3 Classifier: Topic :: System :: Installation/Setup Requires-Dist: Jinja2 (>=2.7) ============================================================= android-debian-builder -- bootstrap a Debian system in a file ============================================================= This tool uses Multistrap_ to bootstrap a Debian (or Debian-based) system into an image file as well as adding an Android-targeted launcher script to chroot into the system. Installation ============ Requirements on the host system: * Python_ 3.3 or up * Jinja_ 2.7 or up * Multistrap_ * because of Multistrap: a Debian_ (or Debian-based) system Requirements on the target device: * root access * Busybox (this might be pre-installed on your system or you could use one of the various installers on the Play Store) * a kernel that supports loop mounts and whatever file system you wish to use Installation with *pip*:: # pip3 install android-debian-builder Installation from the source tarball:: # python3 setup.py install Usage ===== Simply running ``android-debian-builder`` (as root) will start building a Debian image in the current directory. To see possible command line options, run ``android-debian-builder --help``. Usually, you'll want to customise the configuration; the easiest way is to dump the default configuration with ``android-debian-builder --print-config`` and build your own based on that. Additional example configurations are included. These can be found in ``android_debian_builder/examples`` in the source distribution or in the ``examples` subdirectory of the installed package. To include one of these examples in your configuration setup, prefix the file name with ``builtin:examples/`` on the command line, like so:: # android-debian-builder --config builtin:examples/jessie-armhf.cfg .. _Multistrap: https://wiki.debian.org/Multistrap .. _Python: https://python.org .. _Jinja: http://jinja.pocoo.org/ .. _Debian: https://debian.org PKeHߵ-android_debian_builder-1.1.0.dist-info/RECORDandroid_debian_builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 android_debian_builder/__main__.py,sha256=iZ8J65Eoj91SUpRr8LNISAxhOB4dfX9mJYrCM-u4EwU,1251 android_debian_builder/build.py,sha256=CQbF9GK7porsIisntJHfnedEJbjWT3E_FqBz1yuqiOM,2585 android_debian_builder/config.py,sha256=2O4Iewhpu_yHbkOS6kYyQLS8XhbgOh0oV4kH_W_Iwtk,3249 android_debian_builder/run_tests.py,sha256=5rwldoC8hMxWy9cmlLmUCVkfuoxRGIIQZLqO5OwU7UM,1428 android_debian_builder/script.py,sha256=V0ENYRFOEaIGHAhhVBkpeZWelLeFvDOux9cy1Xor3tc,4508 android_debian_builder/util.py,sha256=ZdYNQ3V68Bh78-41XthxzsfnYI9O2pEpQS8Xb6XCcls,5303 android_debian_builder/data/deb.sh,sha256=y4hmoTI5znZViS34BmRIixwR4zNI6ehW8fqIdCnrGrc,2198 android_debian_builder/data/default-config,sha256=MJ9e48tc9FZqSLempDssH46teY8RZ02nKtgear1brJs,1028 android_debian_builder/data/first-time-setup.sh,sha256=eT4DoDkwqAkXbnGkbB7AwMlrk2cEaWqtqGq2yjUP5lA,2902 android_debian_builder/data/init.sh,sha256=vLqcm_rXfy12yzminFFb8ZSL-Z2xjpbZod6AJKOKFJA,750 android_debian_builder/examples/jessie-armhf.cfg,sha256=O0oYqUs0Nkz3ky64pD1BfKy8x1-YkL7Wg_MdI8H3ih0,429 android_debian_builder-1.1.0.data/scripts/android-debian-builder,sha256=pVq6uxuNt8Nye_o4U455BYNbqLDUia2QfkrGV39c57U,155 android_debian_builder-1.1.0.dist-info/DESCRIPTION.rst,sha256=RaMnJx4jMGez2K1349YBe8dloII9eiM0K7LIf7Y6MRQ,1878 android_debian_builder-1.1.0.dist-info/METADATA,sha256=x9Lz5V9n8u6JJW6hk9n972D5m9A9jZZBK4BVBeAROcg,2463 android_debian_builder-1.1.0.dist-info/RECORD,, android_debian_builder-1.1.0.dist-info/WHEEL,sha256=zX7PHtH_7K-lEzyK75et0UBa3Bj8egCBMXe1M4gc6SU,92 android_debian_builder-1.1.0.dist-info/entry_points.txt,sha256=Lsm-5NHuiKn5BvztErn4gPG3XSlH2ToIJlpdOf6_Jrk,79 android_debian_builder-1.1.0.dist-info/metadata.json,sha256=8wKPY-ebksHrNM7TOmE3W2Guwn6BE1Ytf4wNIEq6cvM,1001 android_debian_builder-1.1.0.dist-info/top_level.txt,sha256=YGGxAAtRFd1e6BF2B5qeG9_WTFemnC_0VzShXmwB1_s,23 PKeH?t@android_debian_builder-1.1.0.data/scripts/android-debian-builderPK.eHL..oandroid_debian_builder/util.pyPK.eH9#android_debian_builder/run_tests.pyPK}eH>:  android_debian_builder/build.pyPK.eH"&android_debian_builder/__init__.pyPKseHY W&android_debian_builder/script.pyPKeH 18android_debian_builder/config.pyPK.eHZ1" Eandroid_debian_builder/__main__.pyPK.eH=–"CJandroid_debian_builder/data/deb.shPKݥeHYH*Sandroid_debian_builder/data/default-configPK.eH#eWandroid_debian_builder/data/init.shPK.eHTV V /Zandroid_debian_builder/data/first-time-setup.shPKeH(9K07fandroid_debian_builder/examples/jessie-armhf.cfgPKeHKx{VV62handroid_debian_builder-1.1.0.dist-info/DESCRIPTION.rstPKeHYOO7oandroid_debian_builder-1.1.0.dist-info/entry_points.txtPKeH1u4pandroid_debian_builder-1.1.0.dist-info/metadata.jsonPKeHX4tandroid_debian_builder-1.1.0.dist-info/top_level.txtPKeH}\\,$uandroid_debian_builder-1.1.0.dist-info/WHEELPKeH~ /uandroid_debian_builder-1.1.0.dist-info/METADATAPKeHߵ-android_debian_builder-1.1.0.dist-info/RECORDPK