181 lines
6.3 KiB
Python
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
|