Implement command line option and configuration handling

This commit is contained in:
László Valkó 2022-10-24 03:25:32 +02:00
parent 3baa75fd8c
commit a634cc5679
6 changed files with 249 additions and 0 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
*~ *~
__pycache__
archive

View file

@ -1 +1,75 @@
# Sysadmin Tools # 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
```

8
config/00defaults.yaml Normal file
View file

@ -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

140
configuration.py Normal file
View file

@ -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 + """ [<options>] <command> [<options>]
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)

19
ktool Executable file
View file

@ -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)

6
progver.py Normal file
View file

@ -0,0 +1,6 @@
# -*- coding: UTF-8 -*-
import sys
this = sys.modules[__name__]
this.VERSION = "0.01"