1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/python/mozbuild/mozpack/test/test_manifests.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,352 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +from __future__ import unicode_literals 1.9 + 1.10 +import os 1.11 + 1.12 +import mozunit 1.13 + 1.14 +from mozpack.copier import ( 1.15 + FileCopier, 1.16 + FileRegistry, 1.17 +) 1.18 +from mozpack.manifests import ( 1.19 + InstallManifest, 1.20 +) 1.21 +from mozpack.test.test_files import TestWithTmpDir 1.22 + 1.23 + 1.24 +class TestInstallManifest(TestWithTmpDir): 1.25 + def test_construct(self): 1.26 + m = InstallManifest() 1.27 + self.assertEqual(len(m), 0) 1.28 + 1.29 + def test_adds(self): 1.30 + m = InstallManifest() 1.31 + m.add_symlink('s_source', 's_dest') 1.32 + m.add_copy('c_source', 'c_dest') 1.33 + m.add_required_exists('e_dest') 1.34 + m.add_optional_exists('o_dest') 1.35 + m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest') 1.36 + m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest') 1.37 + m.add_preprocess('p_source', 'p_dest', 'p_source.pp') 1.38 + 1.39 + self.assertEqual(len(m), 7) 1.40 + self.assertIn('s_dest', m) 1.41 + self.assertIn('c_dest', m) 1.42 + self.assertIn('p_dest', m) 1.43 + self.assertIn('e_dest', m) 1.44 + self.assertIn('o_dest', m) 1.45 + 1.46 + with self.assertRaises(ValueError): 1.47 + m.add_symlink('s_other', 's_dest') 1.48 + 1.49 + with self.assertRaises(ValueError): 1.50 + m.add_copy('c_other', 'c_dest') 1.51 + 1.52 + with self.assertRaises(ValueError): 1.53 + m.add_preprocess('p_other', 'p_dest', 'p_other.pp') 1.54 + 1.55 + with self.assertRaises(ValueError): 1.56 + m.add_required_exists('e_dest') 1.57 + 1.58 + with self.assertRaises(ValueError): 1.59 + m.add_optional_exists('o_dest') 1.60 + 1.61 + with self.assertRaises(ValueError): 1.62 + m.add_pattern_symlink('ps_base', 'ps/*', 'ps_dest') 1.63 + 1.64 + with self.assertRaises(ValueError): 1.65 + m.add_pattern_copy('pc_base', 'pc/**', 'pc_dest') 1.66 + 1.67 + def _get_test_manifest(self): 1.68 + m = InstallManifest() 1.69 + m.add_symlink(self.tmppath('s_source'), 's_dest') 1.70 + m.add_copy(self.tmppath('c_source'), 'c_dest') 1.71 + m.add_preprocess(self.tmppath('p_source'), 'p_dest', self.tmppath('p_source.pp'), '#', {'FOO':'BAR', 'BAZ':'QUX'}) 1.72 + m.add_required_exists('e_dest') 1.73 + m.add_optional_exists('o_dest') 1.74 + m.add_pattern_symlink('ps_base', '*', 'ps_dest') 1.75 + m.add_pattern_copy('pc_base', '**', 'pc_dest') 1.76 + 1.77 + return m 1.78 + 1.79 + def test_serialization(self): 1.80 + m = self._get_test_manifest() 1.81 + 1.82 + p = self.tmppath('m') 1.83 + m.write(path=p) 1.84 + self.assertTrue(os.path.isfile(p)) 1.85 + 1.86 + with open(p, 'rb') as fh: 1.87 + c = fh.read() 1.88 + 1.89 + self.assertEqual(c.count('\n'), 8) 1.90 + 1.91 + lines = c.splitlines() 1.92 + self.assertEqual(len(lines), 8) 1.93 + 1.94 + self.assertEqual(lines[0], '4') 1.95 + 1.96 + m2 = InstallManifest(path=p) 1.97 + self.assertEqual(m, m2) 1.98 + p2 = self.tmppath('m2') 1.99 + m2.write(path=p2) 1.100 + 1.101 + with open(p2, 'rb') as fh: 1.102 + c2 = fh.read() 1.103 + 1.104 + self.assertEqual(c, c2) 1.105 + 1.106 + def test_populate_registry(self): 1.107 + m = self._get_test_manifest() 1.108 + r = FileRegistry() 1.109 + m.populate_registry(r) 1.110 + 1.111 + self.assertEqual(len(r), 5) 1.112 + self.assertEqual(r.paths(), ['c_dest', 'e_dest', 'o_dest', 'p_dest', 's_dest']) 1.113 + 1.114 + def test_pattern_expansion(self): 1.115 + source = self.tmppath('source') 1.116 + os.mkdir(source) 1.117 + os.mkdir('%s/base' % source) 1.118 + os.mkdir('%s/base/foo' % source) 1.119 + 1.120 + with open('%s/base/foo/file1' % source, 'a'): 1.121 + pass 1.122 + 1.123 + with open('%s/base/foo/file2' % source, 'a'): 1.124 + pass 1.125 + 1.126 + m = InstallManifest() 1.127 + m.add_pattern_symlink('%s/base' % source, '**', 'dest') 1.128 + 1.129 + c = FileCopier() 1.130 + m.populate_registry(c) 1.131 + self.assertEqual(c.paths(), ['dest/foo/file1', 'dest/foo/file2']) 1.132 + 1.133 + def test_or(self): 1.134 + m1 = self._get_test_manifest() 1.135 + orig_length = len(m1) 1.136 + m2 = InstallManifest() 1.137 + m2.add_symlink('s_source2', 's_dest2') 1.138 + m2.add_copy('c_source2', 'c_dest2') 1.139 + 1.140 + m1 |= m2 1.141 + 1.142 + self.assertEqual(len(m2), 2) 1.143 + self.assertEqual(len(m1), orig_length + 2) 1.144 + 1.145 + self.assertIn('s_dest2', m1) 1.146 + self.assertIn('c_dest2', m1) 1.147 + 1.148 + def test_copier_application(self): 1.149 + dest = self.tmppath('dest') 1.150 + os.mkdir(dest) 1.151 + 1.152 + to_delete = self.tmppath('dest/to_delete') 1.153 + with open(to_delete, 'a'): 1.154 + pass 1.155 + 1.156 + with open(self.tmppath('s_source'), 'wt') as fh: 1.157 + fh.write('symlink!') 1.158 + 1.159 + with open(self.tmppath('c_source'), 'wt') as fh: 1.160 + fh.write('copy!') 1.161 + 1.162 + with open(self.tmppath('p_source'), 'wt') as fh: 1.163 + fh.write('#define FOO 1\npreprocess!') 1.164 + 1.165 + with open(self.tmppath('dest/e_dest'), 'a'): 1.166 + pass 1.167 + 1.168 + with open(self.tmppath('dest/o_dest'), 'a'): 1.169 + pass 1.170 + 1.171 + m = self._get_test_manifest() 1.172 + c = FileCopier() 1.173 + m.populate_registry(c) 1.174 + result = c.copy(dest) 1.175 + 1.176 + self.assertTrue(os.path.exists(self.tmppath('dest/s_dest'))) 1.177 + self.assertTrue(os.path.exists(self.tmppath('dest/c_dest'))) 1.178 + self.assertTrue(os.path.exists(self.tmppath('dest/p_dest'))) 1.179 + self.assertTrue(os.path.exists(self.tmppath('dest/e_dest'))) 1.180 + self.assertTrue(os.path.exists(self.tmppath('dest/o_dest'))) 1.181 + self.assertFalse(os.path.exists(to_delete)) 1.182 + 1.183 + with open(self.tmppath('dest/s_dest'), 'rt') as fh: 1.184 + self.assertEqual(fh.read(), 'symlink!') 1.185 + 1.186 + with open(self.tmppath('dest/c_dest'), 'rt') as fh: 1.187 + self.assertEqual(fh.read(), 'copy!') 1.188 + 1.189 + with open(self.tmppath('dest/p_dest'), 'rt') as fh: 1.190 + self.assertEqual(fh.read(), 'preprocess!') 1.191 + 1.192 + self.assertEqual(result.updated_files, set(self.tmppath(p) for p in ( 1.193 + 'dest/s_dest', 'dest/c_dest', 'dest/p_dest'))) 1.194 + self.assertEqual(result.existing_files, 1.195 + set([self.tmppath('dest/e_dest'), self.tmppath('dest/o_dest')])) 1.196 + self.assertEqual(result.removed_files, {to_delete}) 1.197 + self.assertEqual(result.removed_directories, set()) 1.198 + 1.199 + def test_preprocessor(self): 1.200 + manifest = self.tmppath('m') 1.201 + deps = self.tmppath('m.pp') 1.202 + dest = self.tmppath('dest') 1.203 + include = self.tmppath('p_incl') 1.204 + 1.205 + with open(include, 'wt') as fh: 1.206 + fh.write('#define INCL\n') 1.207 + time = os.path.getmtime(include) - 3 1.208 + os.utime(include, (time, time)) 1.209 + 1.210 + with open(self.tmppath('p_source'), 'wt') as fh: 1.211 + fh.write('#ifdef FOO\n#if BAZ == QUX\nPASS1\n#endif\n#endif\n') 1.212 + fh.write('#ifdef DEPTEST\nPASS2\n#endif\n') 1.213 + fh.write('#include p_incl\n#ifdef INCLTEST\nPASS3\n#endif\n') 1.214 + time = os.path.getmtime(self.tmppath('p_source')) - 3 1.215 + os.utime(self.tmppath('p_source'), (time, time)) 1.216 + 1.217 + # Create and write a manifest with the preprocessed file, then apply it. 1.218 + # This should write out our preprocessed file. 1.219 + m = InstallManifest() 1.220 + m.add_preprocess(self.tmppath('p_source'), 'p_dest', deps, '#', {'FOO':'BAR', 'BAZ':'QUX'}) 1.221 + m.write(path=manifest) 1.222 + 1.223 + m = InstallManifest(path=manifest) 1.224 + c = FileCopier() 1.225 + m.populate_registry(c) 1.226 + c.copy(dest) 1.227 + 1.228 + self.assertTrue(os.path.exists(self.tmppath('dest/p_dest'))) 1.229 + 1.230 + with open(self.tmppath('dest/p_dest'), 'rt') as fh: 1.231 + self.assertEqual(fh.read(), 'PASS1\n') 1.232 + 1.233 + # Create a second manifest with the preprocessed file, then apply it. 1.234 + # Since this manifest does not exist on the disk, there should not be a 1.235 + # dependency on it, and the preprocessed file should not be modified. 1.236 + m2 = InstallManifest() 1.237 + m2.add_preprocess(self.tmppath('p_source'), 'p_dest', deps, '#', {'DEPTEST':True}) 1.238 + c = FileCopier() 1.239 + m2.populate_registry(c) 1.240 + result = c.copy(dest) 1.241 + 1.242 + self.assertFalse(self.tmppath('dest/p_dest') in result.updated_files) 1.243 + self.assertTrue(self.tmppath('dest/p_dest') in result.existing_files) 1.244 + 1.245 + # Write out the second manifest, then load it back in from the disk. 1.246 + # This should add the dependency on the manifest file, so our 1.247 + # preprocessed file should be regenerated with the new defines. 1.248 + # We also set the mtime on the destination file back, so it will be 1.249 + # older than the manifest file. 1.250 + m2.write(path=manifest) 1.251 + time = os.path.getmtime(manifest) - 1 1.252 + os.utime(self.tmppath('dest/p_dest'), (time, time)) 1.253 + m2 = InstallManifest(path=manifest) 1.254 + c = FileCopier() 1.255 + m2.populate_registry(c) 1.256 + self.assertTrue(c.copy(dest)) 1.257 + 1.258 + with open(self.tmppath('dest/p_dest'), 'rt') as fh: 1.259 + self.assertEqual(fh.read(), 'PASS2\n') 1.260 + 1.261 + # Set the time on the manifest back, so it won't be picked up as 1.262 + # modified in the next test 1.263 + time = os.path.getmtime(manifest) - 1 1.264 + os.utime(manifest, (time, time)) 1.265 + 1.266 + # Update the contents of a file included by the source file. This should 1.267 + # cause the destination to be regenerated. 1.268 + with open(include, 'wt') as fh: 1.269 + fh.write('#define INCLTEST\n') 1.270 + 1.271 + time = os.path.getmtime(include) - 1 1.272 + os.utime(self.tmppath('dest/p_dest'), (time, time)) 1.273 + c = FileCopier() 1.274 + m2.populate_registry(c) 1.275 + self.assertTrue(c.copy(dest)) 1.276 + 1.277 + with open(self.tmppath('dest/p_dest'), 'rt') as fh: 1.278 + self.assertEqual(fh.read(), 'PASS2\nPASS3\n') 1.279 + 1.280 + def test_preprocessor_dependencies(self): 1.281 + manifest = self.tmppath('m') 1.282 + deps = self.tmppath('m.pp') 1.283 + dest = self.tmppath('dest') 1.284 + source = self.tmppath('p_source') 1.285 + destfile = self.tmppath('dest/p_dest') 1.286 + include = self.tmppath('p_incl') 1.287 + os.mkdir(dest) 1.288 + 1.289 + with open(source, 'wt') as fh: 1.290 + fh.write('#define SRC\nSOURCE\n') 1.291 + time = os.path.getmtime(source) - 3 1.292 + os.utime(source, (time, time)) 1.293 + 1.294 + with open(include, 'wt') as fh: 1.295 + fh.write('INCLUDE\n') 1.296 + time = os.path.getmtime(source) - 3 1.297 + os.utime(include, (time, time)) 1.298 + 1.299 + # Create and write a manifest with the preprocessed file. 1.300 + m = InstallManifest() 1.301 + m.add_preprocess(source, 'p_dest', deps, '#', {'FOO':'BAR', 'BAZ':'QUX'}) 1.302 + m.write(path=manifest) 1.303 + 1.304 + time = os.path.getmtime(source) - 5 1.305 + os.utime(manifest, (time, time)) 1.306 + 1.307 + # Now read the manifest back in, and apply it. This should write out 1.308 + # our preprocessed file. 1.309 + m = InstallManifest(path=manifest) 1.310 + c = FileCopier() 1.311 + m.populate_registry(c) 1.312 + self.assertTrue(c.copy(dest)) 1.313 + 1.314 + with open(destfile, 'rt') as fh: 1.315 + self.assertEqual(fh.read(), 'SOURCE\n') 1.316 + 1.317 + # Next, modify the source to #INCLUDE another file. 1.318 + with open(source, 'wt') as fh: 1.319 + fh.write('SOURCE\n#include p_incl\n') 1.320 + time = os.path.getmtime(source) - 1 1.321 + os.utime(destfile, (time, time)) 1.322 + 1.323 + # Apply the manifest, and confirm that it also reads the newly included 1.324 + # file. 1.325 + m = InstallManifest(path=manifest) 1.326 + c = FileCopier() 1.327 + m.populate_registry(c) 1.328 + c.copy(dest) 1.329 + 1.330 + with open(destfile, 'rt') as fh: 1.331 + self.assertEqual(fh.read(), 'SOURCE\nINCLUDE\n') 1.332 + 1.333 + # Set the time on the source file back, so it won't be picked up as 1.334 + # modified in the next test. 1.335 + time = os.path.getmtime(source) - 1 1.336 + os.utime(source, (time, time)) 1.337 + 1.338 + # Now, modify the include file (but not the original source). 1.339 + with open(include, 'wt') as fh: 1.340 + fh.write('INCLUDE MODIFIED\n') 1.341 + time = os.path.getmtime(include) - 1 1.342 + os.utime(destfile, (time, time)) 1.343 + 1.344 + # Apply the manifest, and confirm that the change to the include file 1.345 + # is detected. That should cause the preprocessor to run again. 1.346 + m = InstallManifest(path=manifest) 1.347 + c = FileCopier() 1.348 + m.populate_registry(c) 1.349 + c.copy(dest) 1.350 + 1.351 + with open(destfile, 'rt') as fh: 1.352 + self.assertEqual(fh.read(), 'SOURCE\nINCLUDE MODIFIED\n') 1.353 + 1.354 +if __name__ == '__main__': 1.355 + mozunit.main()