| #! /usr/bin/env python |
| # encoding: utf-8 |
| # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file |
| |
| import os,shutil,re,tempfile |
| from waflib import Utils,Logs,Errors |
| NOT_RUN=0 |
| MISSING=1 |
| CRASHED=2 |
| EXCEPTION=3 |
| SKIPPED=8 |
| SUCCESS=9 |
| ASK_LATER=-1 |
| SKIP_ME=-2 |
| RUN_ME=-3 |
| COMPILE_TEMPLATE_SHELL=''' |
| def f(tsk): |
| env = tsk.env |
| gen = tsk.generator |
| bld = gen.bld |
| wd = getattr(tsk, 'cwd', None) |
| p = env.get_flat |
| tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s |
| return tsk.exec_command(cmd, cwd=wd, env=env.env or None) |
| ''' |
| COMPILE_TEMPLATE_NOSHELL=''' |
| def f(tsk): |
| env = tsk.env |
| gen = tsk.generator |
| bld = gen.bld |
| wd = getattr(tsk, 'cwd', None) |
| def to_list(xx): |
| if isinstance(xx, str): return [xx] |
| return xx |
| tsk.last_cmd = lst = [] |
| %s |
| lst = [x for x in lst if x] |
| return tsk.exec_command(lst, cwd=wd, env=env.env or None) |
| ''' |
| def cache_outputs(cls): |
| m1=cls.run |
| def run(self): |
| bld=self.generator.bld |
| if bld.cache_global and not bld.nocache: |
| if self.can_retrieve_cache(): |
| return 0 |
| return m1(self) |
| cls.run=run |
| m2=cls.post_run |
| def post_run(self): |
| bld=self.generator.bld |
| ret=m2(self) |
| if bld.cache_global and not bld.nocache: |
| self.put_files_cache() |
| return ret |
| cls.post_run=post_run |
| return cls |
| classes={} |
| class store_task_type(type): |
| def __init__(cls,name,bases,dict): |
| super(store_task_type,cls).__init__(name,bases,dict) |
| name=cls.__name__ |
| if name.endswith('_task'): |
| name=name.replace('_task','') |
| if name!='evil'and name!='TaskBase': |
| global classes |
| if getattr(cls,'run_str',None): |
| (f,dvars)=compile_fun(cls.run_str,cls.shell) |
| cls.hcode=cls.run_str |
| cls.run_str=None |
| cls.run=f |
| cls.vars=list(set(cls.vars+dvars)) |
| cls.vars.sort() |
| elif getattr(cls,'run',None)and not'hcode'in cls.__dict__: |
| cls.hcode=Utils.h_fun(cls.run) |
| if not getattr(cls,'nocache',None): |
| cls=cache_outputs(cls) |
| getattr(cls,'register',classes)[name]=cls |
| evil=store_task_type('evil',(object,),{}) |
| class TaskBase(evil): |
| color='GREEN' |
| ext_in=[] |
| ext_out=[] |
| before=[] |
| after=[] |
| hcode='' |
| def __init__(self,*k,**kw): |
| self.hasrun=NOT_RUN |
| try: |
| self.generator=kw['generator'] |
| except KeyError: |
| self.generator=self |
| def __repr__(self): |
| return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,'fun',''))) |
| def __str__(self): |
| if hasattr(self,'fun'): |
| return'executing: %s\n'%self.fun.__name__ |
| return self.__class__.__name__+'\n' |
| def __hash__(self): |
| return id(self) |
| def exec_command(self,cmd,**kw): |
| bld=self.generator.bld |
| try: |
| if not kw.get('cwd',None): |
| kw['cwd']=bld.cwd |
| except AttributeError: |
| bld.cwd=kw['cwd']=bld.variant_dir |
| return bld.exec_command(cmd,**kw) |
| def runnable_status(self): |
| return RUN_ME |
| def process(self): |
| m=self.master |
| if m.stop: |
| m.out.put(self) |
| return |
| try: |
| del self.generator.bld.task_sigs[self.uid()] |
| except KeyError: |
| pass |
| try: |
| self.generator.bld.returned_tasks.append(self) |
| self.log_display(self.generator.bld) |
| ret=self.run() |
| except Exception: |
| self.err_msg=Utils.ex_stack() |
| self.hasrun=EXCEPTION |
| m.error_handler(self) |
| m.out.put(self) |
| return |
| if ret: |
| self.err_code=ret |
| self.hasrun=CRASHED |
| else: |
| try: |
| self.post_run() |
| except Errors.WafError: |
| pass |
| except Exception: |
| self.err_msg=Utils.ex_stack() |
| self.hasrun=EXCEPTION |
| else: |
| self.hasrun=SUCCESS |
| if self.hasrun!=SUCCESS: |
| m.error_handler(self) |
| m.out.put(self) |
| def run(self): |
| if hasattr(self,'fun'): |
| return self.fun(self) |
| return 0 |
| def post_run(self): |
| pass |
| def log_display(self,bld): |
| bld.to_log(self.display()) |
| def display(self): |
| col1=Logs.colors(self.color) |
| col2=Logs.colors.NORMAL |
| master=self.master |
| def cur(): |
| tmp=-1 |
| if hasattr(master,'ready'): |
| tmp-=master.ready.qsize() |
| return master.processed+tmp |
| if self.generator.bld.progress_bar==1: |
| return self.generator.bld.progress_line(cur(),master.total,col1,col2) |
| if self.generator.bld.progress_bar==2: |
| ela=str(self.generator.bld.timer) |
| try: |
| ins=','.join([n.name for n in self.inputs]) |
| except AttributeError: |
| ins='' |
| try: |
| outs=','.join([n.name for n in self.outputs]) |
| except AttributeError: |
| outs='' |
| return'|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n'%(master.total,cur(),ins,outs,ela) |
| s=str(self) |
| if not s: |
| return None |
| total=master.total |
| n=len(str(total)) |
| fs='[%%%dd/%%%dd] %%s%%s%%s'%(n,n) |
| return fs%(cur(),total,col1,s,col2) |
| def attr(self,att,default=None): |
| ret=getattr(self,att,self) |
| if ret is self:return getattr(self.__class__,att,default) |
| return ret |
| def hash_constraints(self): |
| cls=self.__class__ |
| tup=(str(cls.before),str(cls.after),str(cls.ext_in),str(cls.ext_out),cls.__name__,cls.hcode) |
| h=hash(tup) |
| return h |
| def format_error(self): |
| msg=getattr(self,'last_cmd','') |
| name=getattr(self.generator,'name','') |
| if getattr(self,"err_msg",None): |
| return self.err_msg |
| elif not self.hasrun: |
| return'task in %r was not executed for some reason: %r'%(name,self) |
| elif self.hasrun==CRASHED: |
| try: |
| return' -> task in %r failed (exit status %r): %r\n%r'%(name,self.err_code,self,msg) |
| except AttributeError: |
| return' -> task in %r failed: %r\n%r'%(name,self,msg) |
| elif self.hasrun==MISSING: |
| return' -> missing files in %r: %r\n%r'%(name,self,msg) |
| else: |
| return'invalid status for task in %r: %r'%(name,self.hasrun) |
| def colon(self,var1,var2): |
| tmp=self.env[var1] |
| if isinstance(var2,str): |
| it=self.env[var2] |
| else: |
| it=var2 |
| if isinstance(tmp,str): |
| return[tmp%x for x in it] |
| else: |
| if Logs.verbose and not tmp and it: |
| Logs.warn('Missing env variable %r for task %r (generator %r)'%(var1,self,self.generator)) |
| lst=[] |
| for y in it: |
| lst.extend(tmp) |
| lst.append(y) |
| return lst |
| class Task(TaskBase): |
| vars=[] |
| shell=False |
| def __init__(self,*k,**kw): |
| TaskBase.__init__(self,*k,**kw) |
| self.env=kw['env'] |
| self.inputs=[] |
| self.outputs=[] |
| self.dep_nodes=[] |
| self.run_after=set([]) |
| def __str__(self): |
| env=self.env |
| src_str=' '.join([a.nice_path()for a in self.inputs]) |
| tgt_str=' '.join([a.nice_path()for a in self.outputs]) |
| if self.outputs:sep=' -> ' |
| else:sep='' |
| return'%s: %s%s%s\n'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str) |
| def __repr__(self): |
| try: |
| ins=",".join([x.name for x in self.inputs]) |
| outs=",".join([x.name for x in self.outputs]) |
| except AttributeError: |
| ins=",".join([str(x)for x in self.inputs]) |
| outs=",".join([str(x)for x in self.outputs]) |
| return"".join(['\n\t{task %r: '%id(self),self.__class__.__name__," ",ins," -> ",outs,'}']) |
| def uid(self): |
| try: |
| return self.uid_ |
| except AttributeError: |
| m=Utils.md5() |
| up=m.update |
| up(self.__class__.__name__) |
| for x in self.inputs+self.outputs: |
| up(x.abspath()) |
| self.uid_=m.digest() |
| return self.uid_ |
| def set_inputs(self,inp): |
| if isinstance(inp,list):self.inputs+=inp |
| else:self.inputs.append(inp) |
| def set_outputs(self,out): |
| if isinstance(out,list):self.outputs+=out |
| else:self.outputs.append(out) |
| def set_run_after(self,task): |
| assert isinstance(task,TaskBase) |
| self.run_after.add(task) |
| def signature(self): |
| try:return self.cache_sig |
| except AttributeError:pass |
| self.m=Utils.md5() |
| self.m.update(self.hcode) |
| self.sig_explicit_deps() |
| self.sig_vars() |
| if self.scan: |
| try: |
| self.sig_implicit_deps() |
| except Errors.TaskRescan: |
| return self.signature() |
| ret=self.cache_sig=self.m.digest() |
| return ret |
| def runnable_status(self): |
| for t in self.run_after: |
| if not t.hasrun: |
| return ASK_LATER |
| bld=self.generator.bld |
| try: |
| new_sig=self.signature() |
| except Errors.TaskNotReady: |
| return ASK_LATER |
| key=self.uid() |
| try: |
| prev_sig=bld.task_sigs[key] |
| except KeyError: |
| Logs.debug("task: task %r must run as it was never run before or the task code changed"%self) |
| return RUN_ME |
| for node in self.outputs: |
| try: |
| if node.sig!=new_sig: |
| return RUN_ME |
| except AttributeError: |
| Logs.debug("task: task %r must run as the output nodes do not exist"%self) |
| return RUN_ME |
| if new_sig!=prev_sig: |
| return RUN_ME |
| return SKIP_ME |
| def post_run(self): |
| bld=self.generator.bld |
| sig=self.signature() |
| for node in self.outputs: |
| try: |
| os.stat(node.abspath()) |
| except OSError: |
| self.hasrun=MISSING |
| self.err_msg='-> missing file: %r'%node.abspath() |
| raise Errors.WafError(self.err_msg) |
| node.sig=sig |
| bld.task_sigs[self.uid()]=self.cache_sig |
| def sig_explicit_deps(self): |
| bld=self.generator.bld |
| upd=self.m.update |
| for x in self.inputs+self.dep_nodes: |
| try: |
| upd(x.get_bld_sig()) |
| except(AttributeError,TypeError): |
| raise Errors.WafError('Missing node signature for %r (required by %r)'%(x,self)) |
| if bld.deps_man: |
| additional_deps=bld.deps_man |
| for x in self.inputs+self.outputs: |
| try: |
| d=additional_deps[id(x)] |
| except KeyError: |
| continue |
| for v in d: |
| if isinstance(v,bld.root.__class__): |
| try: |
| v=v.get_bld_sig() |
| except AttributeError: |
| raise Errors.WafError('Missing node signature for %r (required by %r)'%(v,self)) |
| elif hasattr(v,'__call__'): |
| v=v() |
| upd(v) |
| return self.m.digest() |
| def sig_vars(self): |
| bld=self.generator.bld |
| env=self.env |
| upd=self.m.update |
| act_sig=bld.hash_env_vars(env,self.__class__.vars) |
| upd(act_sig) |
| dep_vars=getattr(self,'dep_vars',None) |
| if dep_vars: |
| upd(bld.hash_env_vars(env,dep_vars)) |
| return self.m.digest() |
| scan=None |
| def sig_implicit_deps(self): |
| bld=self.generator.bld |
| key=self.uid() |
| prev=bld.task_sigs.get((key,'imp'),[]) |
| if prev: |
| try: |
| if prev==self.compute_sig_implicit_deps(): |
| return prev |
| except Exception: |
| for x in bld.node_deps.get(self.uid(),[]): |
| if x.is_child_of(bld.srcnode): |
| try: |
| os.stat(x.abspath()) |
| except OSError: |
| try: |
| del x.parent.children[x.name] |
| except KeyError: |
| pass |
| del bld.task_sigs[(key,'imp')] |
| raise Errors.TaskRescan('rescan') |
| (nodes,names)=self.scan() |
| if Logs.verbose: |
| Logs.debug('deps: scanner for %s returned %s %s'%(str(self),str(nodes),str(names))) |
| bld.node_deps[key]=nodes |
| bld.raw_deps[key]=names |
| self.are_implicit_nodes_ready() |
| try: |
| bld.task_sigs[(key,'imp')]=sig=self.compute_sig_implicit_deps() |
| except Exception: |
| if Logs.verbose: |
| for k in bld.node_deps.get(self.uid(),[]): |
| try: |
| k.get_bld_sig() |
| except Exception: |
| Logs.warn('Missing signature for node %r (may cause rebuilds)'%k) |
| else: |
| return sig |
| def compute_sig_implicit_deps(self): |
| upd=self.m.update |
| bld=self.generator.bld |
| self.are_implicit_nodes_ready() |
| for k in bld.node_deps.get(self.uid(),[]): |
| upd(k.get_bld_sig()) |
| return self.m.digest() |
| def are_implicit_nodes_ready(self): |
| bld=self.generator.bld |
| try: |
| cache=bld.dct_implicit_nodes |
| except AttributeError: |
| bld.dct_implicit_nodes=cache={} |
| try: |
| dct=cache[bld.cur] |
| except KeyError: |
| dct=cache[bld.cur]={} |
| for tsk in bld.cur_tasks: |
| for x in tsk.outputs: |
| dct[x]=tsk |
| modified=False |
| for x in bld.node_deps.get(self.uid(),[]): |
| if x in dct: |
| self.run_after.add(dct[x]) |
| modified=True |
| if modified: |
| for tsk in self.run_after: |
| if not tsk.hasrun: |
| raise Errors.TaskNotReady('not ready') |
| def can_retrieve_cache(self): |
| if not getattr(self,'outputs',None): |
| return None |
| sig=self.signature() |
| ssig=Utils.to_hex(self.uid())+Utils.to_hex(sig) |
| dname=os.path.join(self.generator.bld.cache_global,ssig) |
| try: |
| t1=os.stat(dname).st_mtime |
| except OSError: |
| return None |
| for node in self.outputs: |
| orig=os.path.join(dname,node.name) |
| try: |
| shutil.copy2(orig,node.abspath()) |
| os.utime(orig,None) |
| except(OSError,IOError): |
| Logs.debug('task: failed retrieving file') |
| return None |
| try: |
| t2=os.stat(dname).st_mtime |
| except OSError: |
| return None |
| if t1!=t2: |
| return None |
| for node in self.outputs: |
| node.sig=sig |
| if self.generator.bld.progress_bar<1: |
| self.generator.bld.to_log('restoring from cache %r\n'%node.abspath()) |
| self.cached=True |
| return True |
| def put_files_cache(self): |
| if getattr(self,'cached',None): |
| return None |
| if not getattr(self,'outputs',None): |
| return None |
| sig=self.signature() |
| ssig=Utils.to_hex(self.uid())+Utils.to_hex(sig) |
| dname=os.path.join(self.generator.bld.cache_global,ssig) |
| tmpdir=tempfile.mkdtemp(prefix=self.generator.bld.cache_global+os.sep+'waf') |
| try: |
| shutil.rmtree(dname) |
| except Exception: |
| pass |
| try: |
| for node in self.outputs: |
| dest=os.path.join(tmpdir,node.name) |
| shutil.copy2(node.abspath(),dest) |
| except(OSError,IOError): |
| try: |
| shutil.rmtree(tmpdir) |
| except Exception: |
| pass |
| else: |
| try: |
| os.rename(tmpdir,dname) |
| except OSError: |
| try: |
| shutil.rmtree(tmpdir) |
| except Exception: |
| pass |
| else: |
| try: |
| os.chmod(dname,Utils.O755) |
| except Exception: |
| pass |
| def is_before(t1,t2): |
| to_list=Utils.to_list |
| for k in to_list(t2.ext_in): |
| if k in to_list(t1.ext_out): |
| return 1 |
| if t1.__class__.__name__ in to_list(t2.after): |
| return 1 |
| if t2.__class__.__name__ in to_list(t1.before): |
| return 1 |
| return 0 |
| def set_file_constraints(tasks): |
| ins=Utils.defaultdict(set) |
| outs=Utils.defaultdict(set) |
| for x in tasks: |
| for a in getattr(x,'inputs',[])+getattr(x,'dep_nodes',[]): |
| ins[id(a)].add(x) |
| for a in getattr(x,'outputs',[]): |
| outs[id(a)].add(x) |
| links=set(ins.keys()).intersection(outs.keys()) |
| for k in links: |
| for a in ins[k]: |
| a.run_after.update(outs[k]) |
| def set_precedence_constraints(tasks): |
| cstr_groups=Utils.defaultdict(list) |
| for x in tasks: |
| h=x.hash_constraints() |
| cstr_groups[h].append(x) |
| keys=list(cstr_groups.keys()) |
| maxi=len(keys) |
| for i in range(maxi): |
| t1=cstr_groups[keys[i]][0] |
| for j in range(i+1,maxi): |
| t2=cstr_groups[keys[j]][0] |
| if is_before(t1,t2): |
| a=i |
| b=j |
| elif is_before(t2,t1): |
| a=j |
| b=i |
| else: |
| continue |
| aval=set(cstr_groups[keys[a]]) |
| for x in cstr_groups[keys[b]]: |
| x.run_after.update(aval) |
| def funex(c): |
| dc={} |
| exec(c,dc) |
| return dc['f'] |
| reg_act=re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})",re.M) |
| def compile_fun_shell(line): |
| extr=[] |
| def repl(match): |
| g=match.group |
| if g('dollar'):return"$" |
| elif g('backslash'):return'\\\\' |
| elif g('subst'):extr.append((g('var'),g('code')));return"%s" |
| return None |
| line=reg_act.sub(repl,line)or line |
| parm=[] |
| dvars=[] |
| app=parm.append |
| for(var,meth)in extr: |
| if var=='SRC': |
| if meth:app('tsk.inputs%s'%meth) |
| else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.inputs])') |
| elif var=='TGT': |
| if meth:app('tsk.outputs%s'%meth) |
| else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.outputs])') |
| elif meth: |
| if meth.startswith(':'): |
| m=meth[1:] |
| if m=='SRC': |
| m='[a.path_from(bld.bldnode) for a in tsk.inputs]' |
| elif m=='TGT': |
| m='[a.path_from(bld.bldnode) for a in tsk.outputs]' |
| elif m[:3]not in('tsk','gen','bld'): |
| dvars.extend([var,meth[1:]]) |
| m='%r'%m |
| app('" ".join(tsk.colon(%r, %s))'%(var,m)) |
| else: |
| app('%s%s'%(var,meth)) |
| else: |
| if not var in dvars:dvars.append(var) |
| app("p('%s')"%var) |
| if parm:parm="%% (%s) "%(',\n\t\t'.join(parm)) |
| else:parm='' |
| c=COMPILE_TEMPLATE_SHELL%(line,parm) |
| Logs.debug('action: %s'%c.strip().splitlines()) |
| return(funex(c),dvars) |
| def compile_fun_noshell(line): |
| extr=[] |
| def repl(match): |
| g=match.group |
| if g('dollar'):return"$" |
| elif g('subst'):extr.append((g('var'),g('code')));return"<<|@|>>" |
| return None |
| line2=reg_act.sub(repl,line) |
| params=line2.split('<<|@|>>') |
| assert(extr) |
| buf=[] |
| dvars=[] |
| app=buf.append |
| for x in range(len(extr)): |
| params[x]=params[x].strip() |
| if params[x]: |
| app("lst.extend(%r)"%params[x].split()) |
| (var,meth)=extr[x] |
| if var=='SRC': |
| if meth:app('lst.append(tsk.inputs%s)'%meth) |
| else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])") |
| elif var=='TGT': |
| if meth:app('lst.append(tsk.outputs%s)'%meth) |
| else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])") |
| elif meth: |
| if meth.startswith(':'): |
| m=meth[1:] |
| if m=='SRC': |
| m='[a.path_from(bld.bldnode) for a in tsk.inputs]' |
| elif m=='TGT': |
| m='[a.path_from(bld.bldnode) for a in tsk.outputs]' |
| elif m[:3]not in('tsk','gen','bld'): |
| dvars.extend([var,m]) |
| m='%r'%m |
| app('lst.extend(tsk.colon(%r, %s))'%(var,m)) |
| else: |
| app('lst.extend(gen.to_list(%s%s))'%(var,meth)) |
| else: |
| app('lst.extend(to_list(env[%r]))'%var) |
| if not var in dvars:dvars.append(var) |
| if extr: |
| if params[-1]: |
| app("lst.extend(%r)"%params[-1].split()) |
| fun=COMPILE_TEMPLATE_NOSHELL%"\n\t".join(buf) |
| Logs.debug('action: %s'%fun.strip().splitlines()) |
| return(funex(fun),dvars) |
| def compile_fun(line,shell=False): |
| if line.find('<')>0 or line.find('>')>0 or line.find('&&')>0: |
| shell=True |
| if shell: |
| return compile_fun_shell(line) |
| else: |
| return compile_fun_noshell(line) |
| def task_factory(name,func=None,vars=None,color='GREEN',ext_in=[],ext_out=[],before=[],after=[],shell=False,scan=None): |
| params={'vars':vars or[],'color':color,'name':name,'ext_in':Utils.to_list(ext_in),'ext_out':Utils.to_list(ext_out),'before':Utils.to_list(before),'after':Utils.to_list(after),'shell':shell,'scan':scan,} |
| if isinstance(func,str): |
| params['run_str']=func |
| else: |
| params['run']=func |
| cls=type(Task)(name,(Task,),params) |
| global classes |
| classes[name]=cls |
| return cls |
| def always_run(cls): |
| old=cls.runnable_status |
| def always(self): |
| ret=old(self) |
| if ret==SKIP_ME: |
| ret=RUN_ME |
| return ret |
| cls.runnable_status=always |
| return cls |
| def update_outputs(cls): |
| old_post_run=cls.post_run |
| def post_run(self): |
| old_post_run(self) |
| for node in self.outputs: |
| node.sig=Utils.h_file(node.abspath()) |
| self.generator.bld.task_sigs[node.abspath()]=self.uid() |
| cls.post_run=post_run |
| old_runnable_status=cls.runnable_status |
| def runnable_status(self): |
| status=old_runnable_status(self) |
| if status!=RUN_ME: |
| return status |
| try: |
| bld=self.generator.bld |
| prev_sig=bld.task_sigs[self.uid()] |
| if prev_sig==self.signature(): |
| for x in self.outputs: |
| if not x.sig or bld.task_sigs[x.abspath()]!=self.uid(): |
| return RUN_ME |
| return SKIP_ME |
| except KeyError: |
| pass |
| except IndexError: |
| pass |
| except AttributeError: |
| pass |
| return RUN_ME |
| cls.runnable_status=runnable_status |
| return cls |