[GTK][EFL] Avoid using a thin directory to create the built product on the archive...
[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 errno
28 import optparse
29 import os
30 import shutil
31 import subprocess
32 import sys
33 import zipfile
34
35 _configurationBuildDirectory = None
36 _topLevelBuildDirectory = None
37
38
39 def main():
40     parser = optparse.OptionParser("usage: %prog [options] [action]")
41     parser.add_option("--platform", dest="platform")
42     parser.add_option("--debug", action="store_const", const="debug", dest="configuration")
43     parser.add_option("--release", action="store_const", const="release", dest="configuration")
44
45     options, (action, ) = parser.parse_args()
46     if not options.platform:
47         parser.error("Platform is required")
48         return 1
49     if not options.configuration:
50         parser.error("Configuration is required")
51         return 1
52     if action not in ('archive', 'extract'):
53         parser.error("Action is required")
54         return 1
55
56     genericPlatform = options.platform.split('-', 1)[0]
57     determineWebKitBuildDirectories(genericPlatform, options.platform, options.configuration)
58     if not _topLevelBuildDirectory:
59         print >> sys.stderr, 'Could not determine top-level build directory'
60         return 1
61     if not _configurationBuildDirectory:
62         print >> sys.stderr, 'Could not determine configuration-specific build directory'
63         return 1
64
65     if action == 'archive':
66         return archiveBuiltProduct(options.configuration, genericPlatform, options.platform)
67     else:
68         return extractBuiltProduct(options.configuration, genericPlatform)
69
70
71 def webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform='', returnTopLevelDirectory=False):
72     if fullPlatform.startswith('ios-simulator'):
73         platform = 'ios-simulator'
74     elif platform == 'ios':
75         platform = 'device'
76     command = ['perl', os.path.join(os.path.dirname(__file__), '..', 'Scripts', 'webkit-build-directory'), '--' + platform, '--' + configuration]
77     if returnTopLevelDirectory:
78         command += ['--top-level']
79     else:
80         command += ['--configuration']
81     return subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0].strip()
82
83
84 def determineWebKitBuildDirectories(platform, fullPlatform, configuration):
85     global _configurationBuildDirectory
86     global _topLevelBuildDirectory
87     _configurationBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform)
88     _topLevelBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, platform, fullPlatform, returnTopLevelDirectory=True)
89     return _topLevelBuildDirectory
90
91
92 def removeDirectoryIfExists(thinDirectory):
93     if os.path.isdir(thinDirectory):
94         shutil.rmtree(thinDirectory)
95
96
97 def copyBuildFiles(source, destination, patterns):
98     shutil.copytree(source, destination, ignore=shutil.ignore_patterns(*patterns))
99
100
101 def createZipFromList(listToZip, configuration, excludePattern=None):
102     archiveDir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'WebKitBuild'))
103     archiveFile = os.path.join(archiveDir, configuration + '.zip')
104
105     try:
106         os.unlink(archiveFile)
107     except OSError, e:
108         if e.errno != errno.ENOENT:
109             raise
110
111     if sys.platform.startswith('linux'):
112         zipCommand = ['zip', '-y', '-r', archiveFile] + listToZip
113         if excludePattern:
114             zipCommand += ['-x', excludePattern]
115         return subprocess.call(zipCommand, cwd=_configurationBuildDirectory)
116
117     raise NotImplementedError('Unsupported platform: {platform}'.format(platform=sys.platform))
118
119
120 def createZipManually(directoryToZip, archiveFile):
121     archiveZip = zipfile.ZipFile(archiveFile, "w")
122
123     for path, dirNames, fileNames in os.walk(directoryToZip):
124         relativePath = os.path.relpath(path, directoryToZip)
125         for fileName in fileNames:
126             archiveZip.write(os.path.join(path, fileName), os.path.join(relativePath, fileName))
127
128     archiveZip.close()
129
130
131 def createZip(directoryToZip, configuration, embedParentDirectoryNameOnDarwin=False):
132     archiveDir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "WebKitBuild"))
133     archiveFile = os.path.join(archiveDir, configuration + ".zip")
134
135     try:
136         os.unlink(archiveFile)
137     except OSError, e:
138         if e.errno != errno.ENOENT:
139             raise
140
141     if sys.platform == 'darwin':
142         command = ['ditto', '-c', '-k', '--sequesterRsrc']
143         if embedParentDirectoryNameOnDarwin:
144             command += ['--keepParent']
145         command += [directoryToZip, archiveFile]
146         return subprocess.call(command)
147     elif sys.platform == 'cygwin':
148         return subprocess.call(["zip", "-r", archiveFile, "bin32"], cwd=directoryToZip)
149     elif sys.platform == 'win32':
150         createZipManually(directoryToZip, archiveFile)
151         return 0
152     elif sys.platform.startswith('linux'):
153         return subprocess.call(["zip", "-y", "-r", archiveFile, "."], cwd=directoryToZip)
154
155
156 def dirContainsdwo(directory):
157     sourcedir = os.path.join(_configurationBuildDirectory, directory)
158     for root, dirs, files in os.walk(sourcedir, topdown=False):
159         for name in files:
160             if name.endswith(".dwo"):
161                 return True
162     return False
163
164
165 def archiveBuiltProduct(configuration, platform, fullPlatform):
166     assert platform in ('mac', 'win', 'gtk', 'efl', 'ios')
167
168     if fullPlatform.startswith('ios-simulator'):
169         # We need to include in the archive the Mac tool, LayoutTestRelay, to run layout tests in the iOS simulator.
170         combinedDirectory = os.path.join(_topLevelBuildDirectory, 'combined-mac-and-ios')
171         removeDirectoryIfExists(combinedDirectory)
172         os.makedirs(combinedDirectory)
173
174         if subprocess.call(['/bin/cp', '-pR', _configurationBuildDirectory, combinedDirectory]):
175             return 1
176
177         macBuildDirectory = webkitBuildDirectoryForConfigurationAndPlatform(configuration, 'mac')
178         destinationDirectory = os.path.join(combinedDirectory, os.path.relpath(macBuildDirectory, _topLevelBuildDirectory))
179         os.makedirs(destinationDirectory)
180         for filename in ['LayoutTestRelay', 'LayoutTestRelay.dSYM']:
181             sourceFile = os.path.join(macBuildDirectory, filename)
182             if not os.path.exists(sourceFile):
183                 continue
184             if subprocess.call(['/bin/cp', '-pR', sourceFile, destinationDirectory]):
185                 return 1
186
187         if createZip(combinedDirectory, configuration):
188             return 1
189         shutil.rmtree(combinedDirectory)
190     elif platform in ('mac', 'ios'):
191         return createZip(_configurationBuildDirectory, configuration, embedParentDirectoryNameOnDarwin=True)
192     elif platform == 'win':
193         # FIXME: We shouldn't hardcode the assumption of a 32-bit build. See <https://bugs.webkit.org/show_bug.cgi?id=149715>.
194         binDirectory = os.path.join(_configurationBuildDirectory, 'bin32')
195         thinDirectory = os.path.join(_configurationBuildDirectory, 'thin')
196         thinBinDirectory = os.path.join(thinDirectory, "bin32")
197
198         removeDirectoryIfExists(thinDirectory)
199         copyBuildFiles(binDirectory, thinBinDirectory, ['*.ilk'])
200         if createZip(thinDirectory, configuration):
201             return 1
202
203         shutil.rmtree(thinDirectory)
204
205     elif platform == 'gtk' or platform == 'efl':
206         # On GTK+/EFL we don't need the intermediate step of creating a thinDirectory
207         # to be compressed in a ZIP file, because we can create the ZIP directly.
208         # This is faster and requires less disk resources.
209         neededDirectories = ['bin', 'lib']
210         # When debug fission is enabled the directories below contain dwo files
211         # with the debug information needed to generate backtraces with GDB.
212         for objectDir in ['Tools', 'Source']:
213             if dirContainsdwo(objectDir):
214                 neededDirectories.append(objectDir)
215
216         if createZipFromList(neededDirectories, configuration, excludePattern='*.o'):
217             return 1
218
219 def unzipArchive(directoryToExtractTo, configuration):
220     archiveDir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "WebKitBuild"))
221     assert os.path.isdir(archiveDir)
222     archiveFile = os.path.join(archiveDir, configuration + ".zip")
223
224     if sys.platform == 'darwin':
225         if subprocess.call(["ditto", "-x", "-k", archiveFile, directoryToExtractTo]):
226             return 1
227     elif sys.platform == 'cygwin' or sys.platform.startswith('linux'):
228         if subprocess.call(["unzip", "-o", archiveFile], cwd=directoryToExtractTo):
229             return 1
230     elif sys.platform == 'win32':
231         archive = zipfile.ZipFile(archiveFile, "r")
232         archive.extractall(directoryToExtractTo)
233         archive.close()
234
235     os.unlink(archiveFile)
236
237
238 def extractBuiltProduct(configuration, platform):
239     assert platform in ('mac', 'win', 'gtk', 'efl', 'ios')
240
241     archiveFile = os.path.join(_topLevelBuildDirectory, configuration + '.zip')
242
243     removeDirectoryIfExists(_configurationBuildDirectory)
244     os.makedirs(_configurationBuildDirectory)
245
246     if platform in ('mac', 'ios'):
247         return unzipArchive(_topLevelBuildDirectory, configuration)
248     elif platform == 'win' or platform == 'gtk' or platform == 'efl':
249         print 'Extracting', _configurationBuildDirectory
250         return unzipArchive(_configurationBuildDirectory, configuration)
251
252
253 if __name__ == '__main__':
254     sys.exit(main())