Make proprietary drivers optional (1/2): pmbootstrap changes (#1254)

Here are the changes necessary in pmbootstrap to make proprietary
software installed onto the device (firmware and userspace drivers)
optional (#756). To full close the issue, we need to apply this concept
to all device packages we already have in a follow-up PR.

Changes:
* New config file options nonfree_firmware and nonfree_userland, which
  we ask for during "pmbootstrap init" if there are non-free components
  for the selected device.
* We find that out by checking the APKBUILD's subpakages: The non-free
  packages are called $pkgname-nonfree-firmware and
  $pkgname-nonfree-userland.
* During "pmbootstrap init" we also show the pkgdesc of these
  subpackages. Parsing that is implemented in
  pmb.parse._apkbuild.subpkgdesc(). It was not implemented as part of
  the regular APKBUILD parsing, as this would need a change in the
  output format, and it is a lot *less* code if done like in this
  commit.
* pmb/parse/apkbuild.py was renamed to _apkbuild.py, and
  pmb/install/install.py to _install.py: needed to call the function in
  the usual way (e.g. pmb.parse.apkbuild()) but still being able to
  test the individual functions from these files in the test suite.
  We did the same thing for pmb/build/_package.py already.
* Install: New function get_nonfree_packages() returns the non-free
  packages that will be installed, based on the user's choice in
  "pmbootstrap init" and on the subpackages the device has.
* Added test cases and test data (APKBUILDs) for all new code,
  refactored test/test_questions.py to have multiple functions for
  testing the various questions / question types from
  "pmbootstrap init" instead of having it all in one big function.
  This allows to use another aport folder for testing the new
  non-free related questions in init.
This commit is contained in:
Oliver Smith 2018-02-24 21:49:10 +00:00 committed by GitHub
parent 2e30fa4281
commit ad5a0d4294
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 469 additions and 62 deletions

View file

@ -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"}}