diff --git a/pmb/build/newapkbuild.py b/pmb/build/newapkbuild.py
index 177e2399..d0862a0e 100644
--- a/pmb/build/newapkbuild.py
+++ b/pmb/build/newapkbuild.py
@@ -21,7 +21,7 @@ import os
import logging
import pmb.chroot.user
import pmb.helpers.cli
-import pmb.parse.apkbuild
+import pmb.parse
def newapkbuild(args, folder, args_passed):
diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py
index c3473ec3..2a8d827f 100644
--- a/pmb/config/__init__.py
+++ b/pmb/config/__init__.py
@@ -46,6 +46,7 @@ work_version = "1"
# Only save keys to the config file, which we ask for in 'pmbootstrap init'.
config_keys = ["ccache_size", "device", "extra_packages", "jobs", "keymap",
+ "nonfree_firmware", "nonfree_userland",
"qemu_native_mesa_driver", "timezone", "ui", "user", "work"]
# Config file/commandline default values
@@ -70,6 +71,8 @@ defaults = {
"log": "$WORK/log.txt",
"mirror_alpine": "http://dl-cdn.alpinelinux.org/alpine/",
"mirror_postmarketos": "http://postmarketos.brixit.nl",
+ "nonfree_firmware": True,
+ "nonfree_userland": False,
"port_distccd": "33632",
"qemu_native_mesa_driver": "dri-virtio",
"timezone": "GMT",
diff --git a/pmb/config/init.py b/pmb/config/init.py
index 6ff39432..4db7d4b6 100644
--- a/pmb/config/init.py
+++ b/pmb/config/init.py
@@ -27,6 +27,7 @@ import pmb.helpers.run
import pmb.helpers.ui
import pmb.chroot.zap
import pmb.parse.deviceinfo
+import pmb.parse._apkbuild
def ask_for_work_path(args):
@@ -123,6 +124,51 @@ def ask_for_timezone(args):
return "GMT"
+def ask_for_device_nonfree(args, device):
+ """
+ Ask the user about enabling proprietary firmware (e.g. Wifi) and userland
+ (e.g. GPU drivers). All proprietary components are in subpackages
+ $pkgname-nonfree-firmware and $pkgname-nonfree-userland, and we show the
+ description of these subpackages (so they can indicate which peripherals
+ are affected).
+
+ :returns: answers as dict, e.g. {"firmware": True, "userland": False}
+ """
+ # Parse existing APKBUILD or return defaults (when called from test case)
+ apkbuild_path = args.aports + "/device/device-" + device + "/APKBUILD"
+ ret = {"firmware": args.nonfree_firmware,
+ "userland": args.nonfree_userland}
+ if not os.path.exists(apkbuild_path):
+ return ret
+ apkbuild = pmb.parse.apkbuild(args, apkbuild_path)
+
+ # Only run when there is a "nonfree" subpackage
+ nonfree_found = False
+ for subpackage in apkbuild["subpackages"]:
+ if subpackage.startswith("device-" + device + "-nonfree"):
+ nonfree_found = True
+ if not nonfree_found:
+ return ret
+
+ # Short explanation
+ logging.info("This device has proprietary components, which trade some of"
+ " your freedom with making more peripherals work.")
+ logging.info("We would like to offer full functionality without hurting"
+ " your freedom, but this is currently not possible for your"
+ " device.")
+
+ # Ask for firmware and userland individually
+ for type in ["firmware", "userland"]:
+ subpkgname = "device-" + device + "-nonfree-" + type
+ if subpkgname in apkbuild["subpackages"]:
+ subpkgdesc = pmb.parse._apkbuild.subpkgdesc(apkbuild_path,
+ "nonfree_" + type)
+ logging.info(subpkgname + ": " + subpkgdesc)
+ ret[type] = pmb.helpers.cli.confirm(args, "Enable this package?",
+ default=ret[type])
+ return ret
+
+
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"
@@ -144,7 +190,8 @@ def ask_for_device(args):
pmb.aportgen.generate(args, "linux-" + device)
break
- return (device, device_exists)
+ nonfree = ask_for_device_nonfree(args, device)
+ return (device, device_exists, nonfree)
def ask_for_qemu_native_mesa_driver(args, device, arch_native):
@@ -200,8 +247,10 @@ def frontend(args):
cfg["pmbootstrap"]["work"] = args.work = ask_for_work_path(args)
# Device
- device, device_exists = ask_for_device(args)
+ device, device_exists, nonfree = ask_for_device(args)
cfg["pmbootstrap"]["device"] = device
+ cfg["pmbootstrap"]["nonfree_firmware"] = str(nonfree["firmware"])
+ cfg["pmbootstrap"]["nonfree_userland"] = str(nonfree["userland"])
# Qemu mesa driver
if cfg["pmbootstrap"]["device"].startswith("qemu-"):
diff --git a/pmb/install/__init__.py b/pmb/install/__init__.py
index e2f2bb45..b8610b5e 100644
--- a/pmb/install/__init__.py
+++ b/pmb/install/__init__.py
@@ -16,7 +16,7 @@ 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 .
"""
-from pmb.install.install import install
+from pmb.install._install import install
from pmb.install.partition import partition
from pmb.install.format import format
from pmb.install.partition import partitions_mount
diff --git a/pmb/install/install.py b/pmb/install/_install.py
similarity index 93%
rename from pmb/install/install.py
rename to pmb/install/_install.py
index 1c523403..c8e9ec60 100644
--- a/pmb/install/install.py
+++ b/pmb/install/_install.py
@@ -67,6 +67,29 @@ def get_subpartitions_size(args):
return (full, boot)
+def get_nonfree_packages(args, device):
+ """
+ Get the non-free packages based on user's choice in "pmbootstrap init" and
+ based on whether there are non-free packages in the APKBUILD or not.
+
+ :returns: list of non-free packages to be installed. Example:
+ ["device-nokia-n900-nonfree-firmware"]
+ """
+ # Read subpackages
+ apkbuild_path = args.aports + "/device/device-" + device + "/APKBUILD"
+ apkbuild = pmb.parse.apkbuild(args, apkbuild_path)
+ subpackages = apkbuild["subpackages"]
+
+ # Check for firmware and userland
+ ret = []
+ prefix = "device-" + device + "-nonfree-"
+ if args.nonfree_firmware and prefix + "firmware" in subpackages:
+ ret += [prefix + "firmware"]
+ if args.nonfree_userland and prefix + "userland" in subpackages:
+ ret += [prefix + "userland"]
+ return ret
+
+
def copy_files_from_chroot(args):
"""
Copy all files from the rootfs chroot to /mnt/install, except
@@ -316,7 +339,8 @@ def install(args):
logging.info('*** (2/{0}) CREATE DEVICE ROOTFS ("{1}") ***'.format(steps,
args.device))
install_packages = (pmb.config.install_device_packages +
- ["device-" + args.device])
+ ["device-" + args.device] +
+ get_nonfree_packages(args, args.device))
if args.ui.lower() != "none":
install_packages += ["postmarketos-ui-" + args.ui]
suffix = "rootfs_" + args.device
diff --git a/pmb/parse/__init__.py b/pmb/parse/__init__.py
index b906f449..249efe36 100644
--- a/pmb/parse/__init__.py
+++ b/pmb/parse/__init__.py
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with pmbootstrap. If not, see .
"""
from pmb.parse.arguments import arguments
-from pmb.parse.apkbuild import apkbuild
+from pmb.parse._apkbuild import apkbuild
from pmb.parse.binfmt_info import binfmt_info
from pmb.parse.deviceinfo import deviceinfo
from pmb.parse.kconfig import check
diff --git a/pmb/parse/apkbuild.py b/pmb/parse/_apkbuild.py
similarity index 85%
rename from pmb/parse/apkbuild.py
rename to pmb/parse/_apkbuild.py
index 5499e4bd..c6fdf046 100644
--- a/pmb/parse/apkbuild.py
+++ b/pmb/parse/_apkbuild.py
@@ -173,3 +173,37 @@ def apkbuild(args, path, check_pkgver=True):
# Fill cache
args.cache["apkbuild"][path] = ret
return ret
+
+
+def subpkgdesc(path, function):
+ """
+ Get the pkgdesc of a subpackage in an APKBUILD.
+
+ :param path: to the APKBUILD file
+ :param function: name of the subpackage (e.g. "nonfree_userland")
+ :returns: the subpackage's pkgdesc
+ """
+ # Read all lines
+ with open(path, encoding="utf-8") as handle:
+ lines = handle.readlines()
+
+ # Prefixes
+ prefix_function = function + "() {"
+ prefix_pkgdesc = "\tpkgdesc=\""
+
+ # Find the pkgdesc
+ in_function = False
+ for line in lines:
+ if in_function:
+ if line.startswith(prefix_pkgdesc):
+ return line[len(prefix_pkgdesc):-2]
+ elif line.startswith(prefix_function):
+ in_function = True
+
+ # Failure
+ if not in_function:
+ raise RuntimeError("Could not find subpackage function, no line starts"
+ " with '" + prefix_function + "' in " + path)
+ raise RuntimeError("Could not find pkgdesc of subpackage function '" +
+ function + "' (spaces used instead of tabs?) in " +
+ path)
diff --git a/test/test_aports_deviceinfo.py b/test/test_aports_deviceinfo.py
index f732b5d1..a3170432 100644
--- a/test/test_aports_deviceinfo.py
+++ b/test/test_aports_deviceinfo.py
@@ -25,7 +25,7 @@ import pytest
pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/.."))
sys.path.append(pmb_src)
import pmb.parse.apkindex
-import pmb.parse.apkbuild
+import pmb.parse
import pmb.helpers.logging
diff --git a/test/test_install.py b/test/test_install.py
new file mode 100644
index 00000000..19ab5a78
--- /dev/null
+++ b/test/test_install.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2018 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 os
+import pytest
+import sys
+
+# Import from parent directory
+pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/.."))
+sys.path.append(pmb_src)
+import pmb.aportgen.device
+import pmb.config
+import pmb.config.init
+import pmb.helpers.logging
+import pmb.install._install
+
+
+@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_get_nonfree_packages(args):
+ args.aports = pmb_src + "/test/testdata/init_questions_device/aports"
+ func = pmb.install._install.get_nonfree_packages
+
+ # Device without any non-free subpackages
+ args.nonfree_firmware = True
+ args.nonfree_userland = True
+ assert func(args, "lg-mako") == []
+
+ # Device with non-free firmware and userland
+ device = "nonfree-firmware-and-userland"
+ assert func(args, device) == ["device-" + device + "-nonfree-firmware",
+ "device-" + device + "-nonfree-userland"]
+
+ # Device with non-free userland
+ device = "nonfree-userland"
+ assert func(args, device) == ["device-" + device + "-nonfree-userland"]
+
+ # Device with non-free userland (but user disabled it init)
+ args.nonfree_userland = False
+ assert func(args, device) == []
diff --git a/test/test_parse_apkbuild.py b/test/test_parse_apkbuild.py
new file mode 100644
index 00000000..b39f94dd
--- /dev/null
+++ b/test/test_parse_apkbuild.py
@@ -0,0 +1,50 @@
+"""
+Copyright 2018 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 os
+import pytest
+import sys
+
+# Import from parent directory
+pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/.."))
+sys.path.append(pmb_src)
+
+import pmb.parse._apkbuild
+
+
+def test_subpkgdesc():
+ func = pmb.parse._apkbuild.subpkgdesc
+ testdata = pmb_src + "/test/testdata"
+
+ # Successful extraction
+ path = (testdata + "/init_questions_device/aports/device/"
+ "device-nonfree-firmware/APKBUILD")
+ pkgdesc = "firmware description"
+ assert func(path, "nonfree_firmware") == pkgdesc
+
+ # Can't find the function
+ with pytest.raises(RuntimeError) as e:
+ func(path, "invalid_function")
+ assert str(e.value).startswith("Could not find subpackage function")
+
+ # Can't find the pkgdesc in the function
+ path = testdata + "/apkbuild/APKBUILD.missing-pkgdesc-in-subpackage"
+ with pytest.raises(RuntimeError) as e:
+ func(path, "subpackage")
+ assert str(e.value).startswith("Could not find pkgdesc of subpackage")
diff --git a/test/test_questions.py b/test/test_questions.py
index 5b6c81ec..685c36bf 100644
--- a/test/test_questions.py
+++ b/test/test_questions.py
@@ -41,64 +41,58 @@ def args(tmpdir, request):
return args
-def test_questions(args, monkeypatch, tmpdir):
- #
- # PREPARATION
- #
+def fake_answers(monkeypatch, answers):
+ """
+ Patch pmb.helpers.cli.ask() function to return defined answers instead of
+ asking the user for an answer.
- # Use prepared answers
+ :param answers: list of answer strings, e.g. ["y", "n", "invalid-device"].
+ In this example, the first question is answered with "y",
+ the second question with "n" and so on.
+ """
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)
+ 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"]
+def test_fake_answers_selftest(monkeypatch):
+ fake_answers(monkeypatch, ["first", "second"])
assert pmb.helpers.cli.ask(args) == "first"
assert pmb.helpers.cli.ask(args) == "second"
- assert len(answers) == 0
- #
- # SIMPLE QUESTIONS
- #
- # Booleans
+def test_questions_booleans(args, monkeypatch):
functions = [pmb.aportgen.device.ask_for_keyboard,
pmb.aportgen.device.ask_for_external_storage]
for func in functions:
- answers = ["y", "n"]
+ fake_answers(monkeypatch, ["y", "n"])
assert func(args) is True
assert func(args) is False
- # Strings
+
+def test_questions_strings(args, monkeypatch):
functions = [pmb.aportgen.device.ask_for_manufacturer,
pmb.aportgen.device.ask_for_name]
for func in functions:
- answers = ["Simple string answer"]
+ fake_answers(monkeypatch, ["Simple string answer"])
assert func(args) == "Simple string answer"
- #
- # QUESTIONS WITH ANSWER VERIFICATION
- #
- # Architecture
- answers = ["invalid_arch", "aarch64"]
+def test_questions_arch(args, monkeypatch):
+ fake_answers(monkeypatch, ["invalid_arch", "aarch64"])
assert pmb.aportgen.device.ask_for_architecture(args) == "aarch64"
- # Bootimg
+
+def test_questions_bootimg(args, monkeypatch):
func = pmb.aportgen.device.ask_for_bootimg
- answers = ["invalid_path", ""]
+ fake_answers(monkeypatch, ["invalid_path", ""])
assert func(args) is None
bootimg_path = pmb_src + "/test/testdata/bootimg/normal-boot.img"
- answers = [bootimg_path]
+ fake_answers(monkeypatch, [bootimg_path])
output = {"base": "0x80000000",
"kernel_offset": "0x00008000",
"ramdisk_offset": "0x04000000",
@@ -109,66 +103,119 @@ def test_questions(args, monkeypatch, tmpdir):
"qcdt": "false"}
assert func(args) == output
- # Device
+
+def test_questions_device(args, monkeypatch):
+ # Prepare args
+ args.aports = pmb_src + "/test/testdata/init_questions_device/aports"
+ args.device = "lg-mako"
+ args.nonfree_firmware = True
+ args.nonfree_userland = False
+
+ # Do not generate aports
+ def fake_generate(args, pkgname):
+ return
+ monkeypatch.setattr(pmb.aportgen, "generate", fake_generate)
+
+ # Existing device (without non-free components so we have defaults there)
func = pmb.config.init.ask_for_device
- answers = ["lg-mako"]
- assert func(args) == ("lg-mako", True)
+ nonfree = {"firmware": True, "userland": False}
+ fake_answers(monkeypatch, ["lg-mako"])
+ assert func(args) == ("lg-mako", True, nonfree)
- answers = ["whoops-typo", "n", "lg-mako"]
- assert func(args) == ("lg-mako", True)
+ # Non-existing device, go back, existing device
+ fake_answers(monkeypatch, ["whoops-typo", "n", "lg-mako"])
+ assert func(args) == ("lg-mako", True, nonfree)
- answers = ["new-device", "y"]
- assert func(args) == ("new-device", False)
+ # New device
+ fake_answers(monkeypatch, ["new-device", "y"])
+ assert func(args) == ("new-device", False, nonfree)
- # Flash methods
+
+def test_questions_device_nonfree(args, monkeypatch):
+ # Prepare args
+ args.aports = pmb_src + "/test/testdata/init_questions_device/aports"
+ args.nonfree_firmware = False
+ args.nonfree_userland = False
+
+ # APKBUILD with firmware and userland (all yes)
+ func = pmb.config.init.ask_for_device_nonfree
+ device = "nonfree-firmware-and-userland"
+ fake_answers(monkeypatch, ["y", "y"])
+ nonfree = {"firmware": True, "userland": True}
+ assert func(args, device) == nonfree
+
+ # APKBUILD with firmware and userland (all no)
+ fake_answers(monkeypatch, ["n", "n"])
+ nonfree = {"firmware": False, "userland": False}
+ assert func(args, device) == nonfree
+
+ # APKBUILD with firmware only
+ func = pmb.config.init.ask_for_device_nonfree
+ device = "nonfree-firmware"
+ fake_answers(monkeypatch, ["y"])
+ nonfree = {"firmware": True, "userland": False}
+ assert func(args, device) == nonfree
+
+ # APKBUILD with userland only
+ func = pmb.config.init.ask_for_device_nonfree
+ device = "nonfree-userland"
+ fake_answers(monkeypatch, ["y"])
+ nonfree = {"firmware": False, "userland": True}
+ assert func(args, device) == nonfree
+
+
+def test_questions_flash_methods(args, monkeypatch):
func = pmb.aportgen.device.ask_for_flash_method
- answers = ["invalid_flash_method", "fastboot"]
+ fake_answers(monkeypatch, ["invalid_flash_method", "fastboot"])
assert func(args) == "fastboot"
- answers = ["0xffff"]
+ fake_answers(monkeypatch, ["0xffff"])
assert func(args) == "0xffff"
- answers = ["heimdall", "invalid_type", "isorec"]
+ fake_answers(monkeypatch, ["heimdall", "invalid_type", "isorec"])
assert func(args) == "heimdall-isorec"
- answers = ["heimdall", "bootimg"]
+ fake_answers(monkeypatch, ["heimdall", "bootimg"])
assert func(args) == "heimdall-bootimg"
- # Keymaps
+
+def test_questions_keymaps(args, monkeypatch):
func = pmb.config.init.ask_for_keymaps
- answers = ["invalid_keymap", "us/rx51_us"]
+ fake_answers(monkeypatch, ["invalid_keymap", "us/rx51_us"])
assert func(args, "nokia-n900") == "us/rx51_us"
assert func(args, "lg-mako") == ""
- # Qemu native mesa driver
+
+def test_questions_qemu_native_mesa(args, monkeypatch):
func = pmb.config.init.ask_for_qemu_native_mesa_driver
- answers = ["invalid_driver", "dri-swrast"]
+ fake_answers(monkeypatch, ["invalid_driver", "dri-swrast"])
assert func(args, "qemu-amd64", "x86_64") == "dri-swrast"
assert func(args, "qemu-aarch64", "x86_64") is None
- # UI
- answers = ["invalid_UI", "weston"]
+
+def test_questions_ui(args, monkeypatch):
+ fake_answers(monkeypatch, ["invalid_UI", "weston"])
assert pmb.config.init.ask_for_ui(args) == "weston"
- # Work path
+
+def test_questions_work_path(args, monkeypatch, tmpdir):
tmpdir = str(tmpdir)
- answers = ["/dev/null", os.path.dirname(__file__), pmb.config.pmb_src,
- tmpdir]
+ fake_answers(monkeypatch, ["/dev/null", os.path.dirname(__file__),
+ pmb.config.pmb_src, tmpdir])
assert pmb.config.init.ask_for_work_path(args) == tmpdir
- #
- # BUILD OPTIONS
- #
+
+def test_questions_build_options(args, monkeypatch):
func = pmb.config.init.ask_for_build_options
cfg = {"pmbootstrap": {}}
# Skip changing anything
- answers = ["n"]
+ fake_answers(monkeypatch, ["n"])
func(args, cfg)
assert cfg == {"pmbootstrap": {}}
# Answer everything
- answers = ["y", "5", "2G", "n"]
+ fake_answers(monkeypatch, ["y", "5", "2G", "n"])
func(args, cfg)
assert cfg == {"pmbootstrap": {"jobs": "5",
"ccache_size": "2G"}}
diff --git a/test/test_upstream_compatibility.py b/test/test_upstream_compatibility.py
index 81825791..e428ffb5 100644
--- a/test/test_upstream_compatibility.py
+++ b/test/test_upstream_compatibility.py
@@ -25,7 +25,7 @@ import pytest
pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/.."))
sys.path.append(pmb_src)
import pmb.parse.apkindex
-import pmb.parse.apkbuild
+import pmb.parse
import pmb.helpers.logging
diff --git a/test/testdata/apkbuild/APKBUILD.missing-pkgdesc-in-subpackage b/test/testdata/apkbuild/APKBUILD.missing-pkgdesc-in-subpackage
new file mode 100644
index 00000000..7d83ff89
--- /dev/null
+++ b/test/testdata/apkbuild/APKBUILD.missing-pkgdesc-in-subpackage
@@ -0,0 +1,8 @@
+# Reference:
+pkgname="missing-pkgdesc-in-subpackage"
+subpackages="$pkgname-subpackage"
+
+subpackage() {
+ # this function does not have a pkgdesc
+ mkdir "$subpkgdir"
+}
diff --git a/test/testdata/init_questions_device/aports/device/device-lg-mako/APKBUILD b/test/testdata/init_questions_device/aports/device/device-lg-mako/APKBUILD
new file mode 100644
index 00000000..55323be7
--- /dev/null
+++ b/test/testdata/init_questions_device/aports/device/device-lg-mako/APKBUILD
@@ -0,0 +1,16 @@
+# This is not a real aport, it's for the "pmbootstrap init" questions test
+
+pkgname=device-lg-mako
+pkgver=2
+pkgrel=16
+pkgdesc="Google Nexus 4"
+url="https://github.com/postmarketOS"
+arch="noarch"
+license="MIT"
+depends="linux-lg-mako mkbootimg mesa-dri-swrast"
+makedepends=""
+install=""
+subpackages="$pkgname-weston"
+source=""
+options="!check"
+
diff --git a/test/testdata/init_questions_device/aports/device/device-lg-mako/deviceinfo b/test/testdata/init_questions_device/aports/device/device-lg-mako/deviceinfo
new file mode 100644
index 00000000..4631f224
--- /dev/null
+++ b/test/testdata/init_questions_device/aports/device/device-lg-mako/deviceinfo
@@ -0,0 +1,31 @@
+# Reference:
+# Please use double quotes only. You can source this file in shell scripts.
+
+deviceinfo_format_version="0"
+deviceinfo_name="Google Nexus 4"
+deviceinfo_manufacturer="LG"
+deviceinfo_date=""
+deviceinfo_nonfree="????"
+deviceinfo_dtb=""
+deviceinfo_modules_initfs=""
+deviceinfo_external_disk="false"
+deviceinfo_external_disk_install="false"
+deviceinfo_flash_method="fastboot"
+deviceinfo_arch="armhf"
+
+# Device related
+deviceinfo_keyboard="false"
+deviceinfo_screen_width="768"
+deviceinfo_screen_height="1280"
+deviceinfo_dev_touchscreen="/dev/input/event2"
+
+# Fastboot related
+deviceinfo_generate_bootimg="true"
+deviceinfo_flash_offset_kernel="0x80208000"
+deviceinfo_flash_offset_ramdisk="0x81800000"
+deviceinfo_flash_offset_second="0x81100000"
+deviceinfo_flash_offset_tags="0x80200100"
+deviceinfo_flash_pagesize="2048"
+
+# Weston red screen workaround (see issue #54)
+deviceinfo_weston_pixman_type="2"
diff --git a/test/testdata/init_questions_device/aports/device/device-nonfree-firmware-and-userland/APKBUILD b/test/testdata/init_questions_device/aports/device/device-nonfree-firmware-and-userland/APKBUILD
new file mode 100644
index 00000000..d86cbc62
--- /dev/null
+++ b/test/testdata/init_questions_device/aports/device/device-nonfree-firmware-and-userland/APKBUILD
@@ -0,0 +1,33 @@
+# Reference:
+pkgname="device-nonfree-firmware-and-userland"
+pkgdesc="Test device for nonfree questions"
+pkgver=0.1
+pkgrel=0
+url="https://postmarketos.org"
+license="MIT"
+arch="noarch"
+options="!check"
+depends="mesa-dri-swrast"
+makedepends="devicepkg-dev"
+source="deviceinfo"
+subpackages="$pkgname-nonfree-firmware:nonfree_firmware $pkgname-nonfree-userland:nonfree_userland"
+
+build() {
+ devicepkg_build $startdir $pkgname
+}
+
+package() {
+ devicepkg_package $startdir $pkgname
+}
+
+nonfree_firmware() {
+ pkgdesc="firmware description"
+ mkdir "$subpkgdir"
+}
+
+nonfree_userland() {
+ pkgdesc="userland description"
+ mkdir "$subpkgdir"
+}
+
+sha512sums="71c640728d3ade4bea402523c1cdb30e0edac585948cfae987bac9f001a0eb572e5be9ea2babef4eb8f9f6437a3677ce3e7be398e00865a6d3f781a8d4b3bf5d deviceinfo"
diff --git a/test/testdata/init_questions_device/aports/device/device-nonfree-firmware/APKBUILD b/test/testdata/init_questions_device/aports/device/device-nonfree-firmware/APKBUILD
new file mode 100644
index 00000000..5b10e3b7
--- /dev/null
+++ b/test/testdata/init_questions_device/aports/device/device-nonfree-firmware/APKBUILD
@@ -0,0 +1,28 @@
+# Reference:
+pkgname="device-nonfree-firmware"
+pkgdesc="Test device for nonfree questions"
+pkgver=0.1
+pkgrel=0
+url="https://postmarketos.org"
+license="MIT"
+arch="noarch"
+options="!check"
+depends="mesa-dri-swrast"
+makedepends="devicepkg-dev"
+source="deviceinfo"
+subpackages="$pkgname-nonfree-firmware:nonfree_firmware"
+
+build() {
+ devicepkg_build $startdir $pkgname
+}
+
+package() {
+ devicepkg_package $startdir $pkgname
+}
+
+nonfree_firmware() {
+ pkgdesc="firmware description"
+ mkdir "$subpkgdir"
+}
+
+sha512sums="71c640728d3ade4bea402523c1cdb30e0edac585948cfae987bac9f001a0eb572e5be9ea2babef4eb8f9f6437a3677ce3e7be398e00865a6d3f781a8d4b3bf5d deviceinfo"
diff --git a/test/testdata/init_questions_device/aports/device/device-nonfree-userland/APKBUILD b/test/testdata/init_questions_device/aports/device/device-nonfree-userland/APKBUILD
new file mode 100644
index 00000000..8c2973ff
--- /dev/null
+++ b/test/testdata/init_questions_device/aports/device/device-nonfree-userland/APKBUILD
@@ -0,0 +1,20 @@
+# Reference:
+pkgname="device-nonfree-userland"
+pkgdesc="Test device for nonfree questions"
+pkgver=0.1
+pkgrel=0
+url="https://postmarketos.org"
+license="MIT"
+arch="noarch"
+options="!check"
+depends="mesa-dri-swrast"
+makedepends="devicepkg-dev"
+source="deviceinfo"
+subpackages="$pkgname-nonfree-userland:nonfree_userland"
+
+nonfree_userland() {
+ pkgdesc="userland description"
+ mkdir "$subpkgdir"
+}
+
+sha512sums="71c640728d3ade4bea402523c1cdb30e0edac585948cfae987bac9f001a0eb572e5be9ea2babef4eb8f9f6437a3677ce3e7be398e00865a6d3f781a8d4b3bf5d deviceinfo"