REGRESSION (r194660): Legacy WebProcess crashes in ChildProcess::initializeSandbox()
[WebKit-https.git] / Tools / BuildSlaveSupport / built-product-archive
1 #!/usr/bin/python
2
3 # Copyright (C) 2009, 2015 Apple Inc.  All rights reserved.
4 # Copyright (C) 2012 Google Inc. All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # 1.  Redistributions of source code must retain the above copyright
11 #     notice, this list of conditions and the following disclaimer. 
12 # 2.  Redistributions in binary form must reproduce the above copyright
13 #     notice, this list of conditions and the following disclaimer in the
14 #     documentation and/or other materials provided with the distribution. 
15 #
16 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
17 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 import optparse
28 import os
29 import shutil
30 import subprocess
31 import sys
32 import zipfile
33
34 _configurationBuildDirectory = None
35 _topLevelBuildDirectory = None
36
37
38 def main():
39     parser = optparse.OptionParser("usage: %prog [options] [action]")
40     parser.add_option("--platform", dest="platform")
41     parser.add_option("--debug", action="store_const", const="debug", dest="configuration")
42     parser.add_option("--release", action="store_const", const="release", dest="configuration")
43
44     options, (action, ) = parser.parse_args()
45     if not options.platform:
46         parser.error("Platform is required")
47         return 1
48     if not options.configuration:
49         parser.error("Configuration is required")
50         return 1
51     if action not in ('archive', 'extract'):
52         parser.error("Action is required")
53         return 1
54
55     genericPlatform = options.platform.split('-', 1)[0]
56     determineWebKitBuildDirectories(genericPlatform, options.platform, options.configuration)
57     if not _topLevelBuildDirectory:
58         print >> sys.stderr, 'Could not determine top-level build directory'
59         return 1
60     if not _configurationBuildDirectory:
61         print >> sys.stderr, 'Could not determine configuration-specific build directory'
62         return 1
63
64     if action == 'archive':
65         return archiveBuiltProduct(options.configuration, genericPlatform, options.platform)
66     else:
67         return extractBuiltProduct(options.configuration, genericPlatform)
68
69
70 def webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform='', returnTopLevelDirectory=False):
71     if fullPlatform.startswith('ios-simulator'):
72         platform = 'ios-simulator'
73     elif platform == 'ios':
74         platform = 'device'
75     command = ['perl', os.path.join(os.path.dirname(__file__), '..', 'Scripts', 'webkit-build-directory'), '--' + platform, '--' + configuration]
76     if returnTopLevelDirectory:
77         command += ['--top-level']
78     else:
79         command += ['--configuration']
80     return subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0].strip()
81
82
83 def determineWebKitBuildDirectories(platform, fullPlatform, configuration):
84     global _configurationBuildDirectory
85     global _topLevelBuildDirectory
86     _configurationBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform)
87     _topLevelBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform, returnTopLevelDirectory=True)
88     return _topLevelBuildDirectory
89
90
91 def removeDirectoryIfExists(thinDirectory):
92     if os.path.isdir(thinDirectory):
93         shutil.rmtree(thinDirectory)
94
95
96 def copyBuildFiles(source, destination, patterns):
97     shutil.copytree(source, destination, ignore=shutil.ignore_patterns(*patterns))
98
99
100 def createZipManually(directoryToZip, archiveFile):
101     archiveZip = zipfile.ZipFile(archiveFile, "w")
102
103     for path, dirNames, fileNames in os.walk(directoryToZip):
104         relativePath = os.path.relpath(path, directoryToZip)
105         for fileName in fileNames:
106             archiveZip.write(os.path.join(path, fileName), os.path.join(relativePath, fileName))
107
108     archiveZip.close()
109
110
111 def createZip(directoryToZip, configuration, embedParentDirectoryNameOnDarwin=False):
112     archiveDir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "WebKitBuild"))
113     archiveFile = os.path.join(archiveDir, configuration + ".zip")
114
115     try:
116         os.unlink(archiveFile)
117     except OSError, e:
118         if e.errno != 2:
119             raise
120
121     if sys.platform == 'darwin':
122         command = ['ditto', '-c', '-k', '--sequesterRsrc']
123         if embedParentDirectoryNameOnDarwin:
124             command += ['--keepParent']
125         command += [directoryToZip, archiveFile]
126         return subprocess.call(command)
127     elif sys.platform == 'cygwin':
128         return subprocess.call(["zip", "-r", archiveFile, "bin32"], cwd=directoryToZip)
129     elif sys.platform == 'win32':
130         createZipManually(directoryToZip, archiveFile)
131         return 0
132     elif sys.platform.startswith('linux'):
133         return subprocess.call(["zip", "-y", "-r", archiveFile, "."], cwd=directoryToZip)
134
135
136 def archiveBuiltProduct(configuration, platform, fullPlatform):
137     assert platform in ('mac', 'win', 'gtk', 'efl', 'ios')
138
139     if fullPlatform.startswith('ios-simulator'):
140         # We need to include in the archive the Mac tool, LayoutTestRelay, to run layout tests in the iOS simulator.
141         combinedDirectory = os.path.join(_topLevelBuildDirectory, 'combined-mac-and-ios')
142         removeDirectoryIfExists(combinedDirectory)
143         os.makedirs(combinedDirectory)
144
145         if subprocess.call(['/bin/cp', '-pR', _configurationBuildDirectory, combinedDirectory]):
146             return 1
147
148         macBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, 'mac')
149         destinationDirectory = os.path.join(combinedDirectory, os.path.relpath(macBuildDirectory, _topLevelBuildDirectory))
150         os.makedirs(destinationDirectory)
151         for filename in ['LayoutTestRelay', 'LayoutTestRelay.dSYM']:
152             sourceFile = os.path.join(macBuildDirectory, filename)
153             if not os.path.exists(sourceFile):
154                 continue
155             if subprocess.call(['/bin/cp', '-pR', sourceFile, destinationDirectory]):
156                 return 1
157
158         if createZip(combinedDirectory, configuration):
159             return 1
160         shutil.rmtree(combinedDirectory)
161     elif platform in ('mac', 'ios'):
162         return createZip(_configurationBuildDirectory, configuration, embedParentDirectoryNameOnDarwin=True)
163     elif platform == 'win':
164         # FIXME: We shouldn't hardcode the assumption of a 32-bit build. See <https://bugs.webkit.org/show_bug.cgi?id=149715>.
165         binDirectory = os.path.join(_configurationBuildDirectory, 'bin32')
166         thinDirectory = os.path.join(_configurationBuildDirectory, 'thin')
167         thinBinDirectory = os.path.join(thinDirectory, "bin32")
168
169         removeDirectoryIfExists(thinDirectory)
170         copyBuildFiles(binDirectory, thinBinDirectory, ['*.ilk'])
171         if createZip(thinDirectory, configuration):
172             return 1
173
174         shutil.rmtree(thinDirectory)
175
176     elif platform == 'gtk' or platform == 'efl':
177         thinDirectory = os.path.join(_configurationBuildDirectory, 'thin')
178
179         removeDirectoryIfExists(thinDirectory)
180         os.mkdir(thinDirectory)
181
182         neededDirectories = ["bin", "lib"]
183
184         # On GTK we need this for the WebKit GObject DOM bindings API break test
185         if platform == 'gtk':
186             neededDirectories.append("DerivedSources/webkitdom")
187             webkitdomFile = os.path.join(_configurationBuildDirectory, 'gtkdoc-webkitdom.cfg')
188             if subprocess.call('cp %s %s' % (webkitdomFile, thinDirectory), shell=True):
189                 return 1
190
191         for dirname in neededDirectories:
192             fromDir = os.path.join(_configurationBuildDirectory, dirname, '.')
193             toDir = os.path.join(thinDirectory, dirname)
194             os.makedirs(toDir)
195             if subprocess.call('cp -R %s %s' % (fromDir, toDir), shell=True):
196                 return 1
197
198         for root, dirs, files in os.walk(thinDirectory, topdown=False):
199             for name in files:
200                 if name.endswith(".o"):
201                     os.remove(os.path.join(root, name))
202
203         if createZip(thinDirectory, configuration):
204             return 1
205
206 def unzipArchive(directoryToExtractTo, configuration):
207     archiveDir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "WebKitBuild"))
208     assert os.path.isdir(archiveDir)
209     archiveFile = os.path.join(archiveDir, configuration + ".zip")
210
211     if sys.platform == 'darwin':
212         if subprocess.call(["ditto", "-x", "-k", archiveFile, directoryToExtractTo]):
213             return 1
214     elif sys.platform == 'cygwin' or sys.platform.startswith('linux'):
215         if subprocess.call(["unzip", "-o", archiveFile], cwd=directoryToExtractTo):
216             return 1
217     elif sys.platform == 'win32':
218         archive = zipfile.ZipFile(archiveFile, "r")
219         archive.extractall(directoryToExtractTo)
220         archive.close()
221
222     os.unlink(archiveFile)
223
224
225 def extractBuiltProduct(configuration, platform):
226     assert platform in ('mac', 'win', 'gtk', 'efl', 'ios')
227
228     archiveFile = os.path.join(_topLevelBuildDirectory, configuration + '.zip')
229
230     removeDirectoryIfExists(_configurationBuildDirectory)
231     os.makedirs(_configurationBuildDirectory)
232
233     if platform in ('mac', 'ios'):
234         return unzipArchive(_topLevelBuildDirectory, configuration)
235     elif platform == 'win' or platform == 'gtk' or platform == 'efl':
236         print 'Extracting', _configurationBuildDirectory
237         return unzipArchive(_configurationBuildDirectory, configuration)
238
239
240 if __name__ == '__main__':
241     sys.exit(main())