-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathcommand.py
131 lines (114 loc) · 4.04 KB
/
command.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import re
import subprocess
# import feature, taskgen_method, before_method, task_gen
from waflib import TaskGen, Node, Task, Utils, Build, Options, Logs, Task
debug = Logs.debug
error = Logs.error
import shellcmd
#shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy
shellcmd.debug = debug
arg_rx = re.compile(r"(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})", re.M)
class command_task(Task.Task):
color = "BLUE"
def __init__(self, env, generator):
Task.Task.__init__(self, env=env, normal=1, generator=generator)
def __str__(self):
"string to display to the user"
env = self.env
src_str = ' '.join([a.bldpath() for a in self.inputs])
tgt_str = ' '.join([a.bldpath() for a in self.outputs])
if self.outputs:
sep = ' -> '
else:
sep = ''
pipeline = shellcmd.Pipeline()
pipeline.parse(self.generator.command)
cmd = pipeline.get_abbreviated_command()
return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str)
def _subst_arg(self, arg, direction, namespace):
"""
@param arg: the command argument (or stdin/stdout/stderr) to substitute
@param direction: direction of the argument: 'in', 'out', or None
"""
def repl(match):
if match.group('dollar'):
return "$"
elif match.group('subst'):
var = match.group('var')
code = match.group('code')
result = eval(var+code, namespace)
if isinstance(result, Node.Node):
if var == 'TGT':
return result.get_bld().abspath()
elif var == 'SRC':
return result.srcpath()
else:
raise ValueError("Bad subst variable %r" % var)
elif result is self.inputs:
if len(self.inputs) == 1:
return result[0].srcpath()
else:
raise ValueError("${SRC} requested but have multiple sources; which one?")
elif result is self.outputs:
if len(self.outputs) == 1:
return result[0].get_bld().abspath()
else:
raise ValueError("${TGT} requested but have multiple targets; which one?")
elif isinstance(result, list):
assert len(result) == 1
return result[0]
else:
return result
return None
return arg_rx.sub(repl, arg)
def run(self):
pipeline = shellcmd.Pipeline()
pipeline.parse(self.generator.command)
namespace = self.env.get_merged_dict()
if self.generator.variables is not None:
namespace.update(self.generator.variables)
namespace.update(env=self.env, SRC=self.inputs, TGT=self.outputs)
for cmd in pipeline.pipeline:
if isinstance(cmd, shellcmd.Command):
if isinstance(cmd.stdin, str):
cmd.stdin = self._subst_arg(cmd.stdin, 'in', namespace)
if isinstance(cmd.stdout, str):
cmd.stdout = self._subst_arg(cmd.stdout, 'out', namespace)
if isinstance(cmd.stderr, str):
cmd.stderr = self._subst_arg(cmd.stderr, 'out', namespace)
for argI in range(len(cmd.argv)):
cmd.argv[argI] = self._subst_arg(cmd.argv[argI], None, namespace)
if cmd.env_vars is not None:
env_vars = dict()
for name, value in cmd.env_vars.items():
env_vars[name] = self._subst_arg(value, None, namespace)
cmd.env_vars = env_vars
elif isinstance(cmd, shellcmd.Chdir):
cmd.dir = self._subst_arg(cmd.dir, None, namespace)
return pipeline.run(verbose=(Options.options.verbose > 0))
@TaskGen.taskgen_method
@TaskGen.feature('command')
def init_command(self):
Utils.def_attrs(self,
# other variables that can be used in the command: ${VARIABLE}
variables = None,
rule='')
@TaskGen.feature('command')
@TaskGen.after_method('process_rule')
def apply_command(self):
#self.meths.remove('apply_core')
# create the task
task = self.create_task('command')
setattr(task, "dep_vars", getattr(self, "dep_vars", None))
# process the sources
inputs = []
for node in self.source:
inputs.append(node)
task.set_inputs(inputs)
task.set_outputs([self.path.find_or_declare(tgt) for tgt in self.to_list(self.target)])
self.source = ''
#Task.file_deps = Task.extract_deps
# class command_taskgen(task_gen):
# def __init__(self, *k, **kw):
# task_gen.__init__(self, *k, **kw)
# self.features.append('command')