forked from Mirror/pmbootstrap
The mesa driver, which ends up in the installation image, needs to be known before the installation is done (in other words: when running the qemu action, it is to late as the image has already been generated). That's why one can choose the Qemu mesa driver in `pmbootstrap init` now: ``` Device [qemu-amd64]: Which mesa driver do you prefer for your Qemu device? Only select something other than the default if you are having graphical problems (such as glitches). Mesa driver (dri-swrast/dri-virtio) [dri-virtio]: ``` It is still possible to select `dri-swrast`, because `dri-virtio` may not work in all cases, and that way we could easily debug it or experiment with other mesa drivers (e.g. the "vmware" one, which is supported by mesa and Qemu). Other changes: * `pmbootstrap qemu` accepts a `--display` variable now, which passes the value directly to `qemu`'s `display` option. It defaults to `sdl,gl=on` (@PureTryOut reported that to work best with plasma mobile on his PC). `--display` and `--spice` (which is still working) are mutually exclusive. * Removed obsolete telnet port pass-through: We only use the debug telnet port since osk-sdl has been merged. * Add show-cursor to the Qemu command line, so it shows a cursor in X11 * Refactored the spice code (`command_spice` only returns the spice command, because it has all necessary information already) and the spice port can be specified on the commandline now (previously it was hardcoded in one place and then always looked up from there). * Start comments with capital letters. * Keep the log on the screen a bit shorter (e.g. Qemu command is written to the "pmbootstrap log" anyway, so there's no need to display it again). * linux-postmarketos-stable: Adjust kernel configs x86_64, armhf: enable as modules: CONFIG_DRM_VIRTIO_GPU, CONFIG_VIRTIO_PCI, CONFIG_VIRTIO_BALLOON aarch64: all 3 options were already enabled as built-in (no change) * Set '-vga virtio' for mesa-dri-virtio
231 lines
9 KiB
Python
231 lines
9 KiB
Python
"""
|
|
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 <http://www.gnu.org/licenses/>.
|
|
"""
|
|
import logging
|
|
import glob
|
|
import os
|
|
|
|
import pmb.config
|
|
import pmb.helpers.cli
|
|
import pmb.helpers.devices
|
|
import pmb.helpers.run
|
|
import pmb.helpers.ui
|
|
import pmb.chroot.zap
|
|
import pmb.parse.deviceinfo
|
|
|
|
|
|
def ask_for_work_path(args):
|
|
"""
|
|
Ask for the work path, until we can create it (when it does not exist) and
|
|
write into it.
|
|
:returns: the work path
|
|
"""
|
|
logging.info("Location of the 'work' path. Multiple chroots"
|
|
" (native, device arch, device rootfs) will be created"
|
|
" in there.")
|
|
while True:
|
|
try:
|
|
ret = os.path.expanduser(pmb.helpers.cli.ask(
|
|
args, "Work path", None, args.work, False))
|
|
ret = os.path.realpath(ret)
|
|
|
|
# Work must not be inside the pmbootstrap path
|
|
if ret == pmb.config.pmb_src or ret.startswith(pmb.config.pmb_src +
|
|
"/"):
|
|
logging.fatal("ERROR: The work path must not be inside the"
|
|
" pmbootstrap path. Please specify another"
|
|
" location.")
|
|
continue
|
|
|
|
# Create the folder with a version file
|
|
if not os.path.exists(ret):
|
|
os.makedirs(ret, 0o700, True)
|
|
with open(ret + "/version", "w") as handle:
|
|
handle.write(pmb.config.work_version + "\n")
|
|
|
|
# Make sure, that we can write into it
|
|
os.makedirs(ret + "/cache_http", 0o700, True)
|
|
return ret
|
|
except OSError:
|
|
logging.fatal("ERROR: Could not create this folder, or write"
|
|
" inside it! Please try again.")
|
|
|
|
|
|
def ask_for_ui(args):
|
|
ui_list = pmb.helpers.ui.list(args)
|
|
logging.info("Available user interfaces (" +
|
|
str(len(ui_list) - 1) + "): ")
|
|
for ui, description in ui_list.items():
|
|
logging.info("* " + ui + ": " + description)
|
|
while True:
|
|
ret = pmb.helpers.cli.ask(args, "User interface", None, args.ui, True)
|
|
if ret in ui_list:
|
|
return ret
|
|
logging.fatal("ERROR: Invalid user interface specified, please type in"
|
|
" one from the list above.")
|
|
|
|
|
|
def ask_for_keymaps(args, device):
|
|
info = pmb.parse.deviceinfo(args, device=device)
|
|
if "keymaps" not in info or info["keymaps"].strip() == "":
|
|
return ""
|
|
options = info["keymaps"].split(' ')
|
|
logging.info("Available keymaps for device (" + str(len(options)) +
|
|
"): " + ", ".join(options))
|
|
if args.keymap is "":
|
|
args.keymap = options[0]
|
|
|
|
while True:
|
|
ret = pmb.helpers.cli.ask(args, "Keymap", None, args.keymap, True)
|
|
if ret in options:
|
|
return ret
|
|
logging.fatal("ERROR: Invalid keymap specified, please type in"
|
|
" one from the list above.")
|
|
|
|
|
|
def ask_for_timezone(args):
|
|
localtimes = ["/etc/zoneinfo/localtime", "/etc/localtime"]
|
|
zoneinfo_path = "/usr/share/zoneinfo/"
|
|
for localtime in localtimes:
|
|
if not os.path.exists(localtime):
|
|
continue
|
|
tz = ""
|
|
if os.path.exists(localtime):
|
|
tzpath = os.path.realpath(localtime)
|
|
tzpath = tzpath.rstrip()
|
|
if os.path.exists(tzpath):
|
|
try:
|
|
_, tz = tzpath.split(zoneinfo_path)
|
|
except:
|
|
pass
|
|
if tz:
|
|
logging.info("Your host timezone: " + tz)
|
|
if pmb.helpers.cli.confirm(args, "Use this timezone instead of GMT?",
|
|
default="y"):
|
|
return tz
|
|
logging.info("WARNING: Unable to determine timezone configuration on host, using GMT.")
|
|
return "GMT"
|
|
|
|
|
|
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))
|
|
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
|
|
|
|
pmb.aportgen.generate(args, "device-" + device)
|
|
pmb.aportgen.generate(args, "linux-" + device)
|
|
break
|
|
|
|
return (device, device_exists)
|
|
|
|
|
|
def ask_for_qemu_mesa_driver(args):
|
|
drivers = pmb.config.qemu_mesa_drivers
|
|
logging.info("Which mesa driver do you prefer for your Qemu device? Only"
|
|
" select something other than the default if you are having"
|
|
" graphical problems (such as glitches).")
|
|
while True:
|
|
ret = pmb.helpers.cli.ask(args, "Mesa driver", drivers,
|
|
args.qemu_mesa_driver)
|
|
if ret in drivers:
|
|
return ret
|
|
logging.fatal("ERROR: Please specify a driver from the list. To change"
|
|
" it, see qemu_mesa_drivers in pmb/config/__init__.py.")
|
|
|
|
|
|
def frontend(args):
|
|
cfg = pmb.config.load(args)
|
|
|
|
# Device
|
|
cfg["pmbootstrap"]["device"], device_exists = ask_for_device(args)
|
|
|
|
# Qemu mesa driver
|
|
if cfg["pmbootstrap"]["device"].startswith("qemu-"):
|
|
cfg["pmbootstrap"]["qemu_mesa_driver"] = ask_for_qemu_mesa_driver(args)
|
|
|
|
# Device keymap
|
|
if device_exists:
|
|
cfg["pmbootstrap"]["keymap"] = ask_for_keymaps(args, device=cfg["pmbootstrap"]["device"])
|
|
|
|
# Username
|
|
cfg["pmbootstrap"]["user"] = pmb.helpers.cli.ask(args, "Username", None,
|
|
args.user, False,
|
|
"[a-z_][a-z0-9_-]*")
|
|
# UI and work folder
|
|
cfg["pmbootstrap"]["ui"] = ask_for_ui(args)
|
|
cfg["pmbootstrap"]["work"] = ask_for_work_path(args)
|
|
|
|
# Parallel job count
|
|
logging.info("How many jobs should run parallel on this machine, when"
|
|
" compiling?")
|
|
cfg["pmbootstrap"]["jobs"] = pmb.helpers.cli.ask(args, "Jobs",
|
|
None, args.jobs, validation_regex="[1-9][0-9]*")
|
|
|
|
# Timestamp based rebuilds
|
|
logging.info("Rebuild packages, when the last modified timestamp changed,"
|
|
" even if the version did not change? This makes pmbootstrap"
|
|
" behave more like 'make'.")
|
|
answer = pmb.helpers.cli.confirm(args, "Timestamp based rebuilds",
|
|
default=args.timestamp_based_rebuild)
|
|
cfg["pmbootstrap"]["timestamp_based_rebuild"] = str(answer)
|
|
|
|
# Extra packages to be installed to rootfs
|
|
logging.info("Additional packages that will be installed to rootfs."
|
|
" Specify them in a comma separated list (e.g.: vim,file)"
|
|
" or \"none\"")
|
|
cfg["pmbootstrap"]["extra_packages"] = pmb.helpers.cli.ask(args, "Extra packages",
|
|
None, args.extra_packages,
|
|
validation_regex="^(|[-.+\w\s]+(?:,[-.+\w\s]*)*)$")
|
|
|
|
# Configure timezone info
|
|
cfg["pmbootstrap"]["timezone"] = ask_for_timezone(args)
|
|
|
|
# Do not save aports location to config file
|
|
del cfg["pmbootstrap"]["aports"]
|
|
|
|
# Save config
|
|
pmb.config.save(args, cfg)
|
|
|
|
# Zap existing chroots
|
|
setattr(args, "work", cfg["pmbootstrap"]["work"])
|
|
if (device_exists and
|
|
len(glob.glob(args.work + "/chroot_*")) and
|
|
pmb.helpers.cli.confirm(args, "Zap existing chroots to apply configuration?", default=True)):
|
|
setattr(args, "deviceinfo", pmb.parse.deviceinfo(args, device=cfg["pmbootstrap"]["device"]))
|
|
# Do not zap any existing packages or cache_http directories
|
|
pmb.chroot.zap(args, confirm=False)
|
|
|
|
logging.info(
|
|
"WARNING: The applications in the chroots do not get updated automatically.")
|
|
logging.info("Run 'pmbootstrap zap' to delete all chroots once a day before"
|
|
" working with pmbootstrap!")
|
|
logging.info("It only takes a few seconds, and all packages are cached.")
|
|
|
|
logging.info("Done!")
|