github.com/hwaf/hwaf@v0.0.0-20140814122253-5465f73b20f1/py-hwaftools/orch/tools.py (about) 1 #!/usr/bin/env python 2 ''' 3 Main entry to worch from a waf wscript file. 4 5 Use the following in the options(), configure() and build() waf wscript methods: 6 7 ctx.load('orch.tools', tooldir='.') 8 9 ''' 10 11 def options(opt): 12 opt.add_option('--orch-config', action = 'store', default = 'orch.cfg', 13 help='Give an orchestration configuration file.') 14 opt.add_option('--orch-start', action = 'store', default = 'start', 15 help='Set the section to start the orchestration') 16 17 def configure(cfg): 18 import orch.configure 19 orch.configure.configure(cfg) 20 21 def build(bld): 22 import orch.build 23 orch.build.build(bld) 24 25 26 # the stuff below is for augmenting waf 27 28 import time 29 from orch.wafutil import exec_command 30 from orch.util import string2list 31 32 default_step_cwd = dict( 33 download = '{download_dir}', 34 unpack = '{source_dir}', 35 patch = '{source_dir}', 36 prepare = '{build_dir}', 37 build = '{build_dir}', 38 install = '{build_dir}', 39 ) 40 41 # Main interface to worch configuration items 42 class WorchConfig(object): 43 def __init__(self, **pkgcfg): 44 self._config = pkgcfg 45 def __getattr__(self, name): 46 return self._config[name] 47 48 def get(self, name, default = None): 49 return self._config.get(name,default) 50 51 def format(self, string, **kwds): 52 ''' 53 Return a string formatted with kwds and configuration items 54 ''' 55 d = dict(self._config, **kwds) 56 return string.format(**d) 57 58 def depends_step(self, step): 59 ''' 60 Return a list of steps that this step depends on 61 ''' 62 d = self._config.get('depends') 63 if not d: return list() 64 ds = [x[1] for x in [s.split(':') for s in string2list(d)] if x[0] == step] 65 return ds 66 67 def dependencies(self): 68 ''' 69 Return all dependencies set via "depends" configuration items 70 return list of tuples: (mystep, package, package_step) 71 eg: ('prepare', 'gcc', 'install') 72 ''' 73 ret = list() 74 try: 75 deps = getattr(self, 'depends', None) 76 except KeyError: 77 return list() 78 for dep in string2list(deps): 79 mystep, other = dep.split(':') 80 pkg,pkg_step = other.split('_',1) 81 ret.append((mystep, pkg, pkg_step)) 82 return ret 83 84 def exports(self): 85 ''' 86 Return all environment settings via export_* configuration items 87 return list of tuples: (variable, value, operator) for exports 88 eg: ('PATH', '/blah/blah', 'prepend') 89 ''' 90 ret = list() 91 for key,val in self._config.items(): 92 if not key.startswith('export_'): 93 continue 94 var = key[len('export_'):] 95 oper = 'set' 96 for maybe in ['prepend', 'append', 'set']: 97 if val.startswith(maybe+':'): 98 oper = maybe 99 val = val[len(maybe)+1:] 100 ret.append((var, val, oper)) 101 return ret 102 103 104 105 # Augment the task generator with worch-specific methods 106 from waflib.TaskGen import taskgen_method 107 108 @taskgen_method 109 def worch_hello(self): 110 'Just testing' 111 print ("%s" % self.worch.format('Hi from worch, my name is "{package}/{version}" and I am using "{dumpenv_cmd}" with extra {extra}', extra='spice')) 112 print ('My bld.env: %s' % (self.bld.env.keys(),)) 113 print ('My all_envs: %s' % (sorted(self.bld.all_envs.keys()),)) 114 print ('My env: %s' % (self.env.keys(),)) 115 print ('My groups: %s' % (self.env['orch_group_dict'].keys(),)) 116 print ('My packages: %s' % (self.env['orch_package_list'],)) 117 # print ('My package dict: %s' % '\n'.join(['%s=%s' %kv for kv in sorted(self.bld.env['orch_package_dict'][self.worch.package].items())])) 118 119 120 121 @taskgen_method 122 def step(self, name, rule, **kwds): 123 ''' 124 Make a worch installation step. 125 126 This invokes the build context on the rule with the following augmentations: 127 128 - the given step name is prefixed with the package name 129 - if the rule is a string (scriptlet) then the worch exec_command is used 130 - successful execution of the rule leads to a worch control file being produced. 131 ''' 132 step_name = '%s_%s' % (self.worch.package, name) 133 134 # append control file as an additional output 135 target = string2list(kwds.get('target', '')) 136 if not isinstance(target, list): 137 target = [target] 138 cn = self.control_node(name) 139 if not cn in target: 140 target.append(cn) 141 kwds['target'] = target 142 143 kwds.setdefault('env', self.env) 144 145 cwd = kwds.get('cwd') 146 if not cwd: 147 cwd = default_step_cwd.get(name) 148 if cwd: 149 cwd = self.worch.format(cwd) 150 cwd = self.make_node(cwd) 151 msg.debug('orch: using cwd for step "%s": %s' % (step_name, cwd.abspath())) 152 kwds['cwd'] = cwd.abspath() 153 154 155 depends = self.worch.depends_step(name) 156 after = string2list(kwds.get('after',[])) + depends 157 if after: 158 kwds['after'] = after 159 msg.debug('orch: run %s AFTER: %s' % (step_name, after)) 160 161 # functionalize scriptlet 162 rulefun = rule 163 if isinstance(rule, type('')): 164 rulefun = lambda t: exec_command(t, rule) 165 166 # curry the real rule function in order to write control file if successful 167 def runit(t): 168 rc = rulefun(t) 169 if not rc: 170 msg.debug('orch: successfully ran %s' % step_name) 171 cn.write(time.asctime(time.localtime()) + '\n') 172 return rc 173 174 # msg.debug('orch: step "%s" with %s in %s\nsource=%s\ntarget=%s' % \ 175 # (step_name, rulefun, cwd, kwds.get('source'), kwds.get('target'))) 176 177 # have to switch group each time as steps are called already asynchronously 178 self.bld.set_group(self.worch.group) 179 return self.bld(name=step_name, rule = runit, **kwds) 180 181 @taskgen_method 182 def control_node(self, step, package = None): 183 ''' 184 Return a node for the control file given step of this package or optionally another package. 185 ''' 186 if not package: 187 package = self.worch.package 188 filename = '%s_%s' % (package, step) 189 path = self.worch.format('{control_dir}/{filename}', filename=filename) 190 return self.path.find_or_declare(path) 191 192 @taskgen_method 193 def make_node(self, path, parent_node=None): 194 if not parent_node: 195 if path.startswith('/'): 196 parent_node = self.bld.root 197 else: 198 parent_node = self.bld.bldnode 199 return parent_node.make_node(path) 200 201 202 import waflib.Logs as msg 203 from waflib.Build import BuildContext 204 def worch_package(ctx, worch_config, *args, **kw): 205 206 # transfer waf-specific keywords explicitly 207 kw['name'] = worch_config['package'] 208 kw['features'] = ' '.join(string2list(worch_config['features'])) 209 kw['use'] = worch_config.get('use') 210 211 # make the TaskGen object for the package 212 worch=WorchConfig(**worch_config) 213 tgen = ctx(*args, worch=worch, **kw) 214 tgen.env = ctx.all_envs[worch.package] 215 tgen.env.env = tgen.env.munged_env 216 msg.debug('orch: package "%s" with features: %s' % \ 217 (kw['name'], ', '.join(kw['features'].split()))) 218 return tgen 219 BuildContext.worch_package = worch_package 220 del worch_package