/usr/lib/python3/dist-packages/simple_cdd/tools/base.py is in python3-simple-cdd 0.6.5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | from simple_cdd.exceptions import Fail
from simple_cdd.utils import run_command, shell_quote
import os.path
import logging
log = logging.getLogger()
class Tool:
"""
Base class for external tools
"""
TOOLS = {}
@classmethod
def register(cls, tool):
"""
Decorator used to register a Tool object so that it can be found when
tools need to be run
"""
cls.TOOLS[(tool.type, tool.name)] = tool
return tool
@classmethod
def create(cls, env, type, name):
"""
Create a tool runner for this type and name.
"""
tool = cls.TOOLS.get((type, name), None)
if tool is None:
return ToolShell(env, type, name)
else:
return tool(env)
class ToolShell(Tool):
"""
Base class for tools implemented as shell scripts
"""
# Tool type (build, mirror, testing)
type = "unknown"
# Tool name
name = "unknown"
def __init__(self, env, type=None, name=None):
"""
Basic initialization, and lookup of the full pathname of the shell
script.
ToolShell can be used directly without subclassing, to run shell tools
without extra checks or exports.
"""
if type is not None: self.type = type
if name is not None: self.name = name
self.env = env
self.pathname = self.find_script()
def find_script(self):
"""
Find the full pathname of the script to be run
"""
for d in self.env.get("simple_cdd_dirs"):
pathname = os.path.join(d, "tools", self.type, self.name)
if not os.path.exists(pathname): continue
return pathname
raise Fail("Cannot find tool %s/%s in %s", self.type, self.name, self.env.get("simple_cdd_dirs"))
def check_pre(self):
"""
Run checks before running the script
"""
pass
def check_post(self, retval):
"""
Run checks after running the script
"""
pass
def _make_run_script(self):
"""
Make a script that can be used to run this tool in the current
environment
"""
logdir = self.env.get("simple_cdd_logs")
scriptname = os.path.join(logdir, "{}-{}".format(self.type, self.name))
# Write out what we are doing into a script, both as clear
# documentation and as a way to rerun this step by hand and tweak
# it for debugging
with open(scriptname, "wt") as fd:
print("#!/bin/sh", file=fd)
print("# Execute tool {}/{}".format(self.type, self.name), file=fd)
print("", file=fd)
print("# Export environment", file=fd)
for name, val, changed in self.env.export_iter():
if val.help: print("#", val.help, file=fd)
print("export {}={}".format(name, shell_quote(str(val))), file=fd)
print("", file=fd)
print("# Run the tool", file=fd)
print("exec /bin/sh -ue {} \"$@\"".format(shell_quote(self.pathname)), file=fd)
os.chmod(scriptname, 0o755)
return scriptname
def run_script(self):
"""
Just build and run the script, without pre and post checks.
This is useful so that run() can be overridden to do more setup and
teardown that just the checks, and running the script can still be
delegated to this method
"""
# Check if the environment has changed since last run
log.info("Running tool %s", self.pathname)
scriptname = self._make_run_script()
retval = None
logfilename = scriptname + ".log"
with open(logfilename, "wt") as fd:
retval = run_command(
"{}/{}".format(self.type, self.name),
[scriptname],
env={},
logfd=fd)
if retval == 0:
log.info("%s/%s ran successfully, full log can be found in %s", self.type, self.name, scriptname)
else:
raise Fail("%s/%s exited with code %s, full log can be found in %s", self.type, self.name, retval, scriptname)
return retval
def run(self):
"""
Export variables and run the script
"""
self.check_pre()
retval = self.run_script()
self.check_post(retval)
|