]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/test/toolset-mock/src/MockProgram.py
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / tools / build / test / toolset-mock / src / MockProgram.py
CommitLineData
11fdf7f2
TL
1# Copyright 2017 Steven Watanabe
2#
3# Distributed under the Boost Software License, Version 1.0.
4# (See accompanying file LICENSE_1_0.txt or copy at
5# http://www.boost.org/LICENSE_1_0.txt)
6
92f5a8d4
TL
7from __future__ import print_function
8
11fdf7f2
TL
9import sys
10import os
11import re
20effc67 12import fnmatch
11fdf7f2
TL
13
14# Represents a sequence of arguments that must appear
15# in a fixed order.
16class ordered:
17 def __init__(self, *args):
18 self.args = args
19 def match(self, command_line, pos, outputs):
20 for p in self.args:
21 res = try_match(command_line, pos, p, outputs)
22 if res is None:
23 return
24 pos = res
25 return pos
26
27# Represents a sequence of arguments that can appear
28# in any order.
29class unordered:
30 def __init__(self, *args):
31 self.args = list(args)
32 def match(self, command_line, pos, outputs):
33 unmatched = self.args[:]
34 while len(unmatched) > 0:
35 res = try_match_one(command_line, pos, unmatched, outputs)
36 if res is None:
37 return
38 pos = res
39 return pos
40
41# Represents a single input file.
42# If id is set, then the file must have been created
43# by a prior use of output_file.
44# If source is set, then the file must be that source file.
45class input_file:
46 def __init__(self, id=None, source=None):
47 assert((id is None) ^ (source is None))
48 self.id = id
49 self.source = source
50 def check(self, path):
51 if path.startswith("-"):
52 return
53 if self.id is not None:
54 try:
55 with open(path, "r") as f:
56 data = f.read()
57 if data == make_file_contents(self.id):
58 return True
59 else:
60 return
61 except:
62 return
63 elif self.source is not None:
64 if self.source == path:
65 return True
66 else:
67 return
68 assert(False)
69 def match(self, command_line, pos, outputs):
70 if self.check(command_line[pos]):
71 return pos + 1
72
73# Matches an output file.
74# If the full pattern is matched, The
75# file will be created.
76class output_file:
77 def __init__(self, id):
78 self.id = id
79 def match(self, command_line, pos, outputs):
80 if command_line[pos].startswith("-"):
81 return
82 outputs.append((command_line[pos], self.id))
83 return pos + 1
84
20effc67
TL
85class arg_file:
86 def __init__(self, id):
87 self.id = id
88 def match(self, command_line, pos, outputs):
89 if command_line[pos].startswith("-"):
90 return
91 if fnmatch.fnmatch(command_line[pos], self.id):
92 return pos + 1
93 else:
94 return
95
11fdf7f2
TL
96# Matches the directory containing an input_file
97class target_path(object):
98 def __init__(self, id):
99 self.tester = input_file(id=id)
100 def match(self, command_line, pos, outputs):
101 arg = command_line[pos]
102 if arg.startswith("-"):
103 return
104 try:
105 for path in os.listdir(arg):
106 if self.tester.check(os.path.join(arg, path)):
107 return pos + 1
108 except:
92f5a8d4 109 return
11fdf7f2
TL
110
111# Matches a single argument, which is composed of a prefix and a path
112# for example arguments of the form -ofilename.
113class arg(object):
114 def __init__(self, prefix, a):
115 # The prefix should be a string, a should be target_path or input_file.
116 self.prefix = prefix
117 self.a = a
118 def match(self, command_line, pos, outputs):
119 s = command_line[pos]
120 if s.startswith(self.prefix) and try_match([s[len(self.prefix):]], 0, self.a, outputs) == 1:
121 return pos + 1
122
123# Given a file id, returns a string that will be
124# written to the file to allow it to be recognized.
125def make_file_contents(id):
126 return id
127
128# Matches a single pattern from a list.
129# If it succeeds, the matching pattern
130# is removed from the list.
131# Returns the index after the end of the match
132def try_match_one(command_line, pos, patterns, outputs):
133 for p in patterns:
134 tmp = outputs[:]
135 res = try_match(command_line, pos, p, tmp)
136 if res is not None:
137 outputs[:] = tmp
138 patterns.remove(p)
139 return res
140
141# returns the end of the match if any
142def try_match(command_line, pos, pattern, outputs):
143 if pos == len(command_line):
144 return
145 elif type(pattern) is str:
146 if pattern == command_line[pos]:
147 return pos + 1
148 else:
149 return pattern.match(command_line, pos, outputs)
150
151known_patterns = []
152program_name = None
153
154# Registers a command
155# The arguments should be a sequence of:
156# str, ordered, unordered, arg, input_file, output_file, target_path
157# kwarg: stdout is text that will be printed on success.
158def command(*args, **kwargs):
159 global known_patterns
160 global program_name
161 stdout = kwargs.get("stdout", None)
162 pattern = ordered(*args)
163 known_patterns += [(pattern, stdout)]
164 if program_name is None:
165 program_name = args[0]
166 else:
167 assert(program_name == args[0])
168
169# Use this to filter the recognized commands, based on the properties
170# passed to b2.
171def allow_properties(*args):
172 try:
173 return all(a in os.environ["B2_PROPERTIES"].split(" ") for a in args)
174 except KeyError:
175 return True
176
177# Use this in the stdout argument of command to print the command
178# for running another script.
179def script(name):
180 return os.path.join(os.path.dirname(__file__), "bin", re.sub('\.py$', '', name))
181
182def match(command_line):
183 for (p, stdout) in known_patterns:
184 outputs = []
185 if try_match(command_line, 0, p, outputs) == len(command_line):
186 return (stdout, outputs)
187
188# Every mock program should call this after setting up all the commands.
189def main():
190 command_line = [program_name] + sys.argv[1:]
191 result = match(command_line)
192 if result is not None:
193 (stdout, outputs) = result
194 if stdout is not None:
92f5a8d4 195 print(stdout)
11fdf7f2
TL
196 for (file,id) in outputs:
197 with open(file, "w") as f:
198 f.write(make_file_contents(id))
199 exit(0)
200 else:
20effc67 201 print("ERROR on command: %s"%(" ".join(command_line)))
11fdf7f2
TL
202 exit(1)
203
204# file should be the name of a file in the same directory
205# as this. Must be called after verify_setup
206def verify_file(filename):
207 global known_files
208 if filename not in known_files:
209 known_files.add(filename)
210 srcdir = os.path.dirname(__file__)
211 execfile(os.path.join(srcdir, filename), {})
212
213def verify_setup():
214 """Override the behavior of most module components
215 in order to detect whether they are being used correctly."""
216 global main
217 global allow_properties
218 global output_file
219 global input_file
220 global target_path
221 global script
222 global command
223 global verify_errors
224 global output_ids
225 global input_ids
226 global known_files
227 def allow_properties(*args):
228 return True
229 def main():
230 pass
231 def output_file(id):
232 global output_ids
233 global verify_error
234 if id in output_ids:
235 verify_error("duplicate output_file: %s" % id)
236 output_ids.add(id)
237 def input_file(id=None, source=None):
238 if id is not None:
239 input_ids.add(id)
240 def target_path(id):
241 input_ids.add(id)
242 def script(filename):
243 verify_file(filename)
244 def command(*args, **kwargs):
245 pass
246 verify_errors = []
247 output_ids = set()
248 input_ids = set()
249 known_files = set()
250
251def verify_error(message):
252 global verify_errors
253 verify_errors += [message]
254
255def verify_finalize():
256 for id in input_ids:
257 if not id in output_ids:
258 verify_error("Input file does not exist: %s" % id)
259 for error in verify_errors:
92f5a8d4 260 print("error: %s" % error)
11fdf7f2
TL
261 if len(verify_errors) != 0:
262 return 1
263 else:
264 return 0
265
266def verify():
267 srcdir = os.path.dirname(__file__)
268 if srcdir == '':
269 srcdir = '.'
270 verify_setup()
271 for f in os.listdir(srcdir):
272 if re.match(r"(gcc|clang|darwin|intel)-.*\.py", f):
273 verify_file(f)
274 exit(verify_finalize())