From 147082ec5821ae4bc8ca3a16fe56ae274c90a5d5 Mon Sep 17 00:00:00 2001 From: Daniele Debernardi Date: Sat, 17 Mar 2018 19:41:41 +0100 Subject: [PATCH] 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 --- pmb/config/__init__.py | 5 +++-- pmb/config/init.py | 15 +++++++++++++++ pmb/helpers/other.py | 26 +++++++++++++++++++++++++- pmb/install/_install.py | 27 +++++++++++++++++++++++++++ test/test_questions.py | 25 +++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index f7fdb3d2..fb60705b 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -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: diff --git a/pmb/config/init.py b/pmb/config/init.py index 4db7d4b6..1996e078 100644 --- a/pmb/config/init.py +++ b/pmb/config/init.py @@ -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) diff --git a/pmb/helpers/other.py b/pmb/helpers/other.py index d5ed667f..4fdf28bf 100644 --- a/pmb/helpers/other.py +++ b/pmb/helpers/other.py @@ -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 . """ -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 + + """ + # 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 diff --git a/pmb/install/_install.py b/pmb/install/_install.py index c8e9ec60..624c965f 100644 --- a/pmb/install/_install.py +++ b/pmb/install/_install.py @@ -18,7 +18,9 @@ along with pmbootstrap. If not, see . """ 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: diff --git a/test/test_questions.py b/test/test_questions.py index 685c36bf..ee3233df 100644 --- a/test/test_questions.py +++ b/test/test_questions.py @@ -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) == ""