bootbox/builder/ipxe.py

181 lines
6.3 KiB
Python

import io
import os
import logging
import pathlib
import re
import shutil
##
import patch_ng
##
from . import config
from . import constants
from . import upstream
from . import compile
_log = logging.getLogger()
class _Opt(object):
switchtype = None
def __init__(self, opt_xml, *args, **kwargs):
self.xml = opt_xml
self.flags = [i.text for i in self.xml.findall('opt')]
class _Enable(_Opt):
switchtype = 'enable'
def __init__(self, opt_xml, *args, **kwargs):
super().__init__(opt_xml, *args, **kwargs)
self.re = re.compile((r'^\s*(//#define|#undef)\s+'
r'(?P<optname>{0})'
r'(?P<comment>\s+/\*.*)?\s*$').format('|'.join(self.flags)))
class _Disable(_Opt):
switchtype = 'disable'
def __init__(self, opt_xml, *args, **kwargs):
super().__init__(opt_xml, *args, **kwargs)
self.re = re.compile((r'^(#define|//#undef)\s+'
r'(?P<optname>{0})'
r'(?P<comment>\s+/\*.*)?\s*$').format('|'.join(self.flags)))
class _MonkeyPatchFile(object):
def __init__(self, builddir, opts_xml):
self.xml = opts_xml
self.fpath = os.path.join(os.path.abspath(os.path.expanduser(builddir)),
self.xml.attrib.get('file'))
self.opts = []
if not os.path.isfile(self.fpath):
_log.error('File {0} was due to be monkeypatched but is not found.'.format(self.fpath))
raise FileNotFoundError('File does not exist')
with open(self.fpath, 'r') as fh:
self.buf = io.StringIO(fh.read())
self.buf.seek(0, 0)
self.lines = self.buf.read().splitlines()
self.buf.seek(0, 0)
self._get_opts()
def _get_opts(self):
for opt in self.xml.xpath('./enable|./disable'):
if opt.tag == 'enable':
self.opts.append(_Enable(opt))
else:
self.opts.append(_Disable(opt))
return (None)
def patch(self):
for opt in self.opts:
for idx, line in enumerate(self.lines[:]):
opt_re = opt.re.search(line)
if opt_re:
if opt.switchtype == 'enable':
self.lines[idx] = '#define {0}{1}'.format(opt_re.group('optname'),
opt_re.group('comment'))
else:
self.lines[idx] = '#undef {0}{1}'.format(opt_re.group('optname'),
opt_re.group('comment'))
shutil.copy2(self.fpath, '{0}.orig'.format(self.fpath))
with open(self.fpath, 'w') as fh:
fh.write('\n'.join(self.lines))
fh.write('\n')
return(None)
class MonkeyPatch(object):
def __init__(self, builddir, switchopts_xml):
self.root = os.path.join(os.path.abspath(os.path.expanduser(builddir)),
os.path.abspath(os.path.expanduser(switchopts_xml.attrib.get('subDir', '.'))))
self.xml = switchopts_xml
self.files = []
self._get_files()
def _get_files(self):
for optfile in self.xml.findall('opts'):
self.files.append(_MonkeyPatchFile(self.root, optfile))
return(None)
class _PatchFile(object):
def __init__(self, patchdir, builddir, patchfile_xml):
self.xml = patchfile_xml
self.builddir = os.path.abspath(os.path.expanduser(builddir))
self.fpath = os.path.join(os.path.abspath(os.path.expanduser(patchdir)),
self.xml.text)
self.strip_level = int(self.xml.attrib.get('stripLevel', 1))
if not os.path.isfile(self.fpath):
_log.error('Patch file {0} does not exist'.format(self.fpath))
with open(self.fpath, 'r') as fh:
self.patch_raw = fh.read()
self.patch_obj = patch_ng.PatchSet(self.patch_raw)
def patch(self):
self.patch_obj.apply(strip = self.strip_level, root = self.builddir)
return(None)
class Patch(object):
def __init__(self, builddir, patch_xml):
self.root = os.path.abspath(os.path.expanduser(builddir))
self.xml = patch_xml
_patch_dir = pathlib.Path(self.xml.attrib.get('patchDir', '.'))
if not _patch_dir.is_absolute():
self.patch_dir = os.path.join(self.root, str(_patch_dir))
else:
self.patch_dir = str(_patch_dir)
self.files = []
def _get_patches(self):
for patch in self.xml.findall('patchFile'):
self.files.append(_PatchFile(self.patch_dir, self.root, patch))
return(None)
class Builder(object):
def __init__(self, cfg = None):
if not cfg:
cfg = constants.IPXE_DEFAULT_CFG
self.cfg_file = os.path.abspath(os.path.expanduser(cfg))
self.cfg = config.Config(cfg)
self.xml = self.cfg.xml
self.dest = None
self.builddir = None
self.upstream = None
self.compiler = None
self.monkeypatches = []
self.patches = []
self._get_info()
self._get_patch()
self._get_compile()
def _get_compile(self):
build_xml = self.xml.find('build')
self.compiler = compile.Compiler(self.builddir,
self.dest,
self.upstream,
self.patches,
self.monkeypatches,
build_xml)
def _get_info(self):
source_xml = self.xml.find('source')
build_xml = self.xml.find('build')
self.dest = os.path.abspath(os.path.expanduser(build_xml.find('dest').text))
self.upstream = upstream.upstream_parser(source_xml.find('upstream'))
self.builddir = self.upstream.dest
return(None)
def _get_patch(self):
for patchset in self.xml.xpath('//patchSet'):
for optswitch in patchset.findall('switchOpts'):
self.monkeypatches.append(MonkeyPatch(self.builddir, optswitch))
for patch in self.xml.xpath('//patch'):
self.patches.append(Patch(self.builddir, patch))
return(None)
def build(self):
pass