Update tests for now discovering dependencies on quoted commands
[scons.git] / test / explain / basic.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 """
28 Verify a lot of the basic operation of the --debug=explain option.
29 """
30
31 import os
32 import string
33 import sys
34 import TestSCons
35
36 python = TestSCons.python
37 _python_ = TestSCons._python_
38
39 test = TestSCons.TestSCons()
40
41 test.subdir(['src'], ['src', 'subdir'])
42
43 subdir_file7 = os.path.join('subdir', 'file7')
44 subdir_file7_in = os.path.join('subdir', 'file7.in')
45 subdir_file8 = os.path.join('subdir', 'file8')
46 subdir_file9 = os.path.join('subdir', 'file9')
47
48 cat_py = test.workpath('cat.py')
49 inc_aaa = test.workpath('inc', 'aaa')
50 inc_ddd = test.workpath('inc', 'ddd')
51 inc_eee = test.workpath('inc', 'eee')
52 inc_bbb_k = test.workpath('inc', 'bbb.k')
53
54
55
56 test.write(cat_py, r"""
57 import sys
58
59 def process(outfp, infp):
60     for line in infp.readlines():
61         if line[:8] == 'include ':
62             file = line[8:-1]
63             try:
64                 fp = open(file, 'rb')
65             except IOError:
66                 import os
67                 print "os.getcwd() =", os.getcwd()
68                 raise
69             process(outfp, fp)
70         else:
71             outfp.write(line)
72
73 outfp = open(sys.argv[1], 'wb')
74 for f in sys.argv[2:]:
75     if f != '-':
76         process(outfp, open(f, 'rb'))
77
78 sys.exit(0)
79 """)
80
81 SConstruct_contents = """\
82 import re
83
84 include_re = re.compile(r'^include\s+(\S+)$', re.M)
85
86 def kfile_scan(node, env, target, arg):
87     contents = node.get_text_contents()
88     includes = include_re.findall(contents)
89     return includes
90
91 kscan = Scanner(name = 'kfile',
92                 function = kfile_scan,
93                 argument = None,
94                 skeys = ['.k'])
95
96 cat = Builder(action = r'%(_python_)s %(cat_py)s $TARGET $SOURCES')
97 one_cat = Builder( action = r'%(_python_)s %(cat_py)s $TARGET ${SOURCES[0]}')
98
99 env = Environment()
100 env.Append(BUILDERS = {'Cat':cat, 'OneCat':one_cat},
101            SCANNERS = kscan)
102
103 Export("env")
104 SConscript('SConscript')
105 env.Install('../inc', 'aaa')
106 env.InstallAs('../inc/bbb.k', 'bbb.k')
107 env.Install('../inc', 'ddd')
108 env.InstallAs('../inc/eee', 'eee.in')
109 """ % locals()
110
111 test.write(['src', 'SConstruct'], SConstruct_contents)
112
113 def WriteInitialTest( valueDict ) :
114     test.write(['src', 'SConscript'], """\
115 Import("env")
116 env.Cat('file1', 'file1.in')
117 env.Cat('file2', 'file2.k')
118 env.Cat('file3', ['xxx', 'yyy', 'zzz'])
119 env.Command('file4', 'file4.in',
120              r'%(_python_)s %(cat_py)s $TARGET $FILE4FLAG $SOURCES',
121              FILE4FLAG='-')
122 env.Cat('file5', 'file5.k')
123 file6 = env.Cat('file6', 'file6.in')
124 AlwaysBuild(file6)
125 env.Cat('subdir/file7', 'subdir/file7.in')
126 env.OneCat('subdir/file8', ['subdir/file7.in', env.Value(%(test_value)s)] )
127 env.OneCat('subdir/file9', ['subdir/file7.in', env.Value(7)] )
128 """ % valueDict )
129
130 test_value = '"first"'
131 WriteInitialTest( locals() )
132
133 test.write(['src', 'aaa'], "aaa 1\n")
134 test.write(['src', 'bbb.k'], """\
135 bbb.k 1
136 include ccc
137 include ../inc/ddd
138 include ../inc/eee
139 """)
140 test.write(['src', 'ccc'], "ccc 1\n")
141 test.write(['src', 'ddd'], "ddd 1\n")
142 test.write(['src', 'eee.in'], "eee.in 1\n")
143
144 test.write(['src', 'file1.in'], "file1.in 1\n")
145
146 test.write(['src', 'file2.k'], """\
147 file2.k 1 line 1
148 include xxx
149 include yyy
150 file2.k 1 line 4
151 """)
152
153 test.write(['src', 'file4.in'], "file4.in 1\n")
154
155 test.write(['src', 'xxx'], "xxx 1\n")
156 test.write(['src', 'yyy'], "yyy 1\n")
157 test.write(['src', 'zzz'], "zzz 1\n")
158
159 test.write(['src', 'file5.k'], """\
160 file5.k 1 line 1
161 include ../inc/aaa
162 include ../inc/bbb.k
163 file5.k 1 line 4
164 """)
165
166 test.write(['src', 'file6.in'], "file6.in 1\n")
167
168 test.write(['src', 'subdir', 'file7.in'], "subdir/file7.in 1\n")
169
170
171
172 args = '--debug=explain .'
173
174
175
176 expect = test.wrap_stdout("""\
177 scons: building `file1' because it doesn't exist
178 %(_python_)s %(cat_py)s file1 file1.in
179 scons: building `file2' because it doesn't exist
180 %(_python_)s %(cat_py)s file2 file2.k
181 scons: building `file3' because it doesn't exist
182 %(_python_)s %(cat_py)s file3 xxx yyy zzz
183 scons: building `file4' because it doesn't exist
184 %(_python_)s %(cat_py)s file4 - file4.in
185 scons: building `%(inc_aaa)s' because it doesn't exist
186 Install file: "aaa" as "%(inc_aaa)s"
187 scons: building `%(inc_ddd)s' because it doesn't exist
188 Install file: "ddd" as "%(inc_ddd)s"
189 scons: building `%(inc_eee)s' because it doesn't exist
190 Install file: "eee.in" as "%(inc_eee)s"
191 scons: building `%(inc_bbb_k)s' because it doesn't exist
192 Install file: "bbb.k" as "%(inc_bbb_k)s"
193 scons: building `file5' because it doesn't exist
194 %(_python_)s %(cat_py)s file5 file5.k
195 scons: building `file6' because it doesn't exist
196 %(_python_)s %(cat_py)s file6 file6.in
197 scons: building `%(subdir_file7)s' because it doesn't exist
198 %(_python_)s %(cat_py)s %(subdir_file7)s %(subdir_file7_in)s
199 scons: building `%(subdir_file8)s' because it doesn't exist
200 %(_python_)s %(cat_py)s %(subdir_file8)s %(subdir_file7_in)s
201 scons: building `%(subdir_file9)s' because it doesn't exist
202 %(_python_)s %(cat_py)s %(subdir_file9)s %(subdir_file7_in)s
203 """ % locals())
204
205 test.run(chdir='src', arguments=args, stdout=expect)
206
207 test.must_match(['src', 'file1'], "file1.in 1\n")
208 test.must_match(['src', 'file2'], """\
209 file2.k 1 line 1
210 xxx 1
211 yyy 1
212 file2.k 1 line 4
213 """)
214 test.must_match(['src', 'file3'], "xxx 1\nyyy 1\nzzz 1\n")
215 test.must_match(['src', 'file4'], "file4.in 1\n")
216 test.must_match(['src', 'file5'], """\
217 file5.k 1 line 1
218 aaa 1
219 bbb.k 1
220 ccc 1
221 ddd 1
222 eee.in 1
223 file5.k 1 line 4
224 """)
225 test.must_match(['src', 'file6'], "file6.in 1\n")
226
227
228
229 test.write(['src', 'file1.in'], "file1.in 2\n")
230 test.write(['src', 'yyy'], "yyy 2\n")
231 test.write(['src', 'zzz'], "zzz 2\n")
232 test.write(['src', 'bbb.k'], "bbb.k 2\ninclude ccc\n")
233
234 test_value = '"second"'
235 WriteInitialTest( locals() )
236
237 expect = test.wrap_stdout("""\
238 scons: rebuilding `file1' because `file1.in' changed
239 %(_python_)s %(cat_py)s file1 file1.in
240 scons: rebuilding `file2' because `yyy' changed
241 %(_python_)s %(cat_py)s file2 file2.k
242 scons: rebuilding `file3' because:
243            `yyy' changed
244            `zzz' changed
245 %(_python_)s %(cat_py)s file3 xxx yyy zzz
246 scons: rebuilding `%(inc_bbb_k)s' because:
247            `%(inc_ddd)s' is no longer a dependency
248            `%(inc_eee)s' is no longer a dependency
249            `bbb.k' changed
250 Install file: "bbb.k" as "%(inc_bbb_k)s"
251 scons: rebuilding `file5' because `%(inc_bbb_k)s' changed
252 %(_python_)s %(cat_py)s file5 file5.k
253 scons: rebuilding `file6' because AlwaysBuild() is specified
254 %(_python_)s %(cat_py)s file6 file6.in
255 scons: rebuilding `%(subdir_file8)s' because:
256            `first' is no longer a dependency
257            `second' is a new dependency
258 %(_python_)s %(cat_py)s %(subdir_file8)s %(subdir_file7_in)s
259 """ % locals())
260
261 test.run(chdir='src', arguments=args, stdout=expect)
262
263 test.must_match(['src', 'file1'], "file1.in 2\n")
264 test.must_match(['src', 'file2'], """\
265 file2.k 1 line 1
266 xxx 1
267 yyy 2
268 file2.k 1 line 4
269 """)
270 test.must_match(['src', 'file3'], "xxx 1\nyyy 2\nzzz 2\n")
271 test.must_match(['src', 'file5'], """\
272 file5.k 1 line 1
273 aaa 1
274 bbb.k 2
275 ccc 1
276 file5.k 1 line 4
277 """)
278
279
280
281 test.write(['src', 'SConscript'], """\
282 Import("env")
283 env.Cat('file3', ['xxx', 'yyy'])
284 """)
285
286 expect = test.wrap_stdout("""\
287 scons: rebuilding `file3' because `zzz' is no longer a dependency
288 %(_python_)s %(cat_py)s file3 xxx yyy
289 """ % locals())
290
291 test.run(chdir='src', arguments=args, stdout=expect)
292
293 test.must_match(['src', 'file3'], "xxx 1\nyyy 2\n")
294
295
296
297 test.write(['src', 'SConscript'], """\
298 Import("env")
299 env.Cat('file3', ['xxx', 'yyy', 'zzz'])
300 """)
301
302 expect = test.wrap_stdout("""\
303 scons: rebuilding `file3' because `zzz' is a new dependency
304 %(_python_)s %(cat_py)s file3 xxx yyy zzz
305 """ % locals())
306
307 test.run(chdir='src', arguments=args, stdout=expect)
308
309 test.must_match(['src', 'file3'], "xxx 1\nyyy 2\nzzz 2\n")
310
311
312
313 test.write(['src', 'SConscript'], """\
314 Import("env")
315 env.Cat('file3', ['zzz', 'yyy', 'xxx'])
316 """)
317
318 expect = test.wrap_stdout("""\
319 scons: rebuilding `file3' because the dependency order changed:
320                old: ['xxx', 'yyy', 'zzz', '%(python)s']
321                new: ['zzz', 'yyy', 'xxx', '%(python)s']
322 %(_python_)s %(cat_py)s file3 zzz yyy xxx
323 """ % locals())
324
325 test.run(chdir='src', arguments=args, stdout=expect)
326
327 test.must_match(['src', 'file3'], "zzz 2\nyyy 2\nxxx 1\n")
328
329
330
331 test.write(['src', 'SConscript'], """\
332 Import("env")
333 f3 = File('file3')
334 env.Cat(f3, ['zzz', 'yyy', 'xxx'])
335 env.AddPostAction(f3, r'%(_python_)s %(cat_py)s ${TARGET}.yyy $SOURCES yyy')
336 env.AddPreAction(f3, r'%(_python_)s %(cat_py)s ${TARGET}.alt $SOURCES')
337 """ % locals())
338
339 expect = test.wrap_stdout("""\
340 scons: rebuilding `file3' because the build action changed:
341                old: %(_python_)s %(cat_py)s $TARGET $SOURCES
342                new: %(_python_)s %(cat_py)s ${TARGET}.alt $SOURCES
343                     %(_python_)s %(cat_py)s $TARGET $SOURCES
344                     %(_python_)s %(cat_py)s ${TARGET}.yyy $SOURCES yyy
345 %(_python_)s %(cat_py)s file3.alt zzz yyy xxx
346 %(_python_)s %(cat_py)s file3 zzz yyy xxx
347 %(_python_)s %(cat_py)s file3.yyy zzz yyy xxx yyy
348 """ % locals())
349
350 test.run(chdir='src', arguments=args, stdout=expect)
351
352 test.must_match(['src', 'file3'], "zzz 2\nyyy 2\nxxx 1\n")
353 test.must_match(['src', 'file3.alt'], "zzz 2\nyyy 2\nxxx 1\n")
354 test.must_match(['src', 'file3.yyy'], "zzz 2\nyyy 2\nxxx 1\nyyy 2\n")
355
356
357
358 test.write(['src', 'SConscript'], """\
359 Import("env")
360 f3 = File('file3')
361 env.Cat(f3, ['zzz', 'yyy', 'xxx'])
362 env.AddPostAction(f3, r'%(_python_)s %(cat_py)s ${TARGET}.yyy $SOURCES xxx')
363 env.AddPreAction(f3, r'%(_python_)s %(cat_py)s ${TARGET}.alt $SOURCES')
364 """ % locals())
365
366 expect = test.wrap_stdout("""\
367 scons: rebuilding `file3' because the build action changed:
368                old: %(_python_)s %(cat_py)s ${TARGET}.alt $SOURCES
369                     %(_python_)s %(cat_py)s $TARGET $SOURCES
370                     %(_python_)s %(cat_py)s ${TARGET}.yyy $SOURCES yyy
371                new: %(_python_)s %(cat_py)s ${TARGET}.alt $SOURCES
372                     %(_python_)s %(cat_py)s $TARGET $SOURCES
373                     %(_python_)s %(cat_py)s ${TARGET}.yyy $SOURCES xxx
374 %(_python_)s %(cat_py)s file3.alt zzz yyy xxx
375 %(_python_)s %(cat_py)s file3 zzz yyy xxx
376 %(_python_)s %(cat_py)s file3.yyy zzz yyy xxx xxx
377 """ % locals())
378
379 test.run(chdir='src', arguments=args, stdout=expect)
380
381 test.must_match(['src', 'file3'], "zzz 2\nyyy 2\nxxx 1\n")
382 test.must_match(['src', 'file3.alt'], "zzz 2\nyyy 2\nxxx 1\n")
383 test.must_match(['src', 'file3.yyy'], "zzz 2\nyyy 2\nxxx 1\nxxx 1\n")
384
385
386
387 test.write(['src', 'SConscript'], """\
388 Import("env")
389 env.Command('file4', 'file4.in',
390             r'%(_python_)s %(cat_py)s $TARGET $FILE4FLAG $SOURCES',
391             FILE4FLAG='')
392 """ % locals())
393
394 expect = test.wrap_stdout("""\
395 scons: rebuilding `file4' because the contents of the build action changed
396                action: %(_python_)s %(cat_py)s $TARGET $FILE4FLAG $SOURCES
397 %(_python_)s %(cat_py)s file4 file4.in
398 """ % locals())
399
400 test.run(chdir='src',arguments=args, stdout=expect)
401
402 test.must_match(['src', 'file4'], "file4.in 1\n")
403
404 test.up_to_date(chdir='src',arguments='.')
405
406
407
408 # Test the transition when you turn ON SConsignFile().
409 # This will (or might) rebuild things, but we don't care what,
410 # we just want to make sure we don't blow up.
411 test.write(['src', 'SConstruct'],
412            "SConsignFile()\n" + SConstruct_contents)
413
414 test.run(chdir='src', arguments=args)
415
416 test.up_to_date(chdir='src',arguments='.')
417
418
419
420 test.pass_test()