pmbootstrap init: Ask for hostname, default: device name (#1327)

* Save "" (empty string) in the user's config as hostname if the user
  let it default to the name of the device. That way, when the device
  gets changed, the user won't get the old device's name as hostname
  by accident.
* Add a test case
This commit is contained in:
Daniele Debernardi 2018-03-17 19:41:41 +01:00 committed by Oliver Smith
parent 16af241e5e
commit 147082ec58
5 changed files with 95 additions and 3 deletions

View File

@ -45,8 +45,8 @@ apk_tools_static_min_version = "2.9.0-r0"
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",
config_keys = ["ccache_size", "device", "extra_packages", "hostname", "jobs",
"keymap", "nonfree_firmware", "nonfree_userland",
"qemu_native_mesa_driver", "timezone", "ui", "user", "work"]
# Config file/commandline default values
@ -62,6 +62,7 @@ defaults = {
"config": os.path.expanduser("~") + "/.config/pmbootstrap.cfg",
"device": "samsung-i9100",
"extra_packages": "none",
"hostname": "",
# A higher value is typically desired, but this can lead to VERY long open
# times on slower devices due to host systems being MUCH faster than the
# target device: <https://github.com/postmarketOS/pmbootstrap/issues/429>

View File

@ -240,6 +240,18 @@ def ask_for_build_options(args, cfg):
cfg["pmbootstrap"]["ccache_size"] = answer
def ask_for_hostname(args, device):
while True:
ret = pmb.helpers.cli.ask(args, "Device hostname (short form, e.g. 'foo')",
None, (args.hostname or device), True)
if not pmb.helpers.other.validate_hostname(ret):
continue
# Don't store device name in user's config (gets replaced in install)
if ret == device:
return ""
return ret
def frontend(args):
cfg = pmb.config.load(args)
@ -281,6 +293,9 @@ def frontend(args):
# Configure timezone info
cfg["pmbootstrap"]["timezone"] = ask_for_timezone(args)
# Hostname
cfg["pmbootstrap"]["hostname"] = ask_for_hostname(args, device)
# Save config
pmb.config.save(args, cfg)

View File

@ -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 <http://www.gnu.org/licenses/>.
"""
import os
import logging
import os
import re
import pmb.chroot
import pmb.config
import pmb.helpers.run
@ -127,3 +128,26 @@ def migrate_work_folder(args):
" folder manually ('sudo rm -rf " + args.work +
"') and start over with 'pmbootstrap init'. All your"
" binary packages will be lost.")
def validate_hostname(hostname):
"""
Check whether the string is a valid hostname, according to
<http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names>
"""
# Check length
if len(hostname) > 63:
logging.fatal("ERROR: Hostname '" + hostname + "' is too long.")
return False
# Check that it only contains valid chars
if not re.match("^[0-9a-z-]*$", hostname):
logging.fatal("ERROR: Hostname must only contain letters (a-z),"
" digits (0-9) or minus signs (-)")
return False
# Check that doesn't begin or end with a minus sign
if hostname[:1] == "-" or hostname[-1:] == "-":
logging.fatal("ERROR: Hostname must not begin or end with a minus sign")
return False
return True

View File

@ -18,7 +18,9 @@ along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
"""
import logging
import os
import re
import glob
import shlex
import pmb.chroot
import pmb.chroot.apk
@ -234,6 +236,28 @@ def setup_keymap(args):
logging.info("NOTE: No valid keymap specified for device")
def setup_hostname(args):
"""
Set the hostname and update localhost address in /etc/hosts
"""
# Default to device name
hostname = args.hostname
if not hostname:
hostname = args.device
if not pmb.helpers.other.validate_hostname(hostname):
raise RuntimeError("Hostname '" + hostname + "' is not valid, please"
" run 'pmbootstrap init' to configure it.")
# Update /etc/hosts
suffix = "rootfs_" + args.device
pmb.chroot.root(args, ["sh", "-c", "echo " + shlex.quote(hostname) +
" > /etc/hostname"], suffix)
regex = ("s/^127\.0\.0\.1.*/127.0.0.1\t" + re.escape(hostname) +
" localhost.localdomain localhost/")
pmb.chroot.root(args, ["sed", "-i", "-e", regex, "/etc/hosts"], suffix)
def install_system_image(args):
# Partition and fill image/sdcard
logging.info("*** (3/5) PREPARE INSTALL BLOCKDEVICE ***")
@ -377,6 +401,9 @@ def install(args):
# Set timezone
pmb.chroot.root(args, ["setup-timezone", "-z", args.timezone], suffix)
# Set the hostname as the device name
setup_hostname(args)
if args.android_recovery_zip:
install_recovery_zip(args)
else:

View File

@ -219,3 +219,28 @@ def test_questions_build_options(args, monkeypatch):
func(args, cfg)
assert cfg == {"pmbootstrap": {"jobs": "5",
"ccache_size": "2G"}}
def test_questions_hostname(args, monkeypatch):
func = pmb.config.init.ask_for_hostname
device = "test-device"
# Valid hostname
fake_answers(monkeypatch, ["valid"])
assert func(args, device) == "valid"
# Hostname too long ("aaaaa...")
fake_answers(monkeypatch, ["a" * 64, "a" * 63])
assert func(args, device) == "a" * 63
# Fail the regex
fake_answers(monkeypatch, ["$invalid", "valid"])
assert func(args, device) == "valid"
# Begins or ends with minus
fake_answers(monkeypatch, ["-invalid", "invalid-", "valid"])
assert func(args, device) == "valid"
# Device name: empty string
fake_answers(monkeypatch, [device])
assert func(args, device) == ""