diff --git a/aports/device/device-nokia-rx51/APKBUILD b/aports/device/device-nokia-rx51/APKBUILD
index 6b4b44d9..84faf287 100644
--- a/aports/device/device-nokia-rx51/APKBUILD
+++ b/aports/device/device-nokia-rx51/APKBUILD
@@ -1,6 +1,6 @@
pkgname=device-nokia-rx51
pkgver=1
-pkgrel=25
+pkgrel=26
pkgdesc="Nokia N900"
url="https://github.com/postmarketOS"
arch="noarch"
@@ -69,7 +69,7 @@ weston() {
"$subpkgdir"/etc/xdg/weston/weston.ini
}
-sha512sums="6309f2e0c6c08f8907fc2a0b94c4a0842fc6d927bd92acb35a068605acffecbaa7d4af31e9329e6686b592840ba7761c58856f7b8378c795771fbd84ddbfcf33 deviceinfo
+sha512sums="8e010bebddf1bb09cde3966e402d2c146476eb21761c3110d2ac01010eced42519dab7b81915899894914c7e3820eaf6c48767a21c955412ad53da0bade0c38c deviceinfo
1b89309dd4fe7ee0ba37c6224a0152d6864bb1c7bc4e96918a57e01bebc4173559855ae9673887223de4a8baa3191c8ad88ec8594776a4110cdb19a7be790db4 uboot-script.cmd
3d55e34b95791636e44a5f41754f3d0de039dbba41f7a556d43a95c9e64afcfa930046b4b96b40020b6f196096ffba93514682927e32fa4488686fdd19c6da5a backlight-enable.sh
d303734dd49fe75a299ca723f4da52bc0cda2775683c54aa736aabf397db4ae8deb6d912d4116800cf2ba17f3a2987ab3e839652879b8ab023b4a91a55849f08 90-touchscreen-dev.rules
diff --git a/aports/device/device-nokia-rx51/deviceinfo b/aports/device/device-nokia-rx51/deviceinfo
index ef0f00bc..574f9b2a 100644
--- a/aports/device/device-nokia-rx51/deviceinfo
+++ b/aports/device/device-nokia-rx51/deviceinfo
@@ -12,7 +12,7 @@ deviceinfo_dtb="omap3-n900"
deviceinfo_modules_initfs="tsc2005 tsc200x-core omap_wdt twl4030_wdt omap-sham"
deviceinfo_external_disk="true"
deviceinfo_external_disk_install="true"
-deviceinfo_flash_methods="0xFFFF"
+deviceinfo_flash_methods="0xffff"
deviceinfo_generate_legacy_uboot_initfs="true"
deviceinfo_arch="armhf"
deviceinfo_dev_touchscreen="/dev/input/event3"
diff --git a/aports/main/postmarketos-update-kernel/APKBUILD b/aports/main/postmarketos-update-kernel/APKBUILD
index 332240da..85cd0b57 100644
--- a/aports/main/postmarketos-update-kernel/APKBUILD
+++ b/aports/main/postmarketos-update-kernel/APKBUILD
@@ -1,5 +1,5 @@
pkgname=postmarketos-update-kernel
-pkgver=0.0.1
+pkgver=0.0.2
pkgrel=0
pkgdesc="kernel updater script for postmarketOS"
url="https://github.com/postmarketOS"
@@ -12,4 +12,4 @@ package() {
install -Dm755 "$srcdir/update-kernel.sh" \
"$pkgdir/sbin/pmos-update-kernel"
}
-sha512sums="7d2f3031b1a468accff5a3584bd51d3607141b01e1d2a93d611852476bdeecc3edd7b80f8e3b034012d9b5f09de907af1de02f48586d82d06ee4b5746d4fd286 update-kernel.sh"
+sha512sums="17fa14327622fcdefa335fccfeac33623a8cf3cb93e6ad833631990f3c88757e81d6eb3b02f0a69177c518b8f45f249e8b9709fe3eb5126a7322da5f7700becb update-kernel.sh"
diff --git a/aports/main/postmarketos-update-kernel/update-kernel.sh b/aports/main/postmarketos-update-kernel/update-kernel.sh
index e45693c9..8ce79bc4 100755
--- a/aports/main/postmarketos-update-kernel/update-kernel.sh
+++ b/aports/main/postmarketos-update-kernel/update-kernel.sh
@@ -28,7 +28,7 @@ case $METHOD in
echo "Flashing initramfs..."
gunzip -c /boot/initramfs-"$FLAVOR" | lzop | dd of="$INITFS_PARTITION" bs=1M
;;
- 0xFFFF)
+ 0xffff)
echo -n "No need to use this utility, since uboot loads the kernel directly from"
echo " the boot partition. Your kernel should be updated already."
exit 1
diff --git a/pmb/__init__.py b/pmb/__init__.py
index 5f47b1a8..3d4b32db 100644
--- a/pmb/__init__.py
+++ b/pmb/__init__.py
@@ -25,6 +25,7 @@ import traceback
from . import config
from . import parse
+from .config import init as config_init
from .helpers import frontend
from .helpers import logging as pmb_logging
from .helpers import other
@@ -42,7 +43,7 @@ def main():
# Initialize or require config
if args.action == "init":
- return config.init(args)
+ return config_init.frontend(args)
elif not os.path.exists(args.config):
logging.critical("Please specify a config file, or run"
" 'pmbootstrap init' to generate one.")
diff --git a/pmb/aportgen/__init__.py b/pmb/aportgen/__init__.py
index 452e6a3b..154084c4 100644
--- a/pmb/aportgen/__init__.py
+++ b/pmb/aportgen/__init__.py
@@ -19,33 +19,47 @@ along with pmbootstrap. If not, see .
import os
import logging
import pmb.aportgen.binutils
-import pmb.aportgen.musl
-import pmb.aportgen.gcc
import pmb.aportgen.busybox_static
-import pmb.helpers.git
+import pmb.aportgen.device
+import pmb.aportgen.gcc
+import pmb.aportgen.linux
+import pmb.aportgen.musl
+import pmb.config
+import pmb.helpers.cli
+
+
+def properties(pkgname):
+ """
+ Get the `pmb.config.aportgen` properties for the aport generator, based on
+ the pkgname prefix.
+
+ Example: "musl-armhf" => ("musl", "cross", {"confirm_overwrite": False})
+
+ :param pkgname: package name
+ :returns: (prefix, folder, options)
+ """
+ for folder, options in pmb.config.aportgen.items():
+ for prefix in options["prefixes"]:
+ if pkgname.startswith(prefix):
+ return (prefix, folder, options)
+ raise ValueError("No generator available for " + pkgname + "!")
def generate(args, pkgname):
- # Prepare git repo and temp folder
- pmb.helpers.git.clone(args, "aports_upstream")
- logging.info("(native) generate " + pkgname + " aport")
+ # Confirm overwrite
+ prefix, folder, options = properties(pkgname)
+ path_target = args.aports + "/" + folder + "/" + pkgname
+ if options["confirm_overwrite"] and os.path.exists(path_target):
+ logging.warning("WARNING: Target folder already exists: " + path_target)
+ if not pmb.helpers.cli.confirm(args, "Continue and overwrite?"):
+ raise RuntimeError("Aborted.")
+
+ # Run pmb.aportgen.PREFIX.generate()
if os.path.exists(args.work + "/aportgen"):
pmb.helpers.run.user(args, ["rm", "-r", args.work + "/aportgen"])
-
- # Choose generator based on the name
- if pkgname.startswith("binutils-"):
- pmb.aportgen.binutils.generate(args, pkgname)
- elif pkgname.startswith("musl-"):
- pmb.aportgen.musl.generate(args, pkgname)
- elif pkgname.startswith("gcc-"):
- pmb.aportgen.gcc.generate(args, pkgname)
- elif pkgname.startswith("busybox-static-"):
- pmb.aportgen.busybox_static.generate(args, pkgname)
- else:
- raise ValueError("No generator available for " + pkgname + "!")
+ getattr(pmb.aportgen, prefix.replace("-", "_")).generate(args, pkgname)
# Move to the aports folder
- path_target = args.aports + "/cross/" + pkgname
if os.path.exists(path_target):
pmb.helpers.run.user(args, ["rm", "-r", path_target])
pmb.helpers.run.user(
diff --git a/pmb/aportgen/binutils.py b/pmb/aportgen/binutils.py
index 64ca12ca..90fc8561 100644
--- a/pmb/aportgen/binutils.py
+++ b/pmb/aportgen/binutils.py
@@ -16,8 +16,9 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pmbootstrap. If not, see .
"""
-import pmb.helpers.run
import pmb.aportgen.core
+import pmb.helpers.git
+import pmb.helpers.run
def generate(args, pkgname):
@@ -25,6 +26,7 @@ def generate(args, pkgname):
arch = pkgname.split("-")[1]
path_original = "main/binutils"
upstream = (args.work + "/cache_git/aports_upstream/" + path_original)
+ pmb.helpers.git.clone(args, "aports_upstream")
pmb.helpers.run.user(args, ["cp", "-r", upstream, args.work + "/aportgen"])
# Rewrite APKBUILD
diff --git a/pmb/aportgen/device.py b/pmb/aportgen/device.py
new file mode 100644
index 00000000..80d060e3
--- /dev/null
+++ b/pmb/aportgen/device.py
@@ -0,0 +1,196 @@
+"""
+Copyright 2017 Oliver Smith
+
+This file is part of pmbootstrap.
+
+pmbootstrap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+pmbootstrap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with pmbootstrap. If not, see .
+"""
+import logging
+import pmb.helpers.run
+import pmb.aportgen.core
+import pmb.parse.apkindex
+
+
+def ask_for_architecture(args):
+ architectures = pmb.config.build_device_architectures
+ while True:
+ ret = pmb.helpers.cli.ask(args, "Device architecture", architectures,
+ architectures[0])
+ if ret in architectures:
+ return ret
+ logging.fatal("ERROR: Invalid architecture specified. If you want to"
+ " add a new architecture, edit build_device_architectures"
+ " in pmb/config/__init__.py.")
+
+
+def ask_for_manufacturer(args):
+ logging.info("Who produced the device (e.g. LG)?")
+ return pmb.helpers.cli.ask(args, "Manufacturer", None, None, False)
+
+
+def ask_for_name(args):
+ logging.info("What is the official name (e.g. Google Nexus 5)?")
+ return pmb.helpers.cli.ask(args, "Name", None, None, False)
+
+
+def ask_for_keyboard(args):
+ return pmb.helpers.cli.confirm(args, "Does the device have a hardware keyboard?")
+
+
+def ask_for_external_storage(args):
+ return pmb.helpers.cli.confirm(args, "Does the device have a sdcard or other"
+ " external storage medium?")
+
+
+def ask_for_flash_method(args):
+ flash_methods = ["fastboot", "heimdall", "0xffff"]
+ while True:
+ logging.info("Which flash method does the device support?")
+ method = pmb.helpers.cli.ask(args, "Flash method", flash_methods,
+ flash_methods[0])
+
+ if method in flash_methods:
+ if method == "heimdall":
+ heimdall_types = ["isorec", "bootimg"]
+ while True:
+ logging.info("Does the device use the \"isolated recovery\" or boot.img?")
+ logging.info("")
+ heimdall_type = pmb.helpers.cli.ask(args, "Type", heimdall_types,
+ heimdall_types[0])
+ if heimdall_type in heimdall_types:
+ method += "-" + heimdall_type
+ break
+ logging.fatal("ERROR: Invalid type specified.")
+ return method
+
+ logging.fatal("ERROR: Invalid flash method specified. If you want to"
+ " add a new flash method, edit flash_methods in"
+ " pmb/config/__init__.py.")
+
+
+def generate_deviceinfo(args, pkgname, name, manufacturer, arch, has_keyboard,
+ has_external_storage, flash_method):
+ content = """\
+ # Reference:
+ # Please use double quotes only. You can source this file in shell scripts.
+
+ deviceinfo_format_version="0"
+ deviceinfo_name=\"""" + name + """\"
+ deviceinfo_manufacturer=\"""" + manufacturer + """\"
+ deviceinfo_date=""
+ deviceinfo_dtb=""
+ deviceinfo_modules_initfs=""
+ deviceinfo_external_disk_install="false"
+ deviceinfo_arch=\"""" + arch + """\"
+
+ # Device related
+ deviceinfo_keyboard=\"""" + ("true" if has_keyboard else "false") + """\"
+ deviceinfo_external_disk=\"""" + ("true" if has_external_storage else "false") + """\"
+ deviceinfo_screen_width="800"
+ deviceinfo_screen_height="600"
+ deviceinfo_dev_touchscreen=""
+ deviceinfo_dev_keyboard=""
+
+ # Bootloader related
+ deviceinfo_flash_methods=\"""" + flash_method + """\"
+ """
+
+ content_fastboot = """\
+ deviceinfo_kernel_cmdline=""
+ deviceinfo_generate_bootimg="true"
+ deviceinfo_bootimg_qcdt="false"
+ deviceinfo_flash_offset_base=""
+ deviceinfo_flash_offset_kernel=""
+ deviceinfo_flash_offset_ramdisk=""
+ deviceinfo_flash_offset_second=""
+ deviceinfo_flash_offset_tags=""
+ deviceinfo_flash_pagesize="2048"
+ """
+
+ content_heimdall_bootimg = """\
+ deviceinfo_flash_heimdall_partition_kernel=""
+ deviceinfo_flash_heimdall_partition_system=""
+ """
+
+ content_heimdall_isorec = """\
+ deviceinfo_flash_heimdall_partition_kernel=""
+ deviceinfo_flash_heimdall_partition_initfs=""
+ deviceinfo_flash_heimdall_partition_system=""
+ """
+
+ content_0xffff = """\
+ deviceinfo_generate_legacy_uboot_initfs="true"
+ """
+
+ if flash_method == "fastboot":
+ content += content_fastboot
+ elif flash_method == "heimdall-bootimg":
+ content += content_fastboot
+ content += content_heimdall_bootimg
+ elif flash_method == "heimdall-isorec":
+ content += content_heimdall_isorec
+ elif flash_method == "0xffff":
+ content += content_0xffff
+
+ # Write to file
+ pmb.helpers.run.user(args, ["mkdir", "-p", args.work + "/aportgen"])
+ with open(args.work + "/aportgen/deviceinfo", "w", encoding="utf-8") as handle:
+ for line in content.split("\n"):
+ handle.write(line.lstrip() + "\n")
+
+
+def generate_apkbuild(args, pkgname, name, arch, flash_method):
+ depends = "linux-" + "-".join(pkgname.split("-")[1:])
+ if flash_method in ["fastboot", "heimdall-bootimg"]:
+ depends += " mkbootimg"
+ if flash_method == "0xffff":
+ depends += " uboot-tools"
+ content = """\
+ pkgname=\"""" + pkgname + """\"
+ pkgdesc=\"""" + name + """\"
+ pkgver=0.1
+ pkgrel=0
+ url="https://postmarketos.org"
+ license="MIT"
+ arch="noarch"
+ options="!check"
+ depends=\"""" + depends + """\"
+ source="deviceinfo"
+
+ package() {
+ install -Dm644 "$srcdir"/deviceinfo \\
+ "$pkgdir"/etc/deviceinfo
+ }
+
+ sha512sums="(run 'pmbootstrap checksum """ + pkgname + """' to fill)"
+ """
+
+ # Write the file
+ pmb.helpers.run.user(args, ["mkdir", "-p", args.work + "/aportgen"])
+ with open(args.work + "/aportgen/APKBUILD", "w", encoding="utf-8") as handle:
+ for line in content.split("\n"):
+ handle.write(line[8:].replace(" " * 4, "\t") + "\n")
+
+
+def generate(args, pkgname):
+ arch = ask_for_architecture(args)
+ manufacturer = ask_for_manufacturer(args)
+ name = ask_for_name(args)
+ has_keyboard = ask_for_keyboard(args)
+ has_external_storage = ask_for_external_storage(args)
+ flash_method = ask_for_flash_method(args)
+
+ generate_deviceinfo(args, pkgname, name, manufacturer, arch, has_keyboard,
+ has_external_storage, flash_method)
+ generate_apkbuild(args, pkgname, name, arch, flash_method)
diff --git a/pmb/aportgen/gcc.py b/pmb/aportgen/gcc.py
index 18abc88e..a1b0bb8b 100644
--- a/pmb/aportgen/gcc.py
+++ b/pmb/aportgen/gcc.py
@@ -16,8 +16,9 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pmbootstrap. If not, see .
"""
-import pmb.helpers.run
import pmb.aportgen.core
+import pmb.helpers.git
+import pmb.helpers.run
def generate(args, pkgname):
@@ -25,6 +26,7 @@ def generate(args, pkgname):
arch = pkgname.split("-")[1]
path_original = "main/gcc"
upstream = (args.work + "/cache_git/aports_upstream/" + path_original)
+ pmb.helpers.git.clone(args, "aports_upstream")
pmb.helpers.run.user(args, ["cp", "-r", upstream, args.work + "/aportgen"])
# Rewrite APKBUILD
diff --git a/pmb/aportgen/linux.py b/pmb/aportgen/linux.py
new file mode 100644
index 00000000..c20e66a6
--- /dev/null
+++ b/pmb/aportgen/linux.py
@@ -0,0 +1,129 @@
+"""
+Copyright 2017 Oliver Smith
+
+This file is part of pmbootstrap.
+
+pmbootstrap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+pmbootstrap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with pmbootstrap. If not, see .
+"""
+import pmb.helpers.run
+import pmb.aportgen.core
+import pmb.parse.apkindex
+import pmb.parse.arch
+
+
+def generate_apkbuild(args, pkgname, name, arch):
+ device = "-".join(pkgname.split("-")[1:])
+ carch = pmb.parse.arch.alpine_to_kernel(arch)
+ content = """\
+ # Kernel config based on: arch/""" + carch + """/configs/(CHANGEME!)
+
+ pkgname=\"""" + pkgname + """\"
+ pkgver=3.x.x
+ pkgrel=0
+ pkgdesc=\"""" + name + """ kernel fork\"
+ arch=\"""" + arch + """\"
+ _carch=\"""" + carch + """\"
+ _flavor=\"""" + device + """\"
+ url="https://kernel.org"
+ license="GPL2"
+ options="!strip !check !tracedeps"
+ makedepends="perl sed installkernel bash gmp-dev bc linux-headers elfutils-dev"
+ HOSTCC="${CC:-gcc}"
+ HOSTCC="${HOSTCC#${CROSS_COMPILE}}"
+
+ # Source
+ _repository="(CHANGEME!)"
+ _commit="ffffffffffffffffffffffffffffffffffffffff"
+ _config="config-${_flavor}.${arch}"
+ source="
+ $pkgname-$_commit.tar.gz::https://github.com/LineageOS/${_repository}/archive/${_commit}.tar.gz
+ $_config
+ compiler-gcc6.h
+ 01_msm-fix-perf_trace_counters.patch
+ 02_gpu-msm-fix-gcc5-compile.patch
+ "
+ builddir="$srcdir/${_repository}-${_commit}"
+
+ prepare() {
+ default_prepare
+
+ # gcc6 support
+ cp -v "$srcdir/compiler-gcc6.h" "$builddir/include/linux/"
+
+ # Remove -Werror from all makefiles
+ find . -type f -name Makefile -print0 | \\
+ xargs -0 sed -i 's/-Werror-/-W/g'
+ find . -type f -name Makefile -print0 | \\
+ xargs -0 sed -i 's/-Werror//g'
+
+ # Prepare kernel config ('yes ""' for kernels lacking olddefconfig)
+ cp "$srcdir"/$_config "$builddir"/.config
+ yes "" | make ARCH="$_carch" HOSTCC="$HOSTCC" oldconfig
+ }
+
+ menuconfig() {
+ cd "$builddir"
+ make ARCH="$_carch" menuconfig
+ cp .config "$startdir"/$_config
+ }
+
+ build() {
+ unset LDFLAGS
+ make ARCH="$_carch" CC="${CC:-gcc}" \\
+ KBUILD_BUILD_VERSION="$((pkgrel + 1 ))-postmarketOS"
+ }
+
+ package() {
+ # kernel.release
+ install -D "$builddir/include/config/kernel.release" \\
+ "$pkgdir/usr/share/kernel/$_flavor/kernel.release"
+
+ # zImage (find the right one)
+ cd "$builddir/arch/$_carch/boot"
+ _target="$pkgdir/boot/vmlinuz-$_flavor"
+ for _zimg in zImage-dtb Image.gz-dtb *zImage Image; do
+ [ -e "$_zimg" ] || continue
+ msg "zImage found: $_zimg"
+ install -Dm644 "$_zimg" "$_target"
+ break
+ done
+ if ! [ -e "$_target" ]; then
+ error "Could not find zImage in $PWD!"
+ return 1
+ fi
+ }
+
+ sha512sums="(run 'pmbootstrap checksum """ + pkgname + """' to fill)"
+ """
+
+ # Write the file
+ with open(args.work + "/aportgen/APKBUILD", "w", encoding="utf-8") as handle:
+ for line in content.split("\n"):
+ handle.write(line[8:].replace(" " * 4, "\t") + "\n")
+
+
+def generate(args, pkgname):
+ device = "-".join(pkgname.split("-")[1:])
+ deviceinfo = pmb.parse.deviceinfo(args, device)
+
+ # Copy gcc6 support header and the patches from lg-mako for now
+ # (automatically finding the right patches is planned in #688)
+ pmb.helpers.run.user(args, ["mkdir", "-p", args.work + "/aportgen"])
+ for file in ["compiler-gcc6.h", "01_msm-fix-perf_trace_counters.patch",
+ "02_gpu-msm-fix-gcc5-compile.patch"]:
+ pmb.helpers.run.user(args, ["cp", args.aports +
+ "/device/linux-lg-mako/" + file,
+ args.work + "/aportgen/"])
+
+ generate_apkbuild(args, pkgname, deviceinfo["name"], deviceinfo["arch"])
diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py
index 6e79d6d1..fe216b8f 100644
--- a/pmb/config/__init__.py
+++ b/pmb/config/__init__.py
@@ -22,7 +22,6 @@ import os
#
# Exported functions
#
-from pmb.config.init import init
from pmb.config.load import load
from pmb.config.save import save
@@ -344,3 +343,18 @@ git_repos = {
"aports_upstream": "https://github.com/alpinelinux/aports",
"apk-tools": "https://github.com/alpinelinux/apk-tools",
}
+
+
+#
+# APORTGEN
+#
+aportgen = {
+ "cross": {
+ "prefixes": ["binutils", "busybox-static", "gcc", "musl"],
+ "confirm_overwrite": False,
+ },
+ "device": {
+ "prefixes": ["device", "linux"],
+ "confirm_overwrite": True,
+ }
+}
diff --git a/pmb/config/init.py b/pmb/config/init.py
index b0e5e254..ecdb6958 100644
--- a/pmb/config/init.py
+++ b/pmb/config/init.py
@@ -113,19 +113,35 @@ def ask_for_timezone(args):
return "GMT"
-def init(args):
- cfg = pmb.config.load(args)
-
- # Device
+def ask_for_device(args):
devices = sorted(pmb.helpers.devices.list(args))
logging.info("Target device (either an existing one, or a new one for"
" porting).")
logging.info("Available (" + str(len(devices)) + "): " +
", ".join(devices))
- cfg["pmbootstrap"]["device"] = pmb.helpers.cli.ask(args, "Device",
- None, args.device, False, "[a-z0-9]+-[a-z0-9]+")
+ while True:
+ device = pmb.helpers.cli.ask(args, "Device", None, args.device, False,
+ "[a-z0-9]+-[a-z0-9]+")
+ device_exists = os.path.exists(args.aports + "/device/device-" +
+ device + "/deviceinfo")
+ if not device_exists:
+ logging.info("You are about to do a new device port for '" +
+ device + "'.")
+ if not pmb.helpers.cli.confirm(args, default=True):
+ continue
- device_exists = os.path.exists(args.aports + "/device/device-" + cfg["pmbootstrap"]["device"] + "/deviceinfo")
+ pmb.aportgen.generate(args, "device-" + device)
+ pmb.aportgen.generate(args, "linux-" + device)
+ break
+
+ return (device, device_exists)
+
+
+def frontend(args):
+ cfg = pmb.config.load(args)
+
+ # Device
+ cfg["pmbootstrap"]["device"], device_exists = ask_for_device(args)
# Device keymap
if device_exists:
diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py
index 3eac89f2..b090f25c 100644
--- a/pmb/helpers/frontend.py
+++ b/pmb/helpers/frontend.py
@@ -80,6 +80,7 @@ def _parse_suffix(args):
def aportgen(args):
for package in args.packages:
+ logging.info("Generate aport: " + package)
pmb.aportgen.generate(args, package)
diff --git a/test/test_aportgen_device_wizard.py b/test/test_aportgen_device_wizard.py
new file mode 100644
index 00000000..bb50d86a
--- /dev/null
+++ b/test/test_aportgen_device_wizard.py
@@ -0,0 +1,151 @@
+"""
+Copyright 2017 Oliver Smith
+
+This file is part of pmbootstrap.
+
+pmbootstrap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+pmbootstrap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with pmbootstrap. If not, see .
+"""
+import logging
+import os
+import pytest
+import sys
+
+# Import from parent directory
+sys.path.append(os.path.realpath(
+ os.path.join(os.path.dirname(__file__) + "/..")))
+import pmb.aportgen
+import pmb.config
+import pmb.helpers.logging
+import pmb.parse
+
+
+@pytest.fixture
+def args(tmpdir, request):
+ sys.argv = ["pmbootstrap.py", "chroot"]
+ args = pmb.parse.arguments()
+ args.log = args.work + "/log_testsuite.txt"
+ pmb.helpers.logging.init(args)
+ request.addfinalizer(args.logfd.close)
+
+ # Fake aports folder):
+ tmpdir = str(tmpdir)
+ setattr(args, "_aports_real", args.aports)
+ args.aports = tmpdir
+ pmb.helpers.run.user(args, ["mkdir", "-p", tmpdir + "/device"])
+
+ # Copy the linux-lg-mako aport (we currently copy patches from there)
+ path_mako = args._aports_real + "/device/linux-lg-mako"
+ pmb.helpers.run.user(args, ["cp", "-r", path_mako, tmpdir + "/device"])
+ return args
+
+
+def generate(args, monkeypatch, answers):
+ """
+ Generate the device-new-device and linux-new-device aports (with a patched pmb.helpers.cli()).
+
+ :returns: (deviceinfo, apkbuild, apkbuild_linux) - the parsed dictionaries
+ of the created files, as returned by pmb.parse.apkbuild() and
+ pmb.parse.deviceinfo().
+ """
+ # Patched function
+ def fake_ask(args, question="Continue?", choices=["y", "n"], default="n",
+ lowercase_answer=True, validation_regex=None):
+ for substr, answer in answers.items():
+ if substr in question:
+ logging.info(question + ": " + answer)
+ # raise RuntimeError("test>" + answer)
+ return answer
+ raise RuntimeError("This testcase didn't expect the question '" +
+ question + "', please add it to the mapping.")
+
+ # Generate the aports
+ monkeypatch.setattr(pmb.helpers.cli, "ask", fake_ask)
+ pmb.aportgen.generate(args, "device-testsuite-testdevice")
+ pmb.aportgen.generate(args, "linux-testsuite-testdevice")
+ monkeypatch.undo()
+
+ # Parse the deviceinfo and apkbuilds
+ args.cache["apkbuild"] = {}
+ apkbuild_path = (args.aports + "/device/device-testsuite-testdevice/"
+ "APKBUILD")
+ apkbuild_path_linux = (args.aports + "/device/"
+ "linux-testsuite-testdevice/APKBUILD")
+ apkbuild = pmb.parse.apkbuild(args, apkbuild_path)
+ apkbuild_linux = pmb.parse.apkbuild(args, apkbuild_path_linux)
+ deviceinfo = pmb.parse.deviceinfo(args, "testsuite-testdevice")
+ return (deviceinfo, apkbuild, apkbuild_linux)
+
+
+def test_aportgen_device_wizard(args, monkeypatch):
+ """
+ Generate a device-testsuite-testdevice and linux-testsuite-testdevice
+ package multiple times and check if the output is correct. Also build the
+ device package once.
+ """
+ # Answers to interactive questions
+ answers = {
+ "Device architecture": "armhf",
+ "external storage": "y",
+ "hardware keyboard": "n",
+ "Flash method": "heimdall",
+ "Manufacturer": "Testsuite",
+ "Name": "Testsuite Testdevice",
+ "Type": "isorec",
+ }
+
+ # First run
+ deviceinfo, apkbuild, apkbuild_linux = generate(args, monkeypatch, answers)
+ assert apkbuild["pkgname"] == "device-testsuite-testdevice"
+ assert apkbuild["pkgdesc"] == "Testsuite Testdevice"
+ assert apkbuild["depends"] == ["linux-testsuite-testdevice"]
+
+ assert apkbuild_linux["pkgname"] == "linux-testsuite-testdevice"
+ assert apkbuild_linux["pkgdesc"] == "Testsuite Testdevice kernel fork"
+ assert apkbuild_linux["arch"] == ["armhf"]
+ assert apkbuild_linux["_flavor"] == "testsuite-testdevice"
+
+ assert deviceinfo["name"] == "Testsuite Testdevice"
+ assert deviceinfo["manufacturer"] == answers["Manufacturer"]
+ assert deviceinfo["arch"] == "armhf"
+ assert deviceinfo["keyboard"] == "false"
+ assert deviceinfo["external_disk"] == "true"
+ assert deviceinfo["flash_methods"] == "heimdall-isorec"
+ assert deviceinfo["generate_bootimg"] == ""
+ assert deviceinfo["generate_legacy_uboot_initfs"] == ""
+
+ # Build the device package
+ pkgname = "device-testsuite-testdevice"
+ pmb.build.checksum(args, pkgname)
+ pmb.build.package(args, pkgname, "x86_64", force=True)
+
+ # Abort on overwrite confirmation
+ answers["overwrite"] = "n"
+ with pytest.raises(RuntimeError) as e:
+ deviceinfo, apkbuild, apkbuild_linux = generate(args, monkeypatch,
+ answers)
+ assert "Aborted." in str(e.value)
+
+ # fastboot (mkbootimg)
+ answers["overwrite"] = "y"
+ answers["Flash method"] = "fastboot"
+ deviceinfo, apkbuild, apkbuild_linux = generate(args, monkeypatch, answers)
+ assert apkbuild["depends"] == ["linux-testsuite-testdevice", "mkbootimg"]
+ assert deviceinfo["flash_methods"] == answers["Flash method"]
+ assert deviceinfo["generate_bootimg"] == "true"
+
+ # 0xffff (legacy uboot initfs)
+ answers["Flash method"] = "0xffff"
+ deviceinfo, apkbuild, apkbuild_linux = generate(args, monkeypatch, answers)
+ assert apkbuild["depends"] == ["linux-testsuite-testdevice", "uboot-tools"]
+ assert deviceinfo["generate_legacy_uboot_initfs"] == "true"
diff --git a/test/test_questions.py b/test/test_questions.py
new file mode 100644
index 00000000..a7c76485
--- /dev/null
+++ b/test/test_questions.py
@@ -0,0 +1,133 @@
+"""
+Copyright 2017 Oliver Smith
+
+This file is part of pmbootstrap.
+
+pmbootstrap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+pmbootstrap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with pmbootstrap. If not, see .
+"""
+import logging
+import os
+import pytest
+import sys
+
+# Import from parent directory
+sys.path.append(os.path.realpath(
+ os.path.join(os.path.dirname(__file__) + "/..")))
+import pmb.aportgen.device
+import pmb.config
+import pmb.config.init
+import pmb.helpers.logging
+
+
+@pytest.fixture
+def args(tmpdir, request):
+ import pmb.parse
+ sys.argv = ["pmbootstrap.py", "init"]
+ args = pmb.parse.arguments()
+ args.log = args.work + "/log_testsuite.txt"
+ pmb.helpers.logging.init(args)
+ request.addfinalizer(args.logfd.close)
+ return args
+
+
+def test_questions(args, monkeypatch, tmpdir):
+ #
+ # PREPARATION
+ #
+
+ # Use prepared answers
+ def fake_ask(args, question="Continue?", choices=["y", "n"], default="n",
+ lowercase_answer=True, validation_regex=None):
+ answer = answers.pop(0)
+ logging.info("pmb.helpers.cli.ask: fake answer: " + answer)
+ return answer
+ monkeypatch.setattr(pmb.helpers.cli, "ask", fake_ask)
+
+ # Do not generate aports
+ def fake_generate(args, pkgname):
+ return
+ monkeypatch.setattr(pmb.aportgen, "generate", fake_generate)
+
+ # Self-test
+ answers = ["first", "second"]
+ assert pmb.helpers.cli.ask(args) == "first"
+ assert pmb.helpers.cli.ask(args) == "second"
+ assert len(answers) == 0
+
+ #
+ # SIMPLE QUESTIONS
+ #
+
+ # Booleans
+ functions = [pmb.aportgen.device.ask_for_keyboard,
+ pmb.aportgen.device.ask_for_external_storage]
+ for func in functions:
+ answers = ["y", "n"]
+ assert func(args) is True
+ assert func(args) is False
+
+ # Strings
+ functions = [pmb.aportgen.device.ask_for_manufacturer,
+ pmb.aportgen.device.ask_for_name]
+ for func in functions:
+ answers = ["Simple string answer"]
+ assert func(args) == "Simple string answer"
+
+ #
+ # QUESTIONS WITH ANSWER VERIFICATION
+ #
+
+ # Architecture
+ answers = ["invalid_arch", "aarch64"]
+ assert pmb.aportgen.device.ask_for_architecture(args) == "aarch64"
+
+ # Device
+ func = pmb.config.init.ask_for_device
+ answers = ["lg-mako"]
+ assert func(args) == ("lg-mako", True)
+
+ answers = ["whoops-typo", "n", "lg-mako"]
+ assert func(args) == ("lg-mako", True)
+
+ answers = ["new-device", "y"]
+ assert func(args) == ("new-device", False)
+
+ # Flash methods
+ func = pmb.aportgen.device.ask_for_flash_method
+ answers = ["invalid_flash_method", "fastboot"]
+ assert func(args) == "fastboot"
+
+ answers = ["0xffff"]
+ assert func(args) == "0xffff"
+
+ answers = ["heimdall", "invalid_type", "isorec"]
+ assert func(args) == "heimdall-isorec"
+
+ answers = ["heimdall", "bootimg"]
+ assert func(args) == "heimdall-bootimg"
+
+ # Keymaps
+ func = pmb.config.init.ask_for_keymaps
+ answers = ["invalid_keymap", "us/rx51_us"]
+ assert func(args, "nokia-rx51") == "us/rx51_us"
+ assert func(args, "lg-mako") == ""
+
+ # UI
+ answers = ["invalid_UI", "weston"]
+ assert pmb.config.init.ask_for_ui(args) == "weston"
+
+ # Work path
+ tmpdir = str(tmpdir)
+ answers = ["/dev/null", tmpdir]
+ assert pmb.config.init.ask_for_work_path(args) == tmpdir