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