checking in before i change a regex pattern. this currently will grab commented out defaults, but we don't want that since it complicates things - so we hardcode in shipped defaults.
This commit is contained in:
parent
7f3b8b98aa
commit
c22b473b49
@ -1 +1,2 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
# Remember to genfstab!
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
# We use a temporary venv to ensure we have all the external libraries we need.
|
# This can set up an environment at runtime.
|
||||||
# This removes the necessity of extra libs at runtime. If you're in an environment that doesn't have access to PyPI/pip,
|
# This removes the necessity of extra libs to be installed persistently.
|
||||||
# you'll need to customize the install host (typically the live CD/live USB) to have them installed as system packages.
|
# However, it is recommended that you install all dependencies in the system itself, because some aren't available
|
||||||
|
# through pip/PyPi.
|
||||||
# Before you hoot and holler about this, Let's Encrypt's certbot-auto does the same thing.
|
# Before you hoot and holler about this, Let's Encrypt's certbot-auto does the same thing.
|
||||||
# Except I segregate it out even further; I don't even install pip into the system python.
|
# Except I segregate it out even further; I don't even install pip into the system python.
|
||||||
|
|
||||||
import ensurepip
|
import ensurepip
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@ -14,6 +16,10 @@ import venv
|
|||||||
##
|
##
|
||||||
import aif.constants_fallback
|
import aif.constants_fallback
|
||||||
|
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class EnvBuilder(object):
|
class EnvBuilder(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.vdir = tempfile.mkdtemp(prefix = '.aif_', suffix = '_VENV')
|
self.vdir = tempfile.mkdtemp(prefix = '.aif_', suffix = '_VENV')
|
||||||
@ -30,11 +36,20 @@ class EnvBuilder(object):
|
|||||||
('import site; '
|
('import site; '
|
||||||
'import json; '
|
'import json; '
|
||||||
'print(json.dumps(site.getsitepackages(), indent = 4))')],
|
'print(json.dumps(site.getsitepackages(), indent = 4))')],
|
||||||
stdout = subprocess.PIPE)
|
stdout = subprocess.PIPE,
|
||||||
|
stderr = subprocess.PIPE)
|
||||||
|
_logger.info('Executed: {0}'.format(' '.join(moddir_raw.args)))
|
||||||
|
if moddir_raw.returncode != 0:
|
||||||
|
_logger.warning('Command returned non-zero status')
|
||||||
|
_logger.debug('Exit status: {0}'.format(str(moddir_raw.returncode)))
|
||||||
|
for a in ('stdout', 'stderr'):
|
||||||
|
x = getattr(moddir_raw, a)
|
||||||
|
if x:
|
||||||
|
_logger.debug('{0}: {1}'.format(a.upper(), x.decode('utf-8').strip()))
|
||||||
|
raise RuntimeError('Failed to establish environment successfully')
|
||||||
self.modulesdir = json.loads(moddir_raw.stdout.decode('utf-8'))[0]
|
self.modulesdir = json.loads(moddir_raw.stdout.decode('utf-8'))[0]
|
||||||
# This is SO. DUMB. WHY DO I HAVE TO CALL PIP FROM A SHELL. IT'S WRITTEN IN PYTHON.
|
# This is SO. DUMB. WHY DO I HAVE TO CALL PIP FROM A SHELL. IT'S WRITTEN IN PYTHON.
|
||||||
# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program
|
# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program
|
||||||
# TODO: logging
|
|
||||||
for m in aif.constants_fallback.EXTERNAL_DEPS:
|
for m in aif.constants_fallback.EXTERNAL_DEPS:
|
||||||
pip_cmd = [os.path.join(self.vdir,
|
pip_cmd = [os.path.join(self.vdir,
|
||||||
'bin',
|
'bin',
|
||||||
@ -44,6 +59,15 @@ class EnvBuilder(object):
|
|||||||
'install',
|
'install',
|
||||||
'--disable-pip-version-check',
|
'--disable-pip-version-check',
|
||||||
m]
|
m]
|
||||||
subprocess.run(pip_cmd)
|
cmd = subprocess.run(pip_cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||||
|
_logger.info('Executed: {0}'.format(' '.join(cmd.args)))
|
||||||
|
if cmd.returncode != 0:
|
||||||
|
_logger.warning('Command returned non-zero status')
|
||||||
|
_logger.debug('Exit status: {0}'.format(str(cmd.returncode)))
|
||||||
|
for a in ('stdout', 'stderr'):
|
||||||
|
x = getattr(cmd, a)
|
||||||
|
if x:
|
||||||
|
_logger.debug('{0}: {1}'.format(a.upper(), x.decode('utf-8').strip()))
|
||||||
|
raise RuntimeError('Failed to install module successfully')
|
||||||
# And now make it available to other components.
|
# And now make it available to other components.
|
||||||
sys.path.insert(1, self.modulesdir)
|
sys.path.insert(1, self.modulesdir)
|
||||||
|
@ -37,7 +37,7 @@ class Connection(_common.BaseConnection):
|
|||||||
self.device = _common.getDefIface(self.connection_type)
|
self.device = _common.getDefIface(self.connection_type)
|
||||||
self.desc = ('A {0} profile for {1} (generated by AIF-NG)').format(self.connection_type,
|
self.desc = ('A {0} profile for {1} (generated by AIF-NG)').format(self.connection_type,
|
||||||
self.device)
|
self.device)
|
||||||
self._cfg = configparser.ConfigParser()
|
self._cfg = configparser.ConfigParser(allow_no_value = True, interpolation = None)
|
||||||
self._cfg.optionxform = str
|
self._cfg.optionxform = str
|
||||||
# configparser *requires* sections. netctl doesn't use them. We strip it when we write.
|
# configparser *requires* sections. netctl doesn't use them. We strip it when we write.
|
||||||
self._cfg['BASE'] = {'Description': self.desc,
|
self._cfg['BASE'] = {'Description': self.desc,
|
||||||
@ -130,7 +130,7 @@ class Connection(_common.BaseConnection):
|
|||||||
fulld = os.path.join(root, d)
|
fulld = os.path.join(root, d)
|
||||||
os.chmod(fulld, 0o0755)
|
os.chmod(fulld, 0o0755)
|
||||||
os.chown(fulld, 0, 0)
|
os.chown(fulld, 0, 0)
|
||||||
systemd_cfg = configparser.ConfigParser()
|
systemd_cfg = configparser.ConfigParser(allow_no_value = True, interpolation = None)
|
||||||
systemd_cfg.optionxform = str
|
systemd_cfg.optionxform = str
|
||||||
systemd_cfg['Unit'] = {'Description': self.desc,
|
systemd_cfg['Unit'] = {'Description': self.desc,
|
||||||
'BindsTo': 'sys-subsystem-net-devices-{0}.device'.format(self.device),
|
'BindsTo': 'sys-subsystem-net-devices-{0}.device'.format(self.device),
|
||||||
|
@ -32,7 +32,7 @@ class Connection(_common.BaseConnection):
|
|||||||
_logger.info('Building config.')
|
_logger.info('Building config.')
|
||||||
if self.device == 'auto':
|
if self.device == 'auto':
|
||||||
self.device = _common.getDefIface(self.connection_type)
|
self.device = _common.getDefIface(self.connection_type)
|
||||||
self._cfg = configparser.ConfigParser()
|
self._cfg = configparser.ConfigParser(allow_no_value = True, interpolation = None)
|
||||||
self._cfg.optionxform = str
|
self._cfg.optionxform = str
|
||||||
self._cfg['connection'] = {'id': self.id,
|
self._cfg['connection'] = {'id': self.id,
|
||||||
'uuid': self.uuid,
|
'uuid': self.uuid,
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
# We can manually bootstrap and alter pacman's keyring. But check the bootstrap tarball; we might not need to.
|
|
||||||
# TODO.
|
|
||||||
|
|
||||||
import os
|
|
||||||
##
|
|
||||||
import gpg
|
|
68
aif/pacman/__init__.py
Normal file
68
aif/pacman/__init__.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# We can manually bootstrap and alter pacman's keyring. But check the bootstrap tarball; we might not need to.
|
||||||
|
# TODO.
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
##
|
||||||
|
import pyalpm
|
||||||
|
import gpg
|
||||||
|
##
|
||||||
|
from . import _common
|
||||||
|
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
_skipconfline_re = re.compile(r'^[ \t]*#([ \t]+.*)?$')
|
||||||
|
|
||||||
|
|
||||||
|
class PackageManager(object):
|
||||||
|
def __init__(self, chroot_base):
|
||||||
|
self.chroot_base = chroot_base
|
||||||
|
self.pacman_dir = os.path.join(self.chroot_base, 'var', 'lib', 'pacman')
|
||||||
|
self.configfile = os.path.join(self.chroot_base, 'etc', 'pacman.conf')
|
||||||
|
self.config = None
|
||||||
|
self._parseConf()
|
||||||
|
|
||||||
|
def _parseConf(self):
|
||||||
|
_cf = []
|
||||||
|
with open(self.configfile, 'r') as fh:
|
||||||
|
for line in fh.read().splitlines():
|
||||||
|
if _skipconfline_re.search(line) or line.strip() == '':
|
||||||
|
continue
|
||||||
|
_cf.append(re.sub(r'^#', '', line))
|
||||||
|
self.config = configparser.ConfigParser(allow_no_value = True,
|
||||||
|
interpolation = None,
|
||||||
|
strict = False,
|
||||||
|
dict_type = _common.MultiOrderedDict)
|
||||||
|
self.config.optionxform = str
|
||||||
|
self.config.read_string('\n'.join(_cf))
|
||||||
|
self.opts = {'Architecture': 'auto',
|
||||||
|
'CacheDir': '/var/cache/pacman/pkg/',
|
||||||
|
'CheckSpace': None,
|
||||||
|
'CleanMethod': 'KeepInstalled',
|
||||||
|
# 'Color': None,
|
||||||
|
'DBPath': '/var/lib/pacman/',
|
||||||
|
'GPGDir': '/etc/pacman.d/gnupg/',
|
||||||
|
'HoldPkg': 'pacman glibc',
|
||||||
|
'HookDir': '/etc/pacman.d/hooks/',
|
||||||
|
'IgnoreGroup': '',
|
||||||
|
'IgnorePkg': '',
|
||||||
|
'LocalFileSigLevel': 'Optional',
|
||||||
|
'LogFile': '/var/log/pacman.log',
|
||||||
|
'NoExtract': '',
|
||||||
|
'NoUpgrade': '',
|
||||||
|
'RemoteFileSigLevel': 'Required',
|
||||||
|
'RootDir': '/',
|
||||||
|
'SigLevel': 'Required DatabaseOptional',
|
||||||
|
# 'TotalDownload': None,
|
||||||
|
# 'UseSyslog': None,
|
||||||
|
# 'VerbosePkgLists': None,
|
||||||
|
'XferCommand': '/usr/bin/curl -L -C - -f -o %o %u'
|
||||||
|
}
|
||||||
|
self.distro_repos = ['']
|
||||||
|
_opts = dict(self.config.items('options'))
|
||||||
|
self.opts.update(_opts)
|
||||||
|
self.config.remove_section('options')
|
19
aif/pacman/_common.py
Normal file
19
aif/pacman/_common.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import configparser
|
||||||
|
import logging
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
|
_logger = logging.getLogger('pacman:_common')
|
||||||
|
|
||||||
|
|
||||||
|
class MultiOrderedDict(OrderedDict):
|
||||||
|
# Thanks, dude: https://stackoverflow.com/a/38286559/733214
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if key in self:
|
||||||
|
if isinstance(value, list):
|
||||||
|
self[key].extend(value)
|
||||||
|
return(None)
|
||||||
|
elif isinstance(value, str):
|
||||||
|
if len(self[key]) > 1:
|
||||||
|
return(None)
|
||||||
|
super(MultiOrderedDict, self).__setitem__(key, value)
|
@ -17,8 +17,8 @@ class Console(object):
|
|||||||
def __init__(self, chroot_base, console_xml):
|
def __init__(self, chroot_base, console_xml):
|
||||||
self.xml = console_xml
|
self.xml = console_xml
|
||||||
self.chroot_base = chroot_base
|
self.chroot_base = chroot_base
|
||||||
self._cfg = configparser.ConfigParser()
|
self._cfg = configparser.ConfigParser(allow_no_value = True, interpolation = None)
|
||||||
self._cfg.optionxform(str)
|
self._cfg.optionxform = str
|
||||||
self.keyboard = Keyboard(self.xml.find('keyboard'))
|
self.keyboard = Keyboard(self.xml.find('keyboard'))
|
||||||
self.font = Font(self.xml.find('text'))
|
self.font = Font(self.xml.find('text'))
|
||||||
self._cfg['BASE'] = {}
|
self._cfg['BASE'] = {}
|
||||||
|
@ -23,7 +23,7 @@ class Locale(object):
|
|||||||
self.syslocales = {}
|
self.syslocales = {}
|
||||||
self.userlocales = []
|
self.userlocales = []
|
||||||
self.rawlocales = None
|
self.rawlocales = None
|
||||||
self._localevars = configparser.ConfigParser()
|
self._localevars = configparser.ConfigParser(allow_no_value = True, interpolation = None)
|
||||||
self._localevars.optionxform = str
|
self._localevars.optionxform = str
|
||||||
self._localevars['BASE'] = {}
|
self._localevars['BASE'] = {}
|
||||||
self._initVars()
|
self._initVars()
|
||||||
|
Loading…
Reference in New Issue
Block a user