[molecule] add preliminary support for template files preprocessor
Implement "%import /path" preprocessor statement support inside .spec files
This commit is contained in:
@@ -1,45 +1,4 @@
|
||||
# Sabayon Linux 5 x86 GNOME Molecule remaster spec file
|
||||
# The aim of this spec file is to add arbitrary applications & misc stuff
|
||||
# to an already built ISO image via scripting (providing hooks that call
|
||||
# user-defined scripts).
|
||||
# squashfs, mkisofs needed
|
||||
|
||||
# Define an alternative execution strategy, in this case, the value must be
|
||||
# "iso_remaster"
|
||||
execution_strategy: iso_remaster
|
||||
|
||||
# pre chroot command, example, for 32bit chroots on 64bit system, you always
|
||||
# have to append "linux32" this is useful for inner_chroot_script
|
||||
prechroot: linux32
|
||||
|
||||
# Path to source ISO file (MANDATORY)
|
||||
source_iso: /sabayon/iso_images/Sabayon_5.0_G.iso
|
||||
|
||||
# Error script command, executed when something went wrong and molecule has to terminate the execution
|
||||
# environment variables exported:
|
||||
# - CHROOT_DIR: path to chroot directory, if any
|
||||
# - CDROOT_DIR: path to livecd root directory, if any
|
||||
# - SOURCE_CHROOT_DIR: path from where chroot is copied for final handling
|
||||
# error_script: /path/to/script/to/be/executed/outside/after
|
||||
|
||||
# Outer chroot script command, to be executed outside destination chroot before
|
||||
# before entering it (and before inner_chroot_script)
|
||||
# outer_chroot_script: /path/to/script/to/be/executed/outside
|
||||
|
||||
# Inner chroot script command, to be executed inside destination chroot before packing it
|
||||
# - kmerge.sh - setup kernel bins
|
||||
# inner_chroot_script: /sabayon/scripts/inner_chroot_script.sh
|
||||
|
||||
# Inner chroot script command, to be executed inside destination chroot after
|
||||
# packages installation and removal
|
||||
# inner_chroot_script_after: /sabayon/scripts/inner_chroot_script_after.sh
|
||||
|
||||
# Outer chroot script command, to be executed outside destination chroot before
|
||||
# before entering it (and AFTER inner_chroot_script)
|
||||
# outer_chroot_script_after: /path/to/script/to/be/executed/outside/after
|
||||
|
||||
# Extra mkisofs parameters, perhaps something to include/use your bootloader
|
||||
extra_mkisofs_parameters: -b isolinux/isolinux.bin -c isolinux/boot.cat
|
||||
%import half.inc
|
||||
|
||||
# Pre-ISO building script. Hook to be able to copy kernel images in place, for example
|
||||
# pre_iso_script: /sabayon/scripts/cdroot.py
|
||||
|
||||
+111
-16
@@ -77,12 +77,110 @@ class Configuration(dict):
|
||||
molecule.utils.valid_exec_check(self.get(key))
|
||||
|
||||
|
||||
class SpecPreprocessor:
|
||||
|
||||
PREFIX = "%"
|
||||
class PreprocessorError(Exception):
|
||||
""" Error while preprocessing file """
|
||||
|
||||
def __init__(self, spec_path):
|
||||
self.__expanders = {}
|
||||
self.__builtin_expanders = {}
|
||||
self._spec_path = spec_path
|
||||
self._add_builtin_expanders()
|
||||
|
||||
def add_expander(self, statement, expander_callback):
|
||||
"""
|
||||
Add Preprocessor expander.
|
||||
|
||||
@param statement: statement to expand
|
||||
@type statement: string
|
||||
@param expand_callback: one argument callback that is used to expand
|
||||
given line (line is raw format). Line is already pre-parsed and
|
||||
contains a valid preprocessor statement that callback can handle.
|
||||
Preprocessor callback should raise SpecPreprocessor.PreprocessorError
|
||||
if line is malformed.
|
||||
@type expander_callback: callable
|
||||
@raise KeyError: if expander is already available
|
||||
@return: a raw string (containing \n and whatever)
|
||||
@rtype: string
|
||||
"""
|
||||
return self._add_expander(statement, expander_callback, builtin = False)
|
||||
|
||||
def _add_expander(self, statement, expander_callback, builtin = False):
|
||||
obj = self.__expanders
|
||||
if builtin:
|
||||
obj = self.__builtin_expanders
|
||||
if statement in obj:
|
||||
raise KeyError("expander %s already provided" % (statement,))
|
||||
obj[SpecPreprocessor.PREFIX + statement] = \
|
||||
expander_callback
|
||||
|
||||
def _add_builtin_expanders(self):
|
||||
# import statement
|
||||
self._add_expander("import", self._import_expander, builtin = True)
|
||||
|
||||
def _import_expander(self, line):
|
||||
|
||||
rest_line = line.split(" ", 1)[1].strip()
|
||||
if not rest_line:
|
||||
return line
|
||||
|
||||
if rest_line.startswith(os.path.sep):
|
||||
# absolute path
|
||||
path = rest_line
|
||||
else:
|
||||
path = os.path.join(os.path.dirname(self._spec_path),
|
||||
rest_line)
|
||||
if not (os.path.isfile(path) and os.access(path, os.R_OK)):
|
||||
raise SpecPreprocessor.PreprocessorError(
|
||||
"invalid preprocessor line: %s" % (line,))
|
||||
|
||||
with open(path, "r") as spec_f:
|
||||
lines = ''
|
||||
for line in spec_f.xreadlines():
|
||||
# call recursively
|
||||
split_line = line.split(" ", 1)
|
||||
if split_line:
|
||||
expander = self.__builtin_expanders.get(split_line[0])
|
||||
if expander is not None:
|
||||
line = expander(line)
|
||||
lines += line
|
||||
|
||||
return lines
|
||||
|
||||
def parse(self):
|
||||
|
||||
content = []
|
||||
with open(self._spec_path, "r") as spec_f:
|
||||
for line in spec_f.xreadlines():
|
||||
split_line = line.split(" ", 1)
|
||||
if split_line:
|
||||
expander = self.__builtin_expanders.get(split_line[0])
|
||||
if expander is not None:
|
||||
line = expander(line)
|
||||
content.append(line)
|
||||
|
||||
final_content = []
|
||||
for line in content:
|
||||
split_line = line.split(" ", 1)
|
||||
if split_line:
|
||||
expander = self.__expanders.get(split_line[0])
|
||||
if expander is not None:
|
||||
line = expander(line)
|
||||
final_content.append(line)
|
||||
|
||||
final_content = (''.join(final_content)).split("\n")
|
||||
|
||||
return final_content
|
||||
|
||||
|
||||
class SpecParser:
|
||||
|
||||
def __init__(self, filepath):
|
||||
|
||||
self.filepath = filepath[:]
|
||||
self._preprocessor = SpecPreprocessor(self.filepath)
|
||||
|
||||
# FIXME: kept for backward .spec files compatibility where
|
||||
# execution_strategy argument is not set
|
||||
@@ -95,7 +193,6 @@ class SpecParser:
|
||||
|
||||
from molecule.specs.factory import PluginFactory
|
||||
spec_plugins = PluginFactory.get_spec_plugins()
|
||||
print spec_plugins
|
||||
|
||||
plugin = spec_plugins.get(execution_strategy)
|
||||
if plugin is None:
|
||||
@@ -109,7 +206,7 @@ class SpecParser:
|
||||
|
||||
|
||||
def parse_execution_strategy(self):
|
||||
data = self.__generic_parser(self.filepath)
|
||||
data = self._generic_parser()
|
||||
exc_str = GenericSpec.EXECUTION_STRATEGY_KEY
|
||||
for line in data:
|
||||
if not line.startswith(exc_str):
|
||||
@@ -132,7 +229,7 @@ class SpecParser:
|
||||
|
||||
def parse(self):
|
||||
mydict = {}
|
||||
data = self.__generic_parser(self.filepath)
|
||||
data = self._generic_parser()
|
||||
# compact lines properly
|
||||
old_key = None
|
||||
for line in data:
|
||||
@@ -175,16 +272,14 @@ class SpecParser:
|
||||
" file is incomplete!" % (self.filepath,param,)
|
||||
)
|
||||
|
||||
def __generic_parser(self, filepath):
|
||||
with open(filepath,"r") as f:
|
||||
data = []
|
||||
content = f.readlines()
|
||||
f.close()
|
||||
# filter comments and white lines
|
||||
content = [x.strip().rsplit("#", 1)[0].strip() for x in content if \
|
||||
not x.startswith("#") and x.strip()]
|
||||
for line in content:
|
||||
if line in data:
|
||||
continue
|
||||
data.append(line)
|
||||
return data
|
||||
def _generic_parser(self):
|
||||
data = []
|
||||
content = self._preprocessor.parse()
|
||||
# filter comments and white lines
|
||||
content = [x.strip().rsplit("#", 1)[0].strip() for x in content if \
|
||||
not x.startswith("#") and x.strip()]
|
||||
for line in content:
|
||||
if line in data:
|
||||
continue
|
||||
data.append(line)
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user