OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # | |
3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
4 # for details. All rights reserved. Use of this source code is governed by a | |
5 # BSD-style license that can be found in the LICENSE file. | |
6 | |
7 # Gets or updates a DumpRenderTree (a nearly headless build of chrome). This is | |
8 # used for running browser tests of client applications. | |
9 | |
10 import optparse | |
11 import os | |
12 import platform | |
13 import shutil | |
14 import subprocess | |
15 import sys | |
16 import tempfile | |
17 import zipfile | |
18 | |
19 def NormJoin(path1, path2): | |
20 return os.path.normpath(os.path.join(path1, path2)) | |
21 | |
22 # Change into the dart directory as we want the project to be rooted here. | |
23 dart_src = NormJoin(os.path.dirname(sys.argv[0]), os.pardir) | |
24 os.chdir(dart_src) | |
25 | |
26 GSUTIL_DIR = os.path.join('third_party', 'gsutil') | |
27 GSUTIL = GSUTIL_DIR + '/gsutil' | |
28 | |
29 DRT_DIR = os.path.join('client', 'tests', 'drt') | |
30 DRT_VERSION = os.path.join(DRT_DIR, 'LAST_VERSION') | |
31 DRT_LATEST_PATTERN = ( | |
32 'gs://dartium-archive/latest/drt-%(osname)s-inc-*.zip') | |
33 DRT_PERMANENT_PREFIX = 'gs://dartium-archive/drt-%(osname)s-inc' | |
34 | |
35 DARTIUM_DIR = os.path.join('client', 'tests', 'dartium') | |
36 DARTIUM_VERSION = os.path.join(DARTIUM_DIR, 'LAST_VERSION') | |
37 DARTIUM_LATEST_PATTERN = ( | |
38 'gs://dartium-archive/latest/dartium-%(osname)s-inc-*.zip') | |
39 DARTIUM_PERMANENT_PREFIX = 'gs://dartium-archive/dartium-%(osname)s-inc' | |
40 | |
41 CHROMEDRIVER_DIR = os.path.join('tools', 'testing', 'dartium-chromedriver') | |
42 CHROMEDRIVER_VERSION = os.path.join(CHROMEDRIVER_DIR, 'LAST_VERSION') | |
43 CHROMEDRIVER_LATEST_PATTERN = ( | |
44 'gs://dartium-archive/latest/chromedriver-%(osname)s-inc-*.zip') | |
45 CHROMEDRIVER_PERMANENT_PREFIX = ( | |
46 'gs://dartium-archive/chromedriver-%(osname)s-inc') | |
47 | |
48 sys.path.append(os.path.join(GSUTIL_DIR, 'boto')) | |
49 import boto | |
50 | |
51 | |
52 def execute_command(*cmd): | |
53 """Execute a command in a subprocess.""" | |
54 pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
55 output, error = pipe.communicate() | |
56 return pipe.returncode, output | |
57 | |
58 | |
59 def execute_command_visible(*cmd): | |
60 """Execute a command in a subprocess, but show stdout/stderr.""" | |
61 result = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr, | |
62 stdin=sys.stdin) | |
63 if result != 0: | |
64 raise Exception('Execution of "%s" failed' % ' '.join(cmd)) | |
65 | |
66 | |
67 def gsutil(*cmd): | |
68 return execute_command('python', GSUTIL, *cmd) | |
69 | |
70 | |
71 def gsutil_visible(*cmd): | |
72 execute_command_visible('python', GSUTIL, *cmd) | |
73 | |
74 | |
75 def has_boto_config(): | |
76 """Returns true if boto config exists.""" | |
77 | |
78 config_paths = boto.pyami.config.BotoConfigLocations | |
79 if 'AWS_CREDENTIAL_FILE' in os.environ: | |
80 config_paths.append(os.environ['AWS_CREDENTIAL_FILE']) | |
81 for config_path in config_paths: | |
82 if os.path.exists(config_path): | |
83 return True | |
84 | |
85 return False | |
86 | |
87 | |
88 def in_runhooks(): | |
89 '''True if this script was called by "gclient runhooks" or "gclient sync"''' | |
90 return 'runhooks' in sys.argv | |
91 | |
92 | |
93 def ensure_config(): | |
94 # If ~/.boto doesn't exist, tell the user to run "gsutil config" | |
95 if not has_boto_config(): | |
96 print >>sys.stderr, ''' | |
97 ******************************************************************************* | |
98 * WARNING: Can't download DumpRenderTree! This is required to test client apps. | |
99 * You need to do a one-time configuration step to access Google Storage. | |
100 * Please run this command and follow the instructions: | |
101 * %s config | |
102 * | |
103 * NOTE: When prompted you can leave "project-id" blank. Just hit enter. | |
104 ******************************************************************************* | |
105 ''' % GSUTIL | |
106 sys.exit(1) | |
107 | |
108 | |
109 def get_latest(name, directory, version_file, latest_pattern, permanent_prefix): | |
110 """Get the latest DumpRenderTree or Dartium binary depending on arguments. | |
111 | |
112 Args: | |
113 directory: target directory (recreated) to install binary | |
114 version_file: name of file with the current version stamp | |
115 latest_pattern: the google store url pattern pointing to the latest binary | |
116 permanent_prefix: stable google store folder used to download versions | |
117 """ | |
118 system = platform.system() | |
119 if system == 'Darwin': | |
120 osname = 'mac' | |
121 elif system == 'Linux': | |
122 osname = 'lucid64' | |
123 elif system == 'Windows': | |
124 osname = 'win' | |
125 else: | |
126 print >>sys.stderr, ('WARNING: platform "%s" does not support' | |
127 '%s for tests') % (system, name) | |
128 return 0 | |
129 | |
130 ensure_config() | |
131 | |
132 # Query for the lastest version | |
133 pattern = latest_pattern % { 'osname' : osname } | |
134 result, out = gsutil('ls', pattern) | |
135 if result == 0: | |
136 latest = out.split()[-1] | |
137 # use permanent link instead, just in case the latest zip entry gets deleted | |
138 # while we are downloading it. | |
139 latest = (permanent_prefix % { 'osname' : osname } | |
140 + latest[latest.rindex('/'):]) | |
141 else: # e.g. no access | |
142 print "Couldn't download %s: %s\n%s" % (name, pattern, out) | |
143 if not os.path.exists(version_file): | |
144 print "Tests using %s will not work. Please try again later." % name | |
145 return 0 | |
146 | |
147 # Check if we need to update the file | |
148 if os.path.exists(version_file): | |
149 v = open(version_file, 'r').read() | |
150 if v == latest: | |
151 if not in_runhooks(): | |
152 print name + ' is up to date.\nVersion: ' + latest | |
153 return 0 # up to date | |
154 | |
155 if os.path.exists(directory): | |
156 print 'Removing old %s tree %s' % (name, directory) | |
157 shutil.rmtree(directory) | |
158 | |
159 # download the zip file to a temporary path, and unzip to the target location | |
160 temp_dir = tempfile.mkdtemp() | |
161 try: | |
162 temp_zip = os.path.join(temp_dir, 'drt.zip') | |
163 temp_zip_url = 'file://' + temp_zip | |
164 # It's nice to show download progress | |
165 gsutil_visible('cp', latest, temp_zip_url) | |
166 | |
167 if platform.system() != 'Windows': | |
168 # The Python zip utility does not preserve executable permissions, but | |
169 # this does not seem to be a problem for Windows, which does not have a | |
170 # built in zip utility. :-/ | |
171 result, out = execute_command('unzip', temp_zip, '-d', temp_dir) | |
172 if result != 0: | |
173 raise Exception('Execution of "unzip %s -d %s" failed: %s' % | |
174 (temp_zip, temp_dir, str(out))) | |
175 unzipped_dir = temp_dir + '/' + os.path.basename(latest)[:-4] #Remove .zip | |
176 else: | |
177 z = zipfile.ZipFile(temp_zip) | |
178 z.extractall(temp_dir) | |
179 # -4 = remove .zip for dir name | |
180 unzipped_dir = os.path.join(temp_dir, os.path.basename(latest)[:-4]) | |
181 z.close() | |
182 shutil.move(unzipped_dir, directory) | |
183 finally: | |
184 shutil.rmtree(temp_dir) | |
185 | |
186 # create the version stamp | |
187 v = open(version_file, 'w') | |
188 v.write(latest) | |
189 v.close() | |
190 | |
191 print 'Successfully downloaded to %s' % directory | |
192 return 0 | |
193 | |
194 | |
195 def main(): | |
196 parser = optparse.OptionParser() | |
197 parser.add_option('--dartium', dest='dartium', | |
198 help='Get latest Dartium', action='store_true', | |
199 default=False) | |
200 parser.add_option('--chromedriver', dest='chromedriver', | |
201 help='Get the latest built ChromeDriver', | |
202 action='store_true', default=False) | |
203 args, _ = parser.parse_args() | |
204 | |
205 if args.dartium: | |
206 get_latest('Dartium', DARTIUM_DIR, DARTIUM_VERSION, | |
207 DARTIUM_LATEST_PATTERN, DARTIUM_PERMANENT_PREFIX) | |
208 elif args.chromedriver: | |
209 get_latest('chromedriver', CHROMEDRIVER_DIR, CHROMEDRIVER_VERSION, | |
210 CHROMEDRIVER_LATEST_PATTERN, CHROMEDRIVER_PERMANENT_PREFIX) | |
211 else: | |
212 get_latest('DumpRenderTree', DRT_DIR, DRT_VERSION, | |
213 DRT_LATEST_PATTERN, DRT_PERMANENT_PREFIX) | |
214 | |
215 if __name__ == '__main__': | |
216 sys.exit(main()) | |
OLD | NEW |