OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright (c) 2012, 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 import hashlib |
| 8 import imp |
| 9 import os |
| 10 import subprocess |
| 11 import sys |
| 12 |
| 13 DART_DIR = os.path.abspath( |
| 14 os.path.normpath(os.path.join(__file__, '..', '..', '..'))) |
| 15 |
| 16 def GetUtils(): |
| 17 '''Dynamically load the tools/utils.py python module.''' |
| 18 return imp.load_source('utils', os.path.join(DART_DIR, 'tools', 'utils.py')) |
| 19 |
| 20 utils = GetUtils() |
| 21 |
| 22 SYSTEM_RENAMES = { |
| 23 'win32': 'windows', |
| 24 'windows': 'windows', |
| 25 'win': 'windows', |
| 26 |
| 27 'linux': 'linux', |
| 28 'linux2': 'linux', |
| 29 'lucid32': 'linux', |
| 30 'lucid64': 'linux', |
| 31 |
| 32 'darwin': 'macos', |
| 33 'mac': 'macos', |
| 34 'macos': 'macos', |
| 35 } |
| 36 |
| 37 ARCH_RENAMES = { |
| 38 '32': 'ia32', |
| 39 'ia32': 'ia32', |
| 40 |
| 41 '64': 'x64', |
| 42 'x64': 'x64', |
| 43 } |
| 44 |
| 45 class Channel(object): |
| 46 BLEEDING_EDGE = 'be' |
| 47 DEV = 'dev' |
| 48 STABLE = 'stable' |
| 49 ALL_CHANNELS = [BLEEDING_EDGE, DEV, STABLE] |
| 50 |
| 51 class ReleaseType(object): |
| 52 RAW = 'raw' |
| 53 SIGNED = 'signed' |
| 54 RELEASE = 'release' |
| 55 ALL_TYPES = [RAW, SIGNED, RELEASE] |
| 56 |
| 57 class Mode(object): |
| 58 RELEASE = 'release' |
| 59 DEBUG = 'debug' |
| 60 ALL_MODES = [RELEASE, DEBUG] |
| 61 |
| 62 class GCSNamer(object): |
| 63 def __init__(self, channel=Channel.BLEEDING_EDGE, |
| 64 release_type=ReleaseType.RAW): |
| 65 assert channel in Channel.ALL_CHANNELS |
| 66 assert release_type in ReleaseType.ALL_TYPES |
| 67 |
| 68 self.channel = channel |
| 69 self.release_type = release_type |
| 70 self.bucket = 'gs://dart-archive' |
| 71 |
| 72 # Functions for quering complete gs:// filepaths |
| 73 |
| 74 def version_filepath(self, revision): |
| 75 return '%s/channels/%s/%s/%s/VERSION' % (self.bucket, self.channel, |
| 76 self.release_type, revision) |
| 77 |
| 78 def editor_zipfilepath(self, revision, system, arch): |
| 79 return '/'.join([self.editor_directory(revision), |
| 80 self.editor_zipfilename(system, arch)]) |
| 81 |
| 82 def sdk_zipfilepath(self, revision, system, arch, mode): |
| 83 return '/'.join([self.sdk_directory(revision), |
| 84 self.sdk_zipfilename(system, arch, mode)]) |
| 85 |
| 86 def dartium_variant_zipfilepath(self, revision, name, system, arch, mode): |
| 87 return '/'.join([self.dartium_directory(revision), |
| 88 self.dartium_variant_zipfilename(name, system, arch, mode)]) |
| 89 |
| 90 # Functions for querying gs:// directories |
| 91 |
| 92 def dartium_directory(self, revision): |
| 93 return self._variant_directory('dartium', revision) |
| 94 |
| 95 def sdk_directory(self, revision): |
| 96 return self._variant_directory('sdk', revision) |
| 97 |
| 98 def editor_directory(self, revision): |
| 99 return self._variant_directory('editor', revision) |
| 100 |
| 101 def editor_eclipse_update_directory(self, revision): |
| 102 return self._variant_directory('editor-eclipse-update', revision) |
| 103 |
| 104 def apidocs_directory(self, revision): |
| 105 return self._variant_directory('api-docs', revision) |
| 106 |
| 107 def misc_directory(self, revision): |
| 108 return self._variant_directory('misc', revision) |
| 109 |
| 110 def _variant_directory(self, name, revision): |
| 111 return '%s/channels/%s/%s/%s/%s' % (self.bucket, self.channel, |
| 112 self.release_type, revision, name) |
| 113 |
| 114 # Functions for quering filenames |
| 115 |
| 116 def apidocs_zipfilename(self): |
| 117 return 'dart-api-docs.zip' |
| 118 |
| 119 def editor_zipfilename(self, system, arch): |
| 120 return 'darteditor-%s-%s.zip' % ( |
| 121 SYSTEM_RENAMES[system], ARCH_RENAMES[arch]) |
| 122 |
| 123 def sdk_zipfilename(self, system, arch, mode): |
| 124 assert mode in Mode.ALL_MODES |
| 125 return 'dartsdk-%s-%s-%s.zip' % ( |
| 126 SYSTEM_RENAMES[system], ARCH_RENAMES[arch], mode) |
| 127 |
| 128 def dartium_variant_zipfilename(self, name, system, arch, mode): |
| 129 assert name in ['chromedriver', 'dartium', 'content_shell'] |
| 130 assert mode in Mode.ALL_MODES |
| 131 return '%s-%s-%s-%s.zip' % ( |
| 132 name, SYSTEM_RENAMES[system], ARCH_RENAMES[arch], mode) |
| 133 |
| 134 def run(command, env=None): |
| 135 print "Running command: ", command |
| 136 p = subprocess.Popen(command, stdout=subprocess.PIPE, |
| 137 stderr=subprocess.PIPE, env=env) |
| 138 (stdout, stderr) = p.communicate() |
| 139 if p.returncode != 0: |
| 140 print >> sys.stderr, "Failed to execute '%s'. Exit code: %s." % ( |
| 141 command, p.returncode) |
| 142 print >> sys.stderr, "stdout: ", stdout |
| 143 print >> sys.stderr, "stderr: ", stderr |
| 144 raise Exception("Failed to execute %s." % command) |
| 145 |
| 146 class GSUtil(object): |
| 147 GSUTIL_PATH = None |
| 148 |
| 149 def _layzCalculateGSUtilPath(self): |
| 150 if not GSUtil.GSUTIL_PATH: |
| 151 dart_gsutil = os.path.join(DART_DIR, 'third_party', 'gsutil', 'gsutil') |
| 152 buildbot_gsutil = os.path.dirname(utils.GetBuildbotGSUtilPath()) |
| 153 possible_locations = (list(os.environ['PATH'].split(os.pathsep)) |
| 154 + [dart_gsutil, buildbot_gsutil]) |
| 155 for directory in possible_locations: |
| 156 location = os.path.join(directory, 'gsutil') |
| 157 if os.path.isfile(location): |
| 158 GSUtil.GSUTIL_PATH = location |
| 159 break |
| 160 assert GSUtil.GSUTIL_PATH |
| 161 |
| 162 def execute(self, gsutil_args): |
| 163 self._layzCalculateGSUtilPath() |
| 164 |
| 165 env = dict(os.environ) |
| 166 # If we're on the buildbot, we use a specific boto file. |
| 167 if utils.GetUserName() == 'chrome-bot': |
| 168 boto_config = { |
| 169 'linux': '/mnt/data/b/build/site_config/.boto', |
| 170 'macos': '/Volumes/data/b/build/site_config/.boto', |
| 171 'win32': r'e:\b\build\site_config\.boto', |
| 172 }[utils.GuessOS()] |
| 173 env['AWS_CREDENTIAL_FILE'] = boto_config |
| 174 env['BOTO_CONFIG'] = boto_config |
| 175 run([sys.executable, GSUtil.GSUTIL_PATH] + gsutil_args, |
| 176 env=env) |
| 177 |
| 178 def upload(self, local_path, remote_path, recursive=False, public=False): |
| 179 assert remote_path.startswith('gs://') |
| 180 |
| 181 args = ['cp'] |
| 182 if public: |
| 183 args += ['-a', 'public-read'] |
| 184 if recursive: |
| 185 args += ['-R'] |
| 186 args += [local_path, remote_path] |
| 187 self.execute(args) |
| 188 |
| 189 def remove(self, remote_path, recursive=False): |
| 190 assert remote_path.startswith('gs://') |
| 191 |
| 192 args = ['rm'] |
| 193 if recursive: |
| 194 args += ['-R'] |
| 195 args += [remote_path] |
| 196 self.execute(args) |
| 197 |
| 198 def CalculateChecksum(filename): |
| 199 """Calculate the MD5 checksum for filename.""" |
| 200 |
| 201 md5 = hashlib.md5() |
| 202 |
| 203 with open(filename, 'rb') as f: |
| 204 data = f.read(65536) |
| 205 while len(data) > 0: |
| 206 md5.update(data) |
| 207 data = f.read(65536) |
| 208 |
| 209 return md5.hexdigest() |
| 210 |
| 211 def CreateChecksumFile(filename, mangled_filename=None): |
| 212 """Create and upload an MD5 checksum file for filename.""" |
| 213 if not mangled_filename: |
| 214 mangled_filename = os.path.basename(filename) |
| 215 |
| 216 checksum = CalculateChecksum(filename) |
| 217 checksum_filename = '%s.md5sum' % filename |
| 218 |
| 219 with open(checksum_filename, 'w') as f: |
| 220 f.write('%s *%s' % (checksum, mangled_filename)) |
| 221 |
| 222 return checksum_filename |
| 223 |
OLD | NEW |