1 #!/usr/bin/python 2 3 # Copyright (C) 2009 Apple Inc. All rights reserved. 4 # 5 # Redistribution and use in source and binary forms, with or without 6 # modification, are permitted provided that the following conditions 7 # are met: 8 # 9 # 1. Redistributions of source code must retain the above copyright 10 # notice, this list of conditions and the following disclaimer. 11 # 2. Redistributions in binary form must reproduce the above copyright 12 # notice, this list of conditions and the following disclaimer in the 13 # documentation and/or other materials provided with the distribution. 14 # 15 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 16 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 19 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26 import optparse, os, shutil, subprocess, sys, zipfile 27 28 sourceRootDirectory = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) 29 archiveFile = os.path.join(sourceRootDirectory, "layout-test-results.zip") 30 31 def main(): 32 parser = optparse.OptionParser("usage: %prog [options] [action]") 33 parser.add_option("--platform", dest="platform") 34 parser.add_option("--debug", action="store_const", const="debug", dest="configuration") 35 parser.add_option("--release", action="store_const", const="release", dest="configuration") 36 37 options, (action, ) = parser.parse_args() 38 if not options.platform: 39 parser.error("Platform is required") 40 if not options.configuration: 41 parser.error("Configuration is required") 42 if action not in ('archive'): 43 parser.error("Action is required") 44 45 layoutTestResultsDir = os.path.abspath(os.path.join(sourceRootDirectory, "layout-test-results")) 46 if options.platform == 'chromium': 47 # See results_directory() in webkitpy/layout_tests/port/chromium.py. 48 layoutTestResultsDir = os.path.abspath(os.path.join(sourceRootDirectory, 49 "Source", "WebKit", "chromium", "webkit", options.configuration.capitalize(), 50 "layout-test-results")) 51 52 return archiveTestResults(options.configuration, options.platform, layoutTestResultsDir) 53 54 def archiveTestResults(configuration, platform, layoutTestResultsDir): 55 assert platform in ('mac', 'win', 'gtk', 'qt', 'chromium') 56 57 try: 58 os.unlink(archiveFile) 59 except OSError, e: 60 if e.errno != 2: 61 raise 62 63 try: 64 # Ensure that layoutTestResultsDir exists since we cannot archive a directory that does not exist 65 os.makedirs(layoutTestResultsDir) 66 except OSError, e: 67 if e.errno != 17: 68 raise 69 70 open(os.path.join(layoutTestResultsDir, '.placeholder'), 'w').close() 71 72 if platform == 'mac': 73 if subprocess.call(["ditto", "-c", "-k", "--sequesterRsrc", layoutTestResultsDir, archiveFile]): 74 return 1 75 elif platform in ('win', 'gtk', 'qt'): 76 if subprocess.call(["zip", "-r", archiveFile, "."], cwd=layoutTestResultsDir): 77 return 1 78 elif platform == 'chromium': 79 cwd = os.getcwd() 80 os.chdir(layoutTestResultsDir) 81 zipFilesRecursively(archiveFile, ["."]) 82 os.chdir(cwd) 83 84 try: 85 shutil.rmtree(layoutTestResultsDir) 86 except OSError, e: 87 88 # Python in Cygwin throws a mysterious exception with errno of 90 89 # when removing the layout test result directory after successfully 90 # deleting its contents, claiming "Directory not empty". 91 # We can safely ignore this since it was the directory contents that 92 # we are most interested in deleting. 93 # Python in Cygwin will also sometimes throw errno 2 if a process is 94 # holding a file open. There's no point in failing to create the 95 # archive just because some other process is behaving badly. See 96 # <http://webkit.org/b/55581>. 97 if e.errno != 90 and e.errno != 2: 98 raise 99 100 def zipFilesRecursively(archiveFile, files): 101 """Make a zip archive. 102 103 Args: 104 archiveFile: The resultant zip archive file name. 105 files: A list of files to be archived. If a list item is a directory, 106 files in the directory are archived recursively.""" 107 zipper = zipfile.ZipFile(archiveFile, 'w', zipfile.ZIP_DEFLATED) 108 for file in files: 109 if os.path.isdir(file): 110 for dirPath, dirNames, fileNames in os.walk(file): 111 for fileName in fileNames: 112 relativePath = os.path.join(dirPath, fileName) 113 print "Adding", relativePath 114 zipper.write(relativePath) 115 else: 116 print "Adding", file 117 zipper.write(file) 118 zipper.close() 119 print "Created zip archive: ", archiveFile 120 121 if __name__ == '__main__': 122 sys.exit(main()) 123