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{0})' r'(?P\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{0})' r'(?P\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