#! /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
