pmbootstrap init: ask for release channel (MR 1912)

Ask for release channel and switch pmaports branch to the related branch
defined in channels.cfg.

Store in pmbootstrap.cfg whether the user chose a channel (boolean). If
the user did not choose a channel yet, suggest the recommended channel
from channels.cfg (currently "edge").
This commit is contained in:
Oliver Smith 2020-04-09 20:48:21 +02:00
parent 261e8595ad
commit 17f3b3c2f0
No known key found for this signature in database
GPG Key ID: 5AE7F5513E0885CB
5 changed files with 132 additions and 1 deletions

View File

@ -42,6 +42,7 @@ config_keys = ["aports",
"device",
"extra_packages",
"hostname",
"is_default_channel",
"jobs",
"kernel",
"keymap",
@ -61,6 +62,7 @@ defaults = {
"alpine_version": "edge", # alternatively: latest-stable
"aports": "$WORK/cache_git/pmaports",
"ccache_size": "5G",
"is_default_channel": True,
# aes-xts-plain64 would be better, but this is not supported on LineageOS
# kernel configs
"cipher": "aes-cbc-plain64",

View File

@ -72,6 +72,39 @@ def ask_for_work_path(args):
" inside it! Please try again.")
def ask_for_channel(args):
""" Ask for the postmarketOS release channel. The channel dictates, which
pmaports branch pmbootstrap will check out, and which repository URLs
will be used when initializing chroots.
:returns: channel name (e.g. "edge", "stable") """
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
count = len(channels_cfg["channels"])
# List channels
logging.info("Choose the postmarketOS release channel.")
logging.info(f"Available ({count}):")
for channel, channel_data in channels_cfg["channels"].items():
logging.info(f"* {channel}: {channel_data['description']}")
# Default for first run: "recommended" from channels.cfg
# Otherwise, if valid: channel from pmaports.cfg of current branch
# The actual channel name is not saved in pmbootstrap.cfg, because then we
# would need to sync it with what is checked out in pmaports.git.
default = pmb.config.pmaports.read_config(args)["channel"]
choices = channels_cfg["channels"].keys()
if args.is_default_channel or default not in choices:
default = channels_cfg["meta"]["recommended"]
# Ask until user gives valid channel
while True:
ret = pmb.helpers.cli.ask(args, "Channel", None, default,
complete=choices)
if ret in choices:
return ret
logging.fatal("ERROR: Invalid channel specified, please type in one"
" from the list above.")
def ask_for_ui(args):
ui_list = pmb.helpers.ui.list(args)
logging.info("Available user interfaces (" +
@ -365,6 +398,11 @@ def frontend(args):
# Clone pmaports
pmb.config.pmaports.init(args)
# Choose release channel, possibly switch pmaports branch
channel = ask_for_channel(args)
pmb.config.pmaports.switch_to_channel_branch(args, channel)
cfg["pmbootstrap"]["is_default_channel"] = "False"
# Device
device, device_exists, kernel, nonfree = ask_for_device(args)
cfg["pmbootstrap"]["device"] = device

View File

@ -124,3 +124,38 @@ def init(args):
clone(args)
symlink(args)
read_config(args)
def switch_to_channel_branch(args, channel_new):
""" Checkout the channel's branch in pmaports.git.
:channel_new: channel name (e.g. "edge", "stable")
:returns: True if another branch was checked out, False otherwise """
# Check current pmaports branch channel
channel_current = read_config(args)["channel"]
if channel_current == channel_new:
return False
# List current and new branches/channels
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
branch_new = channels_cfg["channels"][channel_new]["branch_pmaports"]
branch_current = pmb.helpers.git.rev_parse(args, args.aports,
extra_args=["--abbrev-ref"])
logging.info(f"Currently checked out branch '{branch_current}' of"
f" pmaports.git is on channel '{channel_current}'.")
logging.info(f"Switching to branch '{branch_new}' on channel"
f" '{channel_new}'...")
# Attempt to switch branch (git gives a nice error message, mentioning
# which files need to be committed/stashed, so just pass it through)
if pmb.helpers.run.user(args, ["git", "checkout", branch_new],
args.aports, "interactive", check=False):
raise RuntimeError("Failed to switch branch. Go to your pmaports and"
" fix what git complained about, then try again: "
f"{args.aports}")
# Invalidate all caches
pmb.helpers.args.add_cache(args)
# Verify pmaports.cfg on new branch
read_config(args)
return True

View File

@ -0,0 +1,50 @@
# Copyright 2020 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
""" Test pmb/config/pmaports.py """
import pytest
import sys
import pmb_test
import pmb_test.const
import pmb_test.git
import pmb.config
import pmb.config.workdir
import pmb.config.pmaports
@pytest.fixture
def args(request):
import pmb.parse
cfg = f"{pmb_test.const.testdata}/channels.cfg"
sys.argv = ["pmbootstrap.py", "--config-channels", cfg, "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_switch_to_channel_branch(args, monkeypatch, tmpdir):
path, run_git = pmb_test.git.prepare_tmpdir(args, monkeypatch, tmpdir)
args.aports = path
# Pretend to have channel=edge in pmaports.cfg
def read_config(args):
return {"channel": "edge"}
monkeypatch.setattr(pmb.config.pmaports, "read_config", read_config)
# Success: Channel does not change
func = pmb.config.pmaports.switch_to_channel_branch
assert func(args, "edge") is False
# Fail: git error (could be any error, but here: branch does not exist)
with pytest.raises(RuntimeError) as e:
func(args, "stable")
assert str(e.value).startswith("Failed to switch branch")
# Success: switch channel and change branch
run_git(["checkout", "-b", "v20.05"])
run_git(["checkout", "master"])
assert func(args, "stable") is True
branch = pmb.helpers.git.rev_parse(args, path, extra_args=["--abbrev-ref"])
assert branch == "v20.05"

View File

@ -16,7 +16,8 @@ import pmb.helpers.logging
@pytest.fixture
def args(tmpdir, request):
import pmb.parse
sys.argv = ["pmbootstrap.py", "init"]
cfg = f"{pmb_test.const.testdata}/channels.cfg"
sys.argv = ["pmbootstrap.py", "--config-channels", cfg, "init"]
args = pmb.parse.arguments()
args.log = args.work + "/log_testsuite.txt"
pmb.helpers.logging.init(args)
@ -287,3 +288,8 @@ def test_questions_hostname(args, monkeypatch):
# Device name: empty string
fake_answers(monkeypatch, [device])
assert func(args, device) == ""
def test_questions_channel(args, monkeypatch):
fake_answers(monkeypatch, ["invalid-channel", "stable"])
assert pmb.config.init.ask_for_channel(args) == "stable"