Merged revisions 1675-1736 via svnmerge from
[scons.git] / test / BuildDir / errors.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 Validate successful handling of errors when duplicating things in
29 BuildDirs.  This is generally when the BuildDir, or something in it,
30 is read-only.
31 """
32
33 import os
34 import os.path
35 import stat
36 import sys
37 import TestSCons
38
39 test = TestSCons.TestSCons()
40
41 for dir in ['normal', 'ro-dir', 'ro-SConscript', 'ro-src']:
42     test.subdir(dir, [dir, 'src'])
43
44     test.write([dir, 'SConstruct'], """\
45 import os.path
46 BuildDir('build', 'src')
47 SConscript(os.path.join('build', 'SConscript'))
48 """) 
49
50     test.write([dir, 'src', 'SConscript'], """\
51 def fake_scan(node, env, target):
52     # We fetch the contents here, even though we don't examine
53     # them, because get_contents() will cause the engine to
54     # try to link the source file into the build directory,
55     # potentially triggering a different failure case.
56     contents = node.get_contents()
57     return []
58
59 def cat(env, source, target):
60     target = str(target[0])
61     source = map(str, source)
62     f = open(target, "wb")
63     for src in source:
64         f.write(open(src, "rb").read())
65     f.close()
66
67 env = Environment(BUILDERS={'Build':Builder(action=cat)},
68                   SCANNERS=[Scanner(fake_scan, skeys = ['.in'])])
69
70 # Do some Node test operations to ensure no side-effects cause failures
71 File('file.in').exists()
72 File('file.in').is_derived()
73 File('file.in').is_pseudo_derived()
74
75 env.Build('file.out', 'file.in')
76 """)
77
78     test.write([dir, 'src', 'file.in'], dir + "/src/file.in\n")
79
80 # Just verify that the normal case works fine.
81 test.run(chdir = 'normal', arguments = ".")
82
83 test.fail_test(test.read(['normal', 'build', 'file.out']) != "normal/src/file.in\n")
84
85 # Verify the error when the BuildDir itself is read-only.  Don't bother
86 # to test this on Windows, because the ACL (I think) still allows the
87 # owner to create files in the directory even when it's read-only.
88 if sys.platform != 'win32':
89     dir = os.path.join('ro-dir', 'build')
90     test.subdir(dir)
91     os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR)
92
93     test.run(chdir = 'ro-dir',
94              arguments = ".",
95              status = 2,
96              stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.\n" % os.path.join('src', 'SConscript'))
97
98 # Verify the error when the SConscript file within the BuildDir is
99 # read-only.  Note that we have to make the directory read-only too,
100 # because otherwise our duplication logic will be able to unlink
101 # the read-only SConscript and duplicate the new one.
102 dir = os.path.join('ro-SConscript', 'build')
103 test.subdir(dir)
104 SConscript = test.workpath(dir, 'SConscript')
105 test.write(SConscript, '')
106 os.chmod(SConscript, os.stat(SConscript)[stat.ST_MODE] & ~stat.S_IWUSR)
107 f = open(SConscript, 'r')
108 os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR)
109
110 test.run(chdir = 'ro-SConscript',
111          arguments = ".",
112          status = 2,
113          stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.\n" % os.path.join('src', 'SConscript'))
114
115 os.chmod('ro-SConscript', os.stat('ro-SConscript')[stat.ST_MODE] | stat.S_IWUSR)
116 f.close()
117
118 test.run(chdir = 'ro-SConscript',
119          arguments = ".",
120          status = 2,
121          stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.\n" % os.path.join('src', 'SConscript'))
122
123 # Verify the error when the source file within the BuildDir is
124 # read-only.  Note that we have to make the directory read-only too,
125 # because otherwise our duplication logic will be able to unlink the
126 # read-only source file and duplicate the new one.  But because we've
127 # made the BuildDir read-only, we must also create a writable SConscript
128 # file there so it can be duplicated from the source directory.
129 dir = os.path.join('ro-src', 'build')
130 test.subdir(dir)
131 test.write([dir, 'SConscript'], '')
132 file_in = test.workpath(dir, 'file.in')
133 test.write(file_in, '')
134 os.chmod(file_in, os.stat(file_in)[stat.ST_MODE] & ~stat.S_IWUSR)
135 f = open(file_in, 'r')
136 os.chmod(dir, os.stat(dir)[stat.ST_MODE] & ~stat.S_IWUSR)
137
138 test.run(chdir = 'ro-src',
139          arguments = ".",
140          status = 2,
141          stderr = """\
142 scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.
143 """ % (os.path.join('src', 'file.in')))
144
145 test.run(chdir = 'ro-src',
146          arguments = "-k .",
147          status = 2,
148          stderr = """\
149 scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.
150 """ % (os.path.join('src', 'file.in')))
151
152 f.close()
153
154 # ensure that specifying multiple source directories for one
155 # build directory results in an error message, rather
156 # than just silently failing.
157 test.subdir('duplicate', ['duplicate', 'src1'], ['duplicate', 'src2'])
158
159 duplicate_SConstruct_path = test.workpath('duplicate', 'SConstruct')
160
161 test.write(duplicate_SConstruct_path, """\
162 BuildDir('build', 'src1')
163 BuildDir('build', 'src2')
164 """)
165
166 expect_stderr = """
167 scons: *** 'build' already has a source directory: 'src1'.
168 """ + test.python_file_line(duplicate_SConstruct_path, 2)
169
170 test.run(chdir = 'duplicate',
171          arguments = ".",
172          status = 2,
173          stderr = expect_stderr)
174
175 test.pass_test()