Move the run part of LoraxTemplateRunner into new TemplateRunner class
This will make it easier to add a new subclass that only handles installpkg for use with livemedia-creator and lorax-composer iso creation. Related: rhbz#1673744
This commit is contained in:
		
							parent
							
								
									8c94ee6ba1
								
							
						
					
					
						commit
						51180ad407
					
				| @ -103,19 +103,13 @@ def rexists(pathname, root=""): | |||||||
|         return True |         return True | ||||||
|     return False |     return False | ||||||
| 
 | 
 | ||||||
| # TODO: operate inside an actual chroot for safety? Not that RPM bothers.. | class TemplateRunner(object): | ||||||
| class LoraxTemplateRunner(object): |  | ||||||
|     ''' |     ''' | ||||||
|     This class parses and executes Lorax templates. Sample usage: |     This class parses and executes Lorax templates. Sample usage: | ||||||
| 
 | 
 | ||||||
|       # install a bunch of packages |       # install a bunch of packages | ||||||
|       runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) |       runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) | ||||||
|       runner.run("install-packages.ltmpl") |       runner.run("install-packages.ltmpl") | ||||||
| 
 |  | ||||||
|       # modify a runtime dir |  | ||||||
|       runner = LoraxTemplateRunner(inroot=rundir, outroot=newrun) |  | ||||||
|       runner.run("runtime-transmogrify.ltmpl") |  | ||||||
| 
 |  | ||||||
|     NOTES: |     NOTES: | ||||||
| 
 | 
 | ||||||
|     * Parsing procedure is roughly: |     * Parsing procedure is roughly: | ||||||
| @ -128,6 +122,75 @@ class LoraxTemplateRunner(object): | |||||||
| 
 | 
 | ||||||
|     * Parsing and execution are *separate* passes - so you can't use the result |     * Parsing and execution are *separate* passes - so you can't use the result | ||||||
|       of a command in an %if statement (or any other control statements)! |       of a command in an %if statement (or any other control statements)! | ||||||
|  |     ''' | ||||||
|  |     def __init__(self, fatalerrors=True, templatedir=None, defaults=None, builtins=None): | ||||||
|  |         self.fatalerrors = fatalerrors | ||||||
|  |         self.templatedir = templatedir or "/usr/share/lorax" | ||||||
|  |         self.templatefile = None | ||||||
|  |         self.builtins = builtins or {} | ||||||
|  |         self.defaults = defaults or {} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def run(self, templatefile, **variables): | ||||||
|  |         for k,v in list(self.defaults.items()) + list(self.builtins.items()): | ||||||
|  |             variables.setdefault(k,v) | ||||||
|  |         logger.debug("executing %s with variables=%s", templatefile, variables) | ||||||
|  |         self.templatefile = templatefile | ||||||
|  |         t = LoraxTemplate(directories=[self.templatedir]) | ||||||
|  |         commands = t.parse(templatefile, variables) | ||||||
|  |         self._run(commands) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def _run(self, parsed_template): | ||||||
|  |         logger.info("running %s", self.templatefile) | ||||||
|  |         for (num, line) in enumerate(parsed_template,1): | ||||||
|  |             logger.debug("template line %i: %s", num, " ".join(line)) | ||||||
|  |             skiperror = False | ||||||
|  |             (cmd, args) = (line[0], line[1:]) | ||||||
|  |             # Following Makefile convention, if the command is prefixed with | ||||||
|  |             # a dash ('-'), we'll ignore any errors on that line. | ||||||
|  |             if cmd.startswith('-'): | ||||||
|  |                 cmd = cmd[1:] | ||||||
|  |                 skiperror = True | ||||||
|  |             try: | ||||||
|  |                 # grab the method named in cmd and pass it the given arguments | ||||||
|  |                 f = getattr(self, cmd, None) | ||||||
|  |                 if cmd[0] == '_' or cmd == 'run' or not isinstance(f, collections.Callable): | ||||||
|  |                     raise ValueError("unknown command %s" % cmd) | ||||||
|  |                 f(*args) | ||||||
|  |             except Exception: # pylint: disable=broad-except | ||||||
|  |                 if skiperror: | ||||||
|  |                     logger.debug("ignoring error") | ||||||
|  |                     continue | ||||||
|  |                 logger.error("template command error in %s:", self.templatefile) | ||||||
|  |                 logger.error("  %s", " ".join(line)) | ||||||
|  |                 # format the exception traceback | ||||||
|  |                 exclines = traceback.format_exception(*sys.exc_info()) | ||||||
|  |                 # skip the bit about "ltmpl.py, in _run()" - we know that | ||||||
|  |                 exclines.pop(1) | ||||||
|  |                 # log the "ErrorType: this is what happened" line | ||||||
|  |                 logger.error("  %s", exclines[-1].strip()) | ||||||
|  |                 # and log the entire traceback to the debug log | ||||||
|  |                 for _line in ''.join(exclines).splitlines(): | ||||||
|  |                     logger.debug("  %s", _line) | ||||||
|  |                 if self.fatalerrors: | ||||||
|  |                     raise | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # TODO: operate inside an actual chroot for safety? Not that RPM bothers.. | ||||||
|  | class LoraxTemplateRunner(TemplateRunner): | ||||||
|  |     ''' | ||||||
|  |     This class parses and executes Lorax templates. Sample usage: | ||||||
|  | 
 | ||||||
|  |       # install a bunch of packages | ||||||
|  |       runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) | ||||||
|  |       runner.run("install-packages.ltmpl") | ||||||
|  | 
 | ||||||
|  |       # modify a runtime dir | ||||||
|  |       runner = LoraxTemplateRunner(inroot=rundir, outroot=newrun) | ||||||
|  |       runner.run("runtime-transmogrify.ltmpl") | ||||||
|  | 
 | ||||||
|  |     NOTES: | ||||||
| 
 | 
 | ||||||
|     * Commands that run external programs (e.g. systemctl) currently use |     * Commands that run external programs (e.g. systemctl) currently use | ||||||
|       the *host*'s copy of that program, which may cause problems if there's a |       the *host*'s copy of that program, which may cause problems if there's a | ||||||
| @ -151,14 +214,11 @@ class LoraxTemplateRunner(object): | |||||||
|         self.inroot = inroot |         self.inroot = inroot | ||||||
|         self.outroot = outroot |         self.outroot = outroot | ||||||
|         self.dbo = dbo |         self.dbo = dbo | ||||||
|         self.fatalerrors = fatalerrors |         builtins = DataHolder(exists=lambda p: rexists(p, root=inroot), | ||||||
|         self.templatedir = templatedir or "/usr/share/lorax" |                               glob=lambda g: list(rglob(g, root=inroot))) | ||||||
|         self.templatefile = None |  | ||||||
|         # some builtin methods |  | ||||||
|         self.builtins = DataHolder(exists=lambda p: rexists(p, root=inroot), |  | ||||||
|                                    glob=lambda g: list(rglob(g, root=inroot))) |  | ||||||
|         self.defaults = defaults or {} |  | ||||||
|         self.results = DataHolder(treeinfo=dict()) # just treeinfo for now |         self.results = DataHolder(treeinfo=dict()) # just treeinfo for now | ||||||
|  | 
 | ||||||
|  |         super(LoraxTemplateRunner, self).__init__(fatalerrors, templatedir, defaults, builtins) | ||||||
|         # TODO: set up custom logger with a filter to add line info |         # TODO: set up custom logger with a filter to add line info | ||||||
| 
 | 
 | ||||||
|     def _out(self, path): |     def _out(self, path): | ||||||
| @ -209,52 +269,6 @@ class LoraxTemplateRunner(object): | |||||||
|             for pkg in debug_pkgs: |             for pkg in debug_pkgs: | ||||||
|                 f.write("%s\n" % pkg) |                 f.write("%s\n" % pkg) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     def run(self, templatefile, **variables): |  | ||||||
|         for k,v in list(self.defaults.items()) + list(self.builtins.items()): |  | ||||||
|             variables.setdefault(k,v) |  | ||||||
|         logger.debug("executing %s with variables=%s", templatefile, variables) |  | ||||||
|         self.templatefile = templatefile |  | ||||||
|         t = LoraxTemplate(directories=[self.templatedir]) |  | ||||||
|         commands = t.parse(templatefile, variables) |  | ||||||
|         self._run(commands) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     def _run(self, parsed_template): |  | ||||||
|         logger.info("running %s", self.templatefile) |  | ||||||
|         for (num, line) in enumerate(parsed_template,1): |  | ||||||
|             logger.debug("template line %i: %s", num, " ".join(line)) |  | ||||||
|             skiperror = False |  | ||||||
|             (cmd, args) = (line[0], line[1:]) |  | ||||||
|             # Following Makefile convention, if the command is prefixed with |  | ||||||
|             # a dash ('-'), we'll ignore any errors on that line. |  | ||||||
|             if cmd.startswith('-'): |  | ||||||
|                 cmd = cmd[1:] |  | ||||||
|                 skiperror = True |  | ||||||
|             try: |  | ||||||
|                 # grab the method named in cmd and pass it the given arguments |  | ||||||
|                 f = getattr(self, cmd, None) |  | ||||||
|                 if cmd[0] == '_' or cmd == 'run' or not isinstance(f, collections.Callable): |  | ||||||
|                     raise ValueError("unknown command %s" % cmd) |  | ||||||
|                 f(*args) |  | ||||||
|             except Exception: # pylint: disable=broad-except |  | ||||||
|                 if skiperror: |  | ||||||
|                     logger.debug("ignoring error") |  | ||||||
|                     continue |  | ||||||
|                 logger.error("template command error in %s:", self.templatefile) |  | ||||||
|                 logger.error("  %s", " ".join(line)) |  | ||||||
|                 # format the exception traceback |  | ||||||
|                 exclines = traceback.format_exception(*sys.exc_info()) |  | ||||||
|                 # skip the bit about "ltmpl.py, in _run()" - we know that |  | ||||||
|                 exclines.pop(1) |  | ||||||
|                 # log the "ErrorType: this is what happened" line |  | ||||||
|                 logger.error("  " + exclines[-1].strip()) |  | ||||||
|                 # and log the entire traceback to the debug log |  | ||||||
|                 for _line in ''.join(exclines).splitlines(): |  | ||||||
|                     logger.debug("  " + _line) |  | ||||||
|                 if self.fatalerrors: |  | ||||||
|                     raise |  | ||||||
| 
 |  | ||||||
|     def install(self, srcglob, dest): |     def install(self, srcglob, dest): | ||||||
|         ''' |         ''' | ||||||
|         install SRC DEST |         install SRC DEST | ||||||
| @ -265,6 +279,7 @@ class LoraxTemplateRunner(object): | |||||||
|           If DEST doesn't exist, SRC will be copied to a file with that name, |           If DEST doesn't exist, SRC will be copied to a file with that name, | ||||||
|           assuming the rest of the path exists. |           assuming the rest of the path exists. | ||||||
|           This is pretty much like how the 'cp' command works. |           This is pretty much like how the 'cp' command works. | ||||||
|  | 
 | ||||||
|           Examples: |           Examples: | ||||||
|             install usr/share/myconfig/grub.conf /boot |             install usr/share/myconfig/grub.conf /boot | ||||||
|             install /usr/share/myconfig/grub.conf.in /boot/grub.conf |             install /usr/share/myconfig/grub.conf.in /boot/grub.conf | ||||||
| @ -320,6 +335,7 @@ class LoraxTemplateRunner(object): | |||||||
|         ''' |         ''' | ||||||
|         mkdir DIR [DIR ...] |         mkdir DIR [DIR ...] | ||||||
|           Create the named DIR(s). Will create leading directories as needed. |           Create the named DIR(s). Will create leading directories as needed. | ||||||
|  | 
 | ||||||
|           Example: |           Example: | ||||||
|             mkdir /images |             mkdir /images | ||||||
|         ''' |         ''' | ||||||
| @ -333,6 +349,7 @@ class LoraxTemplateRunner(object): | |||||||
|         replace PATTERN REPLACEMENT FILEGLOB [FILEGLOB ...] |         replace PATTERN REPLACEMENT FILEGLOB [FILEGLOB ...] | ||||||
|           Find-and-replace the given PATTERN (Python-style regex) with the given |           Find-and-replace the given PATTERN (Python-style regex) with the given | ||||||
|           REPLACEMENT string for each of the files listed. |           REPLACEMENT string for each of the files listed. | ||||||
|  | 
 | ||||||
|           Example: |           Example: | ||||||
|             replace @VERSION@ ${product.version} /boot/grub.conf /boot/isolinux.cfg |             replace @VERSION@ ${product.version} /boot/grub.conf /boot/isolinux.cfg | ||||||
|         ''' |         ''' | ||||||
| @ -350,7 +367,9 @@ class LoraxTemplateRunner(object): | |||||||
|           Append STRING (followed by a newline character) to FILE. |           Append STRING (followed by a newline character) to FILE. | ||||||
|           Python character escape sequences ('\\n', '\\t', etc.) will be |           Python character escape sequences ('\\n', '\\t', etc.) will be | ||||||
|           converted to the appropriate characters. |           converted to the appropriate characters. | ||||||
|  | 
 | ||||||
|           Examples: |           Examples: | ||||||
|  | 
 | ||||||
|             append /etc/depmod.d/dd.conf "search updates built-in" |             append /etc/depmod.d/dd.conf "search updates built-in" | ||||||
|             append /etc/resolv.conf "" |             append /etc/resolv.conf "" | ||||||
|         ''' |         ''' | ||||||
| @ -363,6 +382,7 @@ class LoraxTemplateRunner(object): | |||||||
|           Add an item to the treeinfo data store. |           Add an item to the treeinfo data store. | ||||||
|           The given SECTION will have a new item added where |           The given SECTION will have a new item added where | ||||||
|           KEY = ARG ARG ... |           KEY = ARG ARG ... | ||||||
|  | 
 | ||||||
|           Example: |           Example: | ||||||
|             treeinfo images-${kernel.arch} boot.iso images/boot.iso |             treeinfo images-${kernel.arch} boot.iso images/boot.iso | ||||||
|         ''' |         ''' | ||||||
| @ -463,6 +483,7 @@ class LoraxTemplateRunner(object): | |||||||
|         ''' |         ''' | ||||||
|         log MESSAGE |         log MESSAGE | ||||||
|           Emit the given log message. Be sure to put it in quotes! |           Emit the given log message. Be sure to put it in quotes! | ||||||
|  | 
 | ||||||
|           Example: |           Example: | ||||||
|             log "Reticulating splines, please wait..." |             log "Reticulating splines, please wait..." | ||||||
|         ''' |         ''' | ||||||
| @ -581,6 +602,7 @@ class LoraxTemplateRunner(object): | |||||||
|         ''' |         ''' | ||||||
|         removepkg PKGGLOB [PKGGLOB...] |         removepkg PKGGLOB [PKGGLOB...] | ||||||
|           Delete the named package(s). |           Delete the named package(s). | ||||||
|  | 
 | ||||||
|           IMPLEMENTATION NOTES: |           IMPLEMENTATION NOTES: | ||||||
|             RPM scriptlets (%preun/%postun) are *not* run. |             RPM scriptlets (%preun/%postun) are *not* run. | ||||||
|             Files are deleted, but directories are left behind. |             Files are deleted, but directories are left behind. | ||||||
| @ -645,6 +667,7 @@ class LoraxTemplateRunner(object): | |||||||
|           (or packages) named. |           (or packages) named. | ||||||
|           If '--allbut' is used, all the files from the given package(s) will |           If '--allbut' is used, all the files from the given package(s) will | ||||||
|           be removed *except* the ones which match the file globs. |           be removed *except* the ones which match the file globs. | ||||||
|  | 
 | ||||||
|           Examples: |           Examples: | ||||||
|             removefrom usbutils /usr/bin/* |             removefrom usbutils /usr/bin/* | ||||||
|             removefrom xfsprogs --allbut /sbin/* |             removefrom xfsprogs --allbut /sbin/* | ||||||
| @ -738,6 +761,7 @@ class LoraxTemplateRunner(object): | |||||||
|         ''' |         ''' | ||||||
|         createaddrsize INITRD_ADDRESS INITRD ADDRSIZE |         createaddrsize INITRD_ADDRESS INITRD ADDRSIZE | ||||||
|           Create the initrd.addrsize file required in LPAR boot process. |           Create the initrd.addrsize file required in LPAR boot process. | ||||||
|  | 
 | ||||||
|           Examples: |           Examples: | ||||||
|             createaddrsize ${INITRD_ADDRESS} ${outroot}/${BOOTDIR}/initrd.img ${outroot}/${BOOTDIR}/initrd.addrsize |             createaddrsize ${INITRD_ADDRESS} ${outroot}/${BOOTDIR}/initrd.img ${outroot}/${BOOTDIR}/initrd.addrsize | ||||||
|         ''' |         ''' | ||||||
| @ -750,6 +774,7 @@ class LoraxTemplateRunner(object): | |||||||
|         ''' |         ''' | ||||||
|         systemctl [enable|disable|mask] UNIT [UNIT...] |         systemctl [enable|disable|mask] UNIT [UNIT...] | ||||||
|           Enable, disable, or mask the given systemd units. |           Enable, disable, or mask the given systemd units. | ||||||
|  | 
 | ||||||
|           Examples: |           Examples: | ||||||
|             systemctl disable lvm2-monitor.service |             systemctl disable lvm2-monitor.service | ||||||
|             systemctl mask fedora-storage-init.service fedora-configure.service |             systemctl mask fedora-storage-init.service fedora-configure.service | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user