#! /usr/bin/env python # encoding: utf-8 import sys if sys.hexversion < 0x020400f0: from sets import Set as set import os,traceback,copy import Build,Task,Utils,Logs,Options from Logs import debug,error,warn from Constants import* typos={'sources':'source','targets':'target','include':'includes','define':'defines','importpath':'importpaths','install_var':'install_path','install_subdir':'install_path','inst_var':'install_path','inst_dir':'install_path','feature':'features',} class register_obj(type): def __init__(cls,name,bases,dict): super(register_obj,cls).__init__(name,bases,dict) name=cls.__name__ suffix='_taskgen' if name.endswith(suffix): task_gen.classes[name.replace(suffix,'')]=cls class task_gen(object): __metaclass__=register_obj mappings={} mapped={} prec=Utils.DefaultDict(list) traits=Utils.DefaultDict(set) classes={} def __init__(self,*kw,**kwargs): self.prec=Utils.DefaultDict(list) self.source='' self.target='' self.meths=[] self.mappings={} self.features=list(kw) self.tasks=[] self.default_chmod=O644 self.default_install_path=None self.allnodes=[] self.bld=kwargs.get('bld',Build.bld) self.env=self.bld.env.copy() self.path=self.bld.path self.name='' self.idx=self.bld.idx[self.path.id]=self.bld.idx.get(self.path.id,0)+1 for key,val in kwargs.iteritems(): setattr(self,key,val) self.bld.task_manager.add_task_gen(self) self.bld.all_task_gen.append(self) def __str__(self): return(""%(self.name or self.target,self.__class__.__name__,str(self.path))) def __setattr__(self,name,attr): real=typos.get(name,name) if real!=name: warn('typo %s -> %s'%(name,real)) if Logs.verbose>0: traceback.print_stack() object.__setattr__(self,real,attr) def to_list(self,value): if isinstance(value,str):return value.split() else:return value def apply(self): keys=set(self.meths) self.features=Utils.to_list(self.features) for x in self.features+['*']: st=task_gen.traits[x] if not st: warn('feature %r does not exist - bind at least one method to it'%x) keys.update(st) prec={} prec_tbl=self.prec or task_gen.prec for x in prec_tbl: if x in keys: prec[x]=prec_tbl[x] tmp=[] for a in keys: for x in prec.values(): if a in x:break else: tmp.append(a) out=[] while tmp: e=tmp.pop() if e in keys:out.append(e) try: nlst=prec[e] except KeyError: pass else: del prec[e] for x in nlst: for y in prec: if x in prec[y]: break else: tmp.append(x) if prec:raise Utils.WafError("graph has a cycle %s"%str(prec)) out.reverse() self.meths=out debug('task_gen: posting %s %d',self,id(self)) for x in out: try: v=getattr(self,x) except AttributeError: raise Utils.WafError("tried to retrieve %s which is not a valid method"%x) debug('task_gen: -> %s (%d)',x,id(self)) v() def post(self): if not self.name: if isinstance(self.target,list): self.name=' '.join(self.target) else: self.name=self.target if getattr(self,'posted',None): return self.apply() self.posted=True debug('task_gen: posted %s',self.name) def get_hook(self,ext): try:return self.mappings[ext] except KeyError: try:return task_gen.mappings[ext] except KeyError:return None def create_task(self,name,src=None,tgt=None,env=None): env=env or self.env task=Task.TaskBase.classes[name](env.copy(),generator=self) if src: task.set_inputs(src) if tgt: task.set_outputs(tgt) self.tasks.append(task) return task def name_to_obj(self,name): return self.bld.name_to_obj(name,self.env) def find_sources_in_dirs(self,dirnames,excludes=[],exts=[]): err_msg="'%s' attribute must be a list" if not isinstance(excludes,list): raise Utils.WscriptError(err_msg%'excludes') if not isinstance(exts,list): raise Utils.WscriptError(err_msg%'exts') lst=[] dirnames=self.to_list(dirnames) ext_lst=exts or list(self.mappings.keys())+list(task_gen.mappings.keys()) for name in dirnames: anode=self.path.find_dir(name) if not anode or not anode.is_child_of(self.bld.srcnode): raise Utils.WscriptError("Unable to use '%s' - either because it's not a relative path"", or it's not child of '%s'."%(name,self.bld.srcnode)) self.bld.rescan(anode) for name in self.bld.cache_dir_contents[anode.id]: if name.startswith('.'): continue (base,ext)=os.path.splitext(name) if ext in ext_lst and not name in lst and not name in excludes: lst.append((anode.relpath_gen(self.path)or'.')+os.path.sep+name) lst.sort() self.source=self.to_list(self.source) if not self.source:self.source=lst else:self.source+=lst def clone(self,env): newobj=task_gen(bld=self.bld) for x in self.__dict__: if x in['env','bld']: continue elif x in["path","features"]: setattr(newobj,x,getattr(self,x)) else: setattr(newobj,x,copy.copy(getattr(self,x))) newobj.__class__=self.__class__ if isinstance(env,str): newobj.env=self.bld.all_envs[env].copy() else: newobj.env=env.copy() return newobj def get_inst_path(self): return getattr(self,'_install_path',getattr(self,'default_install_path','')) def set_inst_path(self,val): self._install_path=val install_path=property(get_inst_path,set_inst_path) def get_chmod(self): return getattr(self,'_chmod',getattr(self,'default_chmod',O644)) def set_chmod(self,val): self._chmod=val chmod=property(get_chmod,set_chmod) def declare_extension(var,func): try: for x in Utils.to_list(var): task_gen.mappings[x]=func except: raise Utils.WscriptError('declare_extension takes either a list or a string %r'%var) task_gen.mapped[func.__name__]=func def declare_order(*k): assert(len(k)>1) n=len(k)-1 for i in xrange(n): f1=k[i] f2=k[i+1] if not f1 in task_gen.prec[f2]: task_gen.prec[f2].append(f1) def declare_chain(name='',action='',ext_in='',ext_out='',reentrant=True,color='BLUE',install=0,before=[],after=[],decider=None,rule=None,scan=None): action=action or rule if isinstance(action,str): act=Task.simple_task_type(name,action,color=color) else: act=Task.task_type_from_func(name,action,color=color) act.ext_in=tuple(Utils.to_list(ext_in)) act.ext_out=tuple(Utils.to_list(ext_out)) act.before=Utils.to_list(before) act.after=Utils.to_list(after) act.scan=scan def x_file(self,node): if decider: ext=decider(self,node) else: ext=ext_out if isinstance(ext,str): out_source=node.change_ext(ext) if reentrant: self.allnodes.append(out_source) elif isinstance(ext,list): out_source=[node.change_ext(x)for x in ext] if reentrant: for i in xrange((reentrant is True)and len(out_source)or reentrant): self.allnodes.append(out_source[i]) else: raise Utils.WafError("do not know how to process %s"%str(ext)) tsk=self.create_task(name,node,out_source) if node.__class__.bld.is_install: tsk.install=install declare_extension(act.ext_in,x_file) return x_file def bind_feature(name,methods): lst=Utils.to_list(methods) task_gen.traits[name].update(lst) def taskgen(func): setattr(task_gen,func.__name__,func) return func def feature(*k): def deco(func): setattr(task_gen,func.__name__,func) for name in k: task_gen.traits[name].update([func.__name__]) return func return deco def before(*k): def deco(func): setattr(task_gen,func.__name__,func) for fun_name in k: if not func.__name__ in task_gen.prec[fun_name]: task_gen.prec[fun_name].append(func.__name__) return func return deco def after(*k): def deco(func): setattr(task_gen,func.__name__,func) for fun_name in k: if not fun_name in task_gen.prec[func.__name__]: task_gen.prec[func.__name__].append(fun_name) return func return deco def extension(var): def deco(func): setattr(task_gen,func.__name__,func) try: for x in Utils.to_list(var): task_gen.mappings[x]=func except: raise Utils.WafError('extension takes either a list or a string %r'%var) task_gen.mapped[func.__name__]=func return func return deco def apply_core(self): find_resource=self.path.find_resource for filename in self.to_list(self.source): x=self.get_hook(filename) if x: x(self,filename) else: node=find_resource(filename) if not node:raise Utils.WafError("source not found: '%s' in '%s'"%(filename,str(self.path))) self.allnodes.append(node) for node in self.allnodes: x=self.get_hook(node.suffix()) if not x: raise Utils.WafError("Cannot guess how to process %s (got mappings %r in %r) -> try conf.check_tool(..)?"%(str(node),self.__class__.mappings.keys(),self.__class__)) x(self,node) feature('*')(apply_core) def exec_rule(self): if not getattr(self,'rule',None): return try: self.meths.remove('apply_core') except ValueError: pass func=self.rule vars2=[] if isinstance(func,str): (func,vars2)=Task.compile_fun('',self.rule,shell=getattr(self,'shell',True)) func.code=self.rule name=getattr(self,'name',None)or self.target or self.rule if not isinstance(name,str): name=str(self.idx) cls=Task.task_type_from_func(name,func,getattr(self,'vars',vars2)) cls.color=getattr(self,'color','BLUE') tsk=self.create_task(name) dep_vars=getattr(self,'dep_vars',['ruledeps']) if dep_vars: tsk.dep_vars=dep_vars if isinstance(self.rule,str): tsk.env.ruledeps=self.rule else: tsk.env.ruledeps=Utils.h_fun(self.rule) if getattr(self,'target',None): cls.quiet=True tsk.outputs=[self.path.find_or_declare(x)for x in self.to_list(self.target)] if getattr(self,'source',None): cls.quiet=True tsk.inputs=[] for x in self.to_list(self.source): y=self.path.find_resource(x) if not y: raise Utils.WafError('input file %r could not be found (%r)'%(x,self.path.abspath())) tsk.inputs.append(y) if self.allnodes: tsk.inputs.extend(self.allnodes) if getattr(self,'scan',None): cls.scan=self.scan if getattr(self,'install_path',None): tsk.install_path=self.install_path if getattr(self,'cwd',None): tsk.cwd=self.cwd if getattr(self,'on_results',None): Task.update_outputs(cls) if getattr(self,'always',None): Task.always_run(cls) for x in['after','before','ext_in','ext_out']: setattr(cls,x,getattr(self,x,[])) feature('*')(exec_rule) before('apply_core')(exec_rule) def sequence_order(self): if self.meths and self.meths[-1]!='sequence_order': self.meths.append('sequence_order') return if getattr(self,'seq_start',None): return if getattr(self.bld,'prev',None): self.bld.prev.post() for x in self.bld.prev.tasks: for y in self.tasks: y.set_run_after(x) self.bld.prev=self feature('seq')(sequence_order)