From a634cc5679a033d0d442a1fc2a22c1e77a3b6e15 Mon Sep 17 00:00:00 2001 From: Laszlo Valko Date: Mon, 24 Oct 2022 03:25:32 +0200 Subject: [PATCH] Implement command line option and configuration handling --- .gitignore | 2 + README.md | 74 ++++++++++++++++++++++ config/00defaults.yaml | 8 +++ configuration.py | 140 +++++++++++++++++++++++++++++++++++++++++ ktool | 19 ++++++ progver.py | 6 ++ 6 files changed, 249 insertions(+) create mode 100644 config/00defaults.yaml create mode 100644 configuration.py create mode 100755 ktool create mode 100644 progver.py diff --git a/.gitignore b/.gitignore index b25c15b..bada32d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *~ +__pycache__ +archive diff --git a/README.md b/README.md index c33979c..9bb7a5e 100644 --- a/README.md +++ b/README.md @@ -1 +1,75 @@ # Sysadmin Tools + +## Steps + +### Make kernel source + +- emerge -1 +- store kernel source +- emerge unmerge + +```bash +ktool mksrc +``` + +### Prepare kernel source + +- load kernel source +- add .config +- make prepare +- store prepared kernel source + +```bash +ktool prepare +``` + +### Build kernel source package + +- emerge -1b prepared kernel source package + +```bash +ktool emergesrc +``` + +### Build kernel & modules + +- make bzimage modules +- store built kernel source +- store built kernel +- make modules_install +- store built modules + +```bash +ktool build +``` + +### Build initrd + +- load built modules +- build initrd +- store initrd + +```bash +ktool initrd +``` + +### Build ucodes + +- build ucodes +- store ucodes + +```bash +ktool mkucodes +``` + +### Install kernel + +- load ucodes +- load built kernel +- load built modules +- emerge -1K prepared kernel source package +- grub-mkconfig + +```bash +ktool install +``` diff --git a/config/00defaults.yaml b/config/00defaults.yaml new file mode 100644 index 0000000..cf7e4f3 --- /dev/null +++ b/config/00defaults.yaml @@ -0,0 +1,8 @@ +# base URL for distribution +baseurl: https://apps.karinthy.hu/gentoo/ + +# base subdirectory for distribution +distdir: distribution + +# kernel series to use (latest or x.y) +kernels: latest diff --git a/configuration.py b/configuration.py new file mode 100644 index 0000000..b9e6a20 --- /dev/null +++ b/configuration.py @@ -0,0 +1,140 @@ +# -*- coding: UTF-8 -*- + +import os +import sys +import getopt +from yaml import load, YAMLError +try: + from yaml import CSafeLoader as SafeLoader +except ImportError: + from yaml import SafeLoader +from pathlib import Path + +class Config(): + def __init__(self, scriptname, progver, commands): + scriptname = os.path.realpath(scriptname) + self.basedir = os.path.dirname(scriptname) + self.progname = os.path.basename(scriptname) + self.progver = progver + self.commands = commands + # options + self.help = False + self.version = False + self.verbose = False + self.config = "config" + self.params = {} + # command + self.cmd = None + # config params + self.config_params = {} + + def usage(self, exitcode): + usage = """Usage: """ + self.progname + """ [] [] + +Commands: +""" + for cmd, desc in self.commands: + usage += " " + cmd + (' ' if len(cmd) >= 31 else ' ' * (31-len(cmd))) + desc + "\n" + usage += """ +Options: + -h, --help Print this help + -V, --version Print version number + -c, --config dir Specify config directory to read [""" + self.config + """] + -s, --set key=value Override config parameter key=value + -v, --verbose Print verbose messages +""" + sys.stderr.write(usage) + if exitcode is not None: + sys.exit(exitcode) + + def parse(self, argv): + try: + (opt, args) = getopt.gnu_getopt(argv[1:], "hVvc:s:", [ + "help", "version", "verbose", "config=", "set=" + ]) + except getopt.GetoptError as e: + sys.stderr.write("Error: %s\n" % str(e)) + self.usage(2) + + for o, a in opt: + if o == '-h' or o == "--help": + self.help = True + elif o == '-V' or o == "--version": + self.version = True + elif o == '-v' or o == "--verbose": + self.verbose = True + elif o == '-c' or o == "--config": + if (a == ''): + sys.stderr.write("Error: option " + o + " requires a non-empty argument\n") + self.usage(2) + self.config = a + elif o == '-s' or o == "--set": + parts = a.partition('=') + if (parts[1] != '='): + sys.stderr.write("Error: option " + o + " requires argument in the format key=value\n") + self.usage(2) + if (parts[0] == ''): + sys.stderr.write("Error: option " + o + " requires argument in the format key=value; key may not be an empty string\n") + self.usage(2) + self.params[parts[0]] = parts[2] + + if self.version: + sys.stdout.write("Version: " + self.progver + "\n") + if self.help: + self.usage(None) + if self.version or self.help: + sys.exit(0) + + self.load_config() + + for c in args: + if self.cmd != None: + sys.stderr.write("Multiple commands specified: " + self.cmd + " vs " + c + "\n") + self.usage(2) + for cmd, _ in self.commands: + if c == cmd: + self.cmd = c + break + if self.cmd == None: + sys.stderr.write("Unknown command specified: " + c + "\n") + self.usage(2) + if self.cmd == None: + sys.stderr.write("Missing command\n") + self.usage(2) + + for k, v in self.params.items(): + self.config_params[k] = v + if self.verbose: + sys.stdout.write("Config parameters:\n") + for k, v in self.config_params.items(): + sys.stdout.write(" " + k + "=" + str(v) + "\n") + + def merge_config(self, src, dest): + for key, value in src.items(): + if isinstance(value, dict): + node = dest.setdefault(key, {}) + self.merge_config(value, node) + else: + dest[key] = value + return dest + + def parse_file(self, filepath): + try: + obj = load(open(filepath, 'r'), SafeLoader) + self.merge_config(obj, self.config_params) + except YAMLError as exc: + sys.stdout.write("Error: reading configuration file failed: %s" % (exc)) + + def load_config(self): + configdir = self.config if self.config.startswith('/') else self.basedir + '/' + self.config + if self.verbose: + sys.stdout.write("Reading config directory " + configdir + "\n") + if not Path(configdir).is_dir(): + sys.stderr.write("Warning: config directory " + configdir + " does not exist\n") + return + with os.scandir(configdir) as it: + for entry in it: + if not entry.name.startswith('.') and (entry.name.endswith('.yml') or entry.name.endswith('.yaml')) and entry.is_file(): + if self.verbose: + sys.stdout.write("Parsing config file " + entry.path + "\n") + self.parse_file(entry.path) diff --git a/ktool b/ktool new file mode 100755 index 0000000..1682a83 --- /dev/null +++ b/ktool @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +import os +import sys + +import progver +from configuration import Config + +config = Config(__file__, progver.VERSION, [ + ['mksrc', 'Make kernel source'], + ['prepare', 'Prepare kernel source'], + ['emergesrc', 'Build kernel source package'], + ['build', 'Build kernel & modules'], + ['initrd', 'Build initrd'], + ['mkucodes', 'Build ucodes'], + ['install', 'Install kernel'] +]) +config.parse(sys.argv) diff --git a/progver.py b/progver.py new file mode 100644 index 0000000..4bbdff8 --- /dev/null +++ b/progver.py @@ -0,0 +1,6 @@ +# -*- coding: UTF-8 -*- + +import sys + +this = sys.modules[__name__] +this.VERSION = "0.01"