133 lines
5.3 KiB
Python
133 lines
5.3 KiB
Python
import os
|
|
import json
|
|
import sys
|
|
import argparse
|
|
|
|
from gentooimgr import LOG
|
|
import gentooimgr.configs
|
|
import multiprocessing
|
|
|
|
# A day in seconds:
|
|
DAY_IN_SECONDS = 60*60*24
|
|
# days until the iso is old
|
|
DAYS = 1
|
|
# Define threads to compile packages with
|
|
THREADS = multiprocessing.cpu_count()
|
|
# URL to latest image text file, defaults to amd64. This is parsed to find latest iso to download
|
|
ARCHITECTURE = "amd64"
|
|
GENTOO_BASE_ISO_URL = f"https://distfiles.gentoo.org/releases/{ARCHITECTURE}/autobuilds/current-install-{ARCHITECTURE}-minimal/"
|
|
GENTOO_BASE_STAGE_OPENRC_URL = f"https://distfiles.gentoo.org/releases/{ARCHITECTURE}/autobuilds/current-stage3-{ARCHITECTURE}-openrc/"
|
|
GENTOO_BASE_STAGE_SYSTEMD_URL = f"https://distfiles.gentoo.org/releases/{ARCHITECTURE}/autobuilds/current-stage3-{ARCHITECTURE}-systemd/"
|
|
GENTOO_LATEST_ISO_FILE = f"latest-install-{ARCHITECTURE}-minimal.txt"
|
|
GENTOO_LATEST_STAGE_OPENRC_FILE = f"latest-stage3-{ARCHITECTURE}-openrc.txt"
|
|
GENTOO_LATEST_STAGE_SYSTEMD_FILE = f"latest-stage3-{ARCHITECTURE}-systemd.txt"
|
|
GENTOO_PORTAGE_FILE = "http://distfiles.gentoo.org/snapshots/portage-latest.tar.xz" # No architecture, no txt files to determine latest.
|
|
|
|
GENTOO_MOUNT = "/mnt/gentoo"
|
|
GENTOO_IMG_NAME = "gentoo.qcow2"
|
|
|
|
GENTOO_FILE_HASH_RE = r"^Hash\: ([\w]*)$"
|
|
GENTOO_FILE_ISO_RE = r"^(install-[\w\-_\.]*.iso) ([\d]*)"
|
|
GENTOO_FILE_ISO_HASH_RE = r"^([\w]*) (install-[\w\-_\.]*.iso)$"
|
|
GENTOO_FILE_STAGE3_RE = r"^(stage3-[\w\-_\.]*.tar.*) ([\d]*)"
|
|
GENTOO_FILE_STAGE3_HASH_RE = r"^([\w]*) (stage3-[\w\-_\.]*.tar.*)$"
|
|
# TODO: Repo regex to replace attributes, use function to do so as find key will change.
|
|
|
|
def replace_repos_conf(key, value):
|
|
pass
|
|
|
|
CLOUD_MODULES = [
|
|
"iscsi_tcp"
|
|
]
|
|
|
|
def load_config(path):
|
|
assert path, "load config called with nothing"
|
|
if os.path.exists(path):
|
|
with open(path, 'r') as f:
|
|
try:
|
|
return json.loads(f.read())
|
|
except Exception as e:
|
|
LOG.error(f"ERROR loading {path}")
|
|
raise
|
|
return {}
|
|
|
|
def load_default_config(config_name):
|
|
"""This is called when a --config option is set. --kernel options update the resulting config, whether
|
|
it be 'base' or other.
|
|
If user is supplying their own configuration, this is not called.
|
|
"""
|
|
name, ext = os.path.splitext(config_name)
|
|
if not name in gentooimgr.configs.KNOWN_CONFIGS:
|
|
return {}
|
|
|
|
json_file = os.path.join(gentooimgr.configs.CONFIG_DIR, config_name)
|
|
ret = {}
|
|
with open(json_file, 'r') as f:
|
|
try:
|
|
ret = json.loads(f.read())
|
|
except Exception as e:
|
|
LOG.error(f"loading {json_file} {e}")
|
|
return ret
|
|
|
|
def inherit_config(config: dict) -> dict:
|
|
"""Returns the json file that the inherit key specifies; will recursively update if inherit values are set.
|
|
"""
|
|
configuration = load_default_config(config.get("inherit"))
|
|
if not configuration:
|
|
configuration = load_config(config.get("inherit"))
|
|
|
|
if not configuration:
|
|
sys.stderr.write(f"\tWW: Warning: Inherited configuration {config.get('inherit')} is not found.\n")
|
|
return {}
|
|
|
|
if configuration.get("inherit"):
|
|
configuration.update(inherit_config(configuration.get("inherit")))
|
|
|
|
return configuration
|
|
|
|
def determine_config(args: argparse.Namespace) -> dict:
|
|
"""Check argparser options and return the most valid configuration
|
|
|
|
The "package" key/value object overrides everything that is set, it does not update() them.
|
|
If you override "base" package set, it's exactly what you set. It makes more sense to do it this way.
|
|
For example, if you have a dist kernel config, you don't want the base.json to update and include all
|
|
non-dist kernel options as it would add a lot of used space for unused functionality.
|
|
|
|
The package set is only overridden in the top level json configuration file though;
|
|
If you have multiple inherits, those package sets will be combined before the parent package set overrides
|
|
with the keys that are set.
|
|
|
|
If you have base.json and base2.json that contain multiple layers of "base" packages, ie: base: ['foo'] and base2: ['bar']
|
|
then you will have in yours.json: packages { base: ['foo', 'bar'] } and unless you set "base", that is what you'll get.
|
|
|
|
|
|
If you check `status` action, it will flatten all configurations into one, so the "inherit" key will always be null.
|
|
|
|
:Returns:
|
|
- configuration from json to dict
|
|
"""
|
|
|
|
# Check custom configuration
|
|
configuration = load_default_config(args.config or 'base.json')
|
|
if not configuration and args.config:
|
|
configuration = load_config(args.config)
|
|
if not configuration:
|
|
LOG.error(f"\tWW: Warning: Configuration {args.config} is empty\n")
|
|
else:
|
|
if configuration.get("inherit"):
|
|
# newpkgs = configuration.get("packages", {})
|
|
inherited = inherit_config(configuration)
|
|
new_packages = configuration.get("packages", {})
|
|
old_packages = inherited.get("packages", {})
|
|
inherited.update(configuration)
|
|
# Set back old package dict and then update only what is set in new:
|
|
inherited['packages'] = old_packages
|
|
for key, pkgs in new_packages.items():
|
|
if pkgs:
|
|
inherited['packages'][key] = pkgs
|
|
|
|
return inherited
|
|
|
|
return configuration
|
|
|