~elementary-apps/noise/trunk

« back to all changes in this revision

Viewing changes to .waf-1.6.2-ad4cc42bd7d347f7e283789e711b993f/waflib/Task.py

  • Committer: Scott Ringwelski
  • Date: 2011-02-10 21:30:53 UTC
  • Revision ID: sgringwe@mtu.edu-20110210213053-d3c7mnexeref3cwj
sexy icons, sexy waf

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# encoding: utf-8
 
3
# WARNING! All changes made to this file will be lost!
 
4
 
 
5
import sys
 
6
if sys.hexversion < 0x020400f0: from sets import Set as set
 
7
import os,shutil,re,tempfile
 
8
from waflib import Utils,Logs,Errors
 
9
NOT_RUN=0
 
10
MISSING=1
 
11
CRASHED=2
 
12
EXCEPTION=3
 
13
SKIPPED=8
 
14
SUCCESS=9
 
15
ASK_LATER=-1
 
16
SKIP_ME=-2
 
17
RUN_ME=-3
 
18
COMPILE_TEMPLATE_SHELL='''
 
19
def f(tsk):
 
20
        env = tsk.env
 
21
        gen = tsk.generator
 
22
        bld = gen.bld
 
23
        wd = getattr(tsk, 'cwd', None)
 
24
        p = env.get_flat
 
25
        tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s
 
26
        return tsk.exec_command(cmd, cwd=wd, env=env.env or None)
 
27
'''
 
28
COMPILE_TEMPLATE_NOSHELL='''
 
29
def f(tsk):
 
30
        env = tsk.env
 
31
        gen = tsk.generator
 
32
        bld = gen.bld
 
33
        wd = getattr(tsk, 'cwd', None)
 
34
        def to_list(xx):
 
35
                if isinstance(xx, str): return [xx]
 
36
                return xx
 
37
        tsk.last_cmd = lst = []
 
38
        %s
 
39
        lst = [x for x in lst if x]
 
40
        return tsk.exec_command(lst, cwd=wd, env=env.env or None)
 
41
'''
 
42
def cache_outputs(cls):
 
43
        m1=cls.run
 
44
        def run(self):
 
45
                bld=self.generator.bld
 
46
                if bld.cache_global and not bld.nocache:
 
47
                        if self.can_retrieve_cache():
 
48
                                return 0
 
49
                return m1(self)
 
50
        cls.run=run
 
51
        m2=cls.post_run
 
52
        def post_run(self):
 
53
                bld=self.generator.bld
 
54
                ret=m2(self)
 
55
                if bld.cache_global and not bld.nocache:
 
56
                        self.put_files_cache()
 
57
                return ret
 
58
        cls.post_run=post_run
 
59
        return cls
 
60
classes={}
 
61
class store_task_type(type):
 
62
        def __init__(cls,name,bases,dict):
 
63
                super(store_task_type,cls).__init__(name,bases,dict)
 
64
                name=cls.__name__
 
65
                if name.endswith('_task'):
 
66
                        name=name.replace('_task','')
 
67
                if name!='evil'and name!='TaskBase':
 
68
                        global classes
 
69
                        if getattr(cls,'run_str',None):
 
70
                                (f,dvars)=compile_fun(cls.run_str,cls.shell)
 
71
                                cls.hcode=cls.run_str
 
72
                                cls.run_str=None
 
73
                                cls.run=f
 
74
                                cls.vars.extend(dvars)
 
75
                        elif getattr(cls,'run',None)and not'hcode'in cls.__dict__:
 
76
                                cls.hcode=Utils.h_fun(cls.run)
 
77
                        if not getattr(cls,'nocache',None):
 
78
                                cls=cache_outputs(cls)
 
79
                        classes[name]=cls
 
80
evil=store_task_type('evil',(object,),{})
 
81
class TaskBase(evil):
 
82
        color='GREEN'
 
83
        ext_in=[]
 
84
        ext_out=[]
 
85
        before=[]
 
86
        after=[]
 
87
        hcode=''
 
88
        def __init__(self,*k,**kw):
 
89
                self.hasrun=NOT_RUN
 
90
                try:
 
91
                        self.generator=kw['generator']
 
92
                except KeyError:
 
93
                        self.generator=self
 
94
        def __repr__(self):
 
95
                return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,'fun','')))
 
96
        def __str__(self):
 
97
                if hasattr(self,'fun'):
 
98
                        return'executing: %s\n'%self.fun.__name__
 
99
                return self.__class__.__name__+'\n'
 
100
        def __hash__(self):
 
101
                return id(self)
 
102
        def exec_command(self,cmd,**kw):
 
103
                bld=self.generator.bld
 
104
                try:
 
105
                        if not kw.get('cwd',None):
 
106
                                kw['cwd']=bld.cwd
 
107
                except AttributeError:
 
108
                        bld.cwd=kw['cwd']=bld.variant_dir
 
109
                return bld.exec_command(cmd,**kw)
 
110
        def runnable_status(self):
 
111
                return RUN_ME
 
112
        def process(self):
 
113
                m=self.master
 
114
                if m.stop:
 
115
                        m.out.put(self)
 
116
                        return
 
117
                try:
 
118
                        del self.generator.bld.task_sigs[self.uid()]
 
119
                except:
 
120
                        pass
 
121
                self.generator.bld.returned_tasks.append(self)
 
122
                self.log_display(self.generator.bld)
 
123
                try:
 
124
                        ret=self.run()
 
125
                except Exception ,e:
 
126
                        self.err_msg=Utils.ex_stack()
 
127
                        self.hasrun=EXCEPTION
 
128
                        m.error_handler(self)
 
129
                        m.out.put(self)
 
130
                        return
 
131
                if ret:
 
132
                        self.err_code=ret
 
133
                        self.hasrun=CRASHED
 
134
                else:
 
135
                        try:
 
136
                                self.post_run()
 
137
                        except Errors.WafError:
 
138
                                pass
 
139
                        except Exception:
 
140
                                self.err_msg=Utils.ex_stack()
 
141
                                self.hasrun=EXCEPTION
 
142
                        else:
 
143
                                self.hasrun=SUCCESS
 
144
                if self.hasrun!=SUCCESS:
 
145
                        m.error_handler(self)
 
146
                m.out.put(self)
 
147
        def run(self):
 
148
                if hasattr(self,'fun'):
 
149
                        return self.fun(self)
 
150
                return 0
 
151
        def post_run(self):
 
152
                pass
 
153
        def log_display(self,bld):
 
154
                bld.to_log(self.display())
 
155
        def display(self):
 
156
                col1=Logs.colors(self.color)
 
157
                col2=Logs.colors.NORMAL
 
158
                if self.generator.bld.progress_bar==1:
 
159
                        return self.generator.bld.progress_line(len(self.generator.bld.returned_tasks),self.position[1],col1,col2)
 
160
                if self.generator.bld.progress_bar==2:
 
161
                        ela=str(self.generator.bld.timer)
 
162
                        try:
 
163
                                ins=','.join([n.name for n in self.inputs])
 
164
                        except AttributeError:
 
165
                                ins=''
 
166
                        try:
 
167
                                outs=','.join([n.name for n in self.outputs])
 
168
                        except AttributeError:
 
169
                                outs=''
 
170
                        return'|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n'%(self.position[1],len(self.generator.bld.returned_tasks),ins,outs,ela)
 
171
                s=str(self)
 
172
                if not s:
 
173
                        return None
 
174
                total=self.position[1]
 
175
                n=len(str(total))
 
176
                fs='[%%%dd/%%%dd] %%s%%s%%s'%(n,n)
 
177
                return fs%(len(self.generator.bld.returned_tasks),self.position[1],col1,s,col2)
 
178
        def attr(self,att,default=None):
 
179
                ret=getattr(self,att,self)
 
180
                if ret is self:return getattr(self.__class__,att,default)
 
181
                return ret
 
182
        def hash_constraints(self):
 
183
                cls=self.__class__
 
184
                tup=(str(cls.before),str(cls.after),str(cls.ext_in),str(cls.ext_out),cls.__name__,cls.hcode)
 
185
                h=hash(tup)
 
186
                return h
 
187
        def format_error(self):
 
188
                msg=getattr(self,'last_cmd','')
 
189
                if getattr(self,"err_msg",None):
 
190
                        return self.err_msg
 
191
                elif self.hasrun==CRASHED:
 
192
                        try:
 
193
                                return' -> task failed (exit status %r): %r\n%r'%(self.err_code,self,msg)
 
194
                        except AttributeError:
 
195
                                return' -> task failed: %r\n%r'%(self,msg)
 
196
                elif self.hasrun==MISSING:
 
197
                        return' -> missing files: %r\n%r'%(self,msg)
 
198
                else:
 
199
                        return'?'
 
200
class Task(TaskBase):
 
201
        vars=[]
 
202
        shell=False
 
203
        def __init__(self,*k,**kw):
 
204
                TaskBase.__init__(self,*k,**kw)
 
205
                self.env=kw['env']
 
206
                self.inputs=[]
 
207
                self.outputs=[]
 
208
                self.dep_nodes=[]
 
209
                self.run_after=set([])
 
210
        def __str__(self):
 
211
                env=self.env
 
212
                src_str=' '.join([a.nice_path(env)for a in self.inputs])
 
213
                tgt_str=' '.join([a.nice_path(env)for a in self.outputs])
 
214
                if self.outputs:sep=' -> '
 
215
                else:sep=''
 
216
                return'%s: %s%s%s\n'%(self.__class__.__name__.replace('_task',''),src_str,sep,tgt_str)
 
217
        def __repr__(self):
 
218
                return"".join(['\n\t{task %r: '%id(self),self.__class__.__name__," ",",".join([x.name for x in self.inputs])," -> ",",".join([x.name for x in self.outputs]),'}'])
 
219
        def uid(self):
 
220
                try:
 
221
                        return self.uid_
 
222
                except AttributeError:
 
223
                        m=Utils.md5()
 
224
                        up=m.update
 
225
                        up(self.__class__.__name__)
 
226
                        for x in self.inputs+self.outputs:
 
227
                                up(x.abspath())
 
228
                        self.uid_=m.digest()
 
229
                        return self.uid_
 
230
        def set_inputs(self,inp):
 
231
                if isinstance(inp,list):self.inputs+=inp
 
232
                else:self.inputs.append(inp)
 
233
        def set_outputs(self,out):
 
234
                if isinstance(out,list):self.outputs+=out
 
235
                else:self.outputs.append(out)
 
236
        def set_run_after(self,task):
 
237
                assert isinstance(task,TaskBase)
 
238
                self.run_after.add(task)
 
239
        def signature(self):
 
240
                try:return self.cache_sig
 
241
                except AttributeError:pass
 
242
                self.m=Utils.md5()
 
243
                self.m.update(self.hcode)
 
244
                self.sig_explicit_deps()
 
245
                self.sig_vars()
 
246
                if self.scan:
 
247
                        try:
 
248
                                imp_sig=self.sig_implicit_deps()
 
249
                        except Errors.TaskRescan:
 
250
                                return self.signature()
 
251
                ret=self.cache_sig=self.m.digest()
 
252
                return ret
 
253
        def runnable_status(self):
 
254
                for t in self.run_after:
 
255
                        if not t.hasrun:
 
256
                                return ASK_LATER
 
257
                env=self.env
 
258
                bld=self.generator.bld
 
259
                try:
 
260
                        new_sig=self.signature()
 
261
                except Errors.TaskNotReady:
 
262
                        return ASK_LATER
 
263
                key=self.uid()
 
264
                try:
 
265
                        prev_sig=bld.task_sigs[key]
 
266
                except KeyError:
 
267
                        Logs.debug("task: task %r must run as it was never run before or the task code changed"%self)
 
268
                        return RUN_ME
 
269
                for node in self.outputs:
 
270
                        try:
 
271
                                if node.sig!=new_sig:
 
272
                                        return RUN_ME
 
273
                        except AttributeError:
 
274
                                Logs.debug("task: task %r must run as the output nodes do not exist"%self)
 
275
                                return RUN_ME
 
276
                if new_sig!=prev_sig:
 
277
                        return RUN_ME
 
278
                return SKIP_ME
 
279
        def post_run(self):
 
280
                bld=self.generator.bld
 
281
                env=self.env
 
282
                sig=self.signature()
 
283
                for node in self.outputs:
 
284
                        try:
 
285
                                os.stat(node.abspath())
 
286
                        except OSError:
 
287
                                self.hasrun=MISSING
 
288
                                self.err_msg='-> missing file: %r'%node.abspath()
 
289
                                raise Errors.WafError(self.err_msg)
 
290
                        node.sig=sig
 
291
                bld.task_sigs[self.uid()]=self.cache_sig
 
292
        def sig_explicit_deps(self):
 
293
                bld=self.generator.bld
 
294
                upd=self.m.update
 
295
                for x in self.inputs+self.dep_nodes:
 
296
                        try:
 
297
                                upd(x.get_bld_sig())
 
298
                        except(AttributeError,TypeError):
 
299
                                raise Errors.WafError('Missing node signature for %r (required by %r)'%(x,self))
 
300
                if bld.deps_man:
 
301
                        additional_deps=bld.deps_man
 
302
                        for x in self.inputs+self.outputs:
 
303
                                try:
 
304
                                        d=additional_deps[id(x)]
 
305
                                except KeyError:
 
306
                                        continue
 
307
                                for v in d:
 
308
                                        if isinstance(v,bld.root.__class__):
 
309
                                                try:
 
310
                                                        v=v.get_bld_sig()
 
311
                                                except AttributeError:
 
312
                                                        raise Errors.WafError('Missing node signature for %r (required by %r)'%(v,self))
 
313
                                        elif hasattr(v,'__call__'):
 
314
                                                v=v()
 
315
                                        upd(v)
 
316
                return self.m.digest()
 
317
        def sig_vars(self):
 
318
                bld=self.generator.bld
 
319
                env=self.env
 
320
                upd=self.m.update
 
321
                act_sig=bld.hash_env_vars(env,self.__class__.vars)
 
322
                upd(act_sig)
 
323
                dep_vars=getattr(self,'dep_vars',None)
 
324
                if dep_vars:
 
325
                        upd(bld.hash_env_vars(env,dep_vars))
 
326
                return self.m.digest()
 
327
        scan=None
 
328
        def sig_implicit_deps(self):
 
329
                bld=self.generator.bld
 
330
                key=self.uid()
 
331
                prev=bld.task_sigs.get((key,'imp'),[])
 
332
                if prev:
 
333
                        try:
 
334
                                if prev==self.compute_sig_implicit_deps():
 
335
                                        return prev
 
336
                        except IOError:
 
337
                                pass
 
338
                        del bld.task_sigs[(key,'imp')]
 
339
                        raise Errors.TaskRescan('rescan')
 
340
                (nodes,names)=self.scan()
 
341
                if Logs.verbose:
 
342
                        Logs.debug('deps: scanner for %s returned %s %s'%(str(self),str(nodes),str(names)))
 
343
                bld.node_deps[key]=nodes
 
344
                bld.raw_deps[key]=names
 
345
                self.are_implicit_nodes_ready()
 
346
                bld.task_sigs[(key,'imp')]=sig=self.compute_sig_implicit_deps()
 
347
                return sig
 
348
        def compute_sig_implicit_deps(self):
 
349
                upd=self.m.update
 
350
                bld=self.generator.bld
 
351
                env=self.env
 
352
                self.are_implicit_nodes_ready()
 
353
                try:
 
354
                        for k in bld.node_deps.get(self.uid(),[]):
 
355
                                upd(k.get_bld_sig())
 
356
                except AttributeError:
 
357
                        nodes=[]
 
358
                        for k in bld.node_deps.get(self.uid(),[]):
 
359
                                try:
 
360
                                        k.get_bld_sig()
 
361
                                except AttributeError:
 
362
                                        nodes.append(k)
 
363
                        raise Errors.WafError('Missing node signature for %r (for implicit dependencies %r)'%(nodes,self))
 
364
                return self.m.digest()
 
365
        def are_implicit_nodes_ready(self):
 
366
                bld=self.generator.bld
 
367
                try:
 
368
                        cache=bld.dct_implicit_nodes
 
369
                except:
 
370
                        bld.dct_implicit_nodes=cache={}
 
371
                try:
 
372
                        dct=cache[bld.cur]
 
373
                except KeyError:
 
374
                        dct=cache[bld.cur]={}
 
375
                        for tsk in bld.cur_tasks:
 
376
                                for x in tsk.outputs:
 
377
                                        dct[x]=tsk
 
378
                modified=False
 
379
                for x in bld.node_deps.get(self.uid(),[]):
 
380
                        if x in dct:
 
381
                                self.run_after.add(dct[x])
 
382
                                modified=True
 
383
                if modified:
 
384
                        for tsk in self.run_after:
 
385
                                if not tsk.hasrun:
 
386
                                        raise Errors.TaskNotReady('not ready')
 
387
        def can_retrieve_cache(self):
 
388
                if not getattr(self,'outputs',None):
 
389
                        return None
 
390
                env=self.env
 
391
                sig=self.signature()
 
392
                ssig=Utils.to_hex(sig)
 
393
                dname=os.path.join(self.generator.bld.cache_global,ssig)
 
394
                try:
 
395
                        t1=os.stat(dname).st_mtime
 
396
                except OSError:
 
397
                        return None
 
398
                for node in self.outputs:
 
399
                        orig=os.path.join(dname,node.name)
 
400
                        try:
 
401
                                shutil.copy2(orig,node.abspath())
 
402
                                os.utime(orig,None)
 
403
                        except(OSError,IOError):
 
404
                                Logs.debug('task: failed retrieving file')
 
405
                                return None
 
406
                try:
 
407
                        t2=os.stat(dname).st_mtime
 
408
                except OSError:
 
409
                        return None
 
410
                if t1!=t2:
 
411
                        return None
 
412
                for node in self.outputs:
 
413
                        node.sig=sig
 
414
                        if self.generator.bld.progress_bar<1:
 
415
                                self.generator.bld.to_log('restoring from cache %r\n'%node.abspath())
 
416
                self.cached=True
 
417
                return True
 
418
        def put_files_cache(self):
 
419
                if getattr(self,'cached',None):
 
420
                        return None
 
421
                sig=self.signature()
 
422
                ssig=Utils.to_hex(sig)
 
423
                dname=os.path.join(self.generator.bld.cache_global,ssig)
 
424
                tmpdir=tempfile.mkdtemp(prefix=self.generator.bld.cache_global+os.sep+'waf')
 
425
                try:
 
426
                        shutil.rmtree(dname)
 
427
                except:
 
428
                        pass
 
429
                try:
 
430
                        for node in self.outputs:
 
431
                                dest=os.path.join(tmpdir,node.name)
 
432
                                shutil.copy2(node.abspath(),dest)
 
433
                except(OSError,IOError):
 
434
                        try:
 
435
                                shutil.rmtree(tmpdir)
 
436
                        except:
 
437
                                pass
 
438
                else:
 
439
                        try:
 
440
                                os.rename(tmpdir,dname)
 
441
                        except OSError:
 
442
                                try:
 
443
                                        shutil.rmtree(tmpdir)
 
444
                                except:
 
445
                                        pass
 
446
                        else:
 
447
                                try:
 
448
                                        os.chmod(dname,Utils.O755)
 
449
                                except:
 
450
                                        pass
 
451
def is_before(t1,t2):
 
452
        to_list=Utils.to_list
 
453
        for k in to_list(t2.ext_in):
 
454
                if k in to_list(t1.ext_out):
 
455
                        return 1
 
456
        if t1.__class__.__name__ in to_list(t2.after):
 
457
                return 1
 
458
        if t2.__class__.__name__ in to_list(t1.before):
 
459
                return 1
 
460
        return 0
 
461
def set_file_constraints(tasks):
 
462
        ins=Utils.defaultdict(set)
 
463
        outs=Utils.defaultdict(set)
 
464
        for x in tasks:
 
465
                for a in getattr(x,'inputs',[])+getattr(x,'dep_nodes',[]):
 
466
                        ins[id(a)].add(x)
 
467
                for a in getattr(x,'outputs',[]):
 
468
                        outs[id(a)].add(x)
 
469
        links=set(ins.keys()).intersection(outs.keys())
 
470
        for k in links:
 
471
                for a in ins[k]:
 
472
                        a.run_after.update(outs[k])
 
473
def set_precedence_constraints(tasks):
 
474
        cstr_groups=Utils.defaultdict(list)
 
475
        for x in tasks:
 
476
                h=x.hash_constraints()
 
477
                cstr_groups[h].append(x)
 
478
        keys=list(cstr_groups.keys())
 
479
        maxi=len(keys)
 
480
        for i in range(maxi):
 
481
                t1=cstr_groups[keys[i]][0]
 
482
                for j in range(i+1,maxi):
 
483
                        t2=cstr_groups[keys[j]][0]
 
484
                        if is_before(t1,t2):
 
485
                                a=i
 
486
                                b=j
 
487
                        elif is_before(t2,t1):
 
488
                                a=j
 
489
                                b=i
 
490
                        else:
 
491
                                continue
 
492
                        for x in cstr_groups[keys[b]]:
 
493
                                x.run_after.update(cstr_groups[keys[a]])
 
494
def funex(c):
 
495
        dc={}
 
496
        exec(c,dc)
 
497
        return dc['f']
 
498
reg_act=re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})",re.M)
 
499
def compile_fun_shell(line):
 
500
        extr=[]
 
501
        def repl(match):
 
502
                g=match.group
 
503
                if g('dollar'):return"$"
 
504
                elif g('backslash'):return'\\\\'
 
505
                elif g('subst'):extr.append((g('var'),g('code')));return"%s"
 
506
                return None
 
507
        line=reg_act.sub(repl,line)or line
 
508
        parm=[]
 
509
        dvars=[]
 
510
        app=parm.append
 
511
        for(var,meth)in extr:
 
512
                if var=='SRC':
 
513
                        if meth:app('tsk.inputs%s'%meth)
 
514
                        else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.inputs])')
 
515
                elif var=='TGT':
 
516
                        if meth:app('tsk.outputs%s'%meth)
 
517
                        else:app('" ".join([a.path_from(bld.bldnode) for a in tsk.outputs])')
 
518
                elif meth:
 
519
                        if meth.startswith(':'):
 
520
                                app('" ".join([env[%r] %% x for x in env[%r]])'%(var,meth[1:]))
 
521
                                dvars.extend([var,meth[1:]])
 
522
                        else:
 
523
                                app('%s%s'%(var,meth))
 
524
                else:
 
525
                        if not var in dvars:dvars.append(var)
 
526
                        app("p('%s')"%var)
 
527
        if parm:parm="%% (%s) "%(',\n\t\t'.join(parm))
 
528
        else:parm=''
 
529
        c=COMPILE_TEMPLATE_SHELL%(line,parm)
 
530
        Logs.debug('action: %s'%c)
 
531
        return(funex(c),dvars)
 
532
def compile_fun_noshell(line):
 
533
        extr=[]
 
534
        def repl(match):
 
535
                g=match.group
 
536
                if g('dollar'):return"$"
 
537
                elif g('subst'):extr.append((g('var'),g('code')));return"<<|@|>>"
 
538
                return None
 
539
        line2=reg_act.sub(repl,line)
 
540
        params=line2.split('<<|@|>>')
 
541
        assert(extr)
 
542
        buf=[]
 
543
        dvars=[]
 
544
        app=buf.append
 
545
        for x in range(len(extr)):
 
546
                params[x]=params[x].strip()
 
547
                if params[x]:
 
548
                        app("lst.extend(%r)"%params[x].split())
 
549
                (var,meth)=extr[x]
 
550
                if var=='SRC':
 
551
                        if meth:app('lst.append(tsk.inputs%s)'%meth)
 
552
                        else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])")
 
553
                elif var=='TGT':
 
554
                        if meth:app('lst.append(tsk.outputs%s)'%meth)
 
555
                        else:app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])")
 
556
                elif meth:
 
557
                        if meth.startswith(':'):
 
558
                                app('lst.extend([env[%r] %% x for x in env[%r]])'%(var,meth[1:]))
 
559
                                dvars.extend([var,meth[1:]])
 
560
                        else:
 
561
                                app('lst.extend(gen.to_list(%s%s))'%(var,meth))
 
562
                else:
 
563
                        app('lst.extend(to_list(env[%r]))'%var)
 
564
                        if not var in dvars:dvars.append(var)
 
565
        if extr:
 
566
                if params[-1]:
 
567
                        app("lst.extend(%r)"%params[-1].split())
 
568
        fun=COMPILE_TEMPLATE_NOSHELL%"\n\t".join(buf)
 
569
        Logs.debug('action: %s'%fun)
 
570
        return(funex(fun),dvars)
 
571
def compile_fun(line,shell=False):
 
572
        if line.find('<')>0 or line.find('>')>0 or line.find('&&')>0:
 
573
                shell=True
 
574
        if shell:
 
575
                return compile_fun_shell(line)
 
576
        else:
 
577
                return compile_fun_noshell(line)
 
578
def task_factory(name,func=None,vars=[],color='GREEN',ext_in=[],ext_out=[],before=[],after=[],shell=False,scan=None):
 
579
        params={'vars':vars,'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,}
 
580
        if isinstance(func,str):
 
581
                params['run_str']=func
 
582
        else:
 
583
                params['run']=func
 
584
        cls=type(Task)(name,(Task,),params)
 
585
        global classes
 
586
        classes[name]=cls
 
587
        return cls
 
588
def always_run(cls):
 
589
        old=cls.runnable_status
 
590
        def always(self):
 
591
                ret=old(self)
 
592
                if ret==SKIP_ME:
 
593
                        ret=RUN_ME
 
594
                return ret
 
595
        cls.runnable_status=always
 
596
        return cls
 
597
def update_outputs(cls):
 
598
        old_post_run=cls.post_run
 
599
        def post_run(self):
 
600
                old_post_run(self)
 
601
                for node in self.outputs:
 
602
                        node.sig=Utils.h_file(node.abspath())
 
603
        cls.post_run=post_run
 
604
        old_runnable_status=cls.runnable_status
 
605
        def runnable_status(self):
 
606
                status=old_runnable_status(self)
 
607
                if status!=RUN_ME:
 
608
                        return status
 
609
                try:
 
610
                        bld=self.generator.bld
 
611
                        new_sig=self.signature()
 
612
                        prev_sig=bld.task_sigs[self.uid()]
 
613
                        if prev_sig==new_sig:
 
614
                                for x in self.outputs:
 
615
                                        if not x.sig:
 
616
                                                return RUN_ME
 
617
                                return SKIP_ME
 
618
                except KeyError:
 
619
                        pass
 
620
                except IndexError:
 
621
                        pass
 
622
                return RUN_ME
 
623
        cls.runnable_status=runnable_status
 
624
        return cls