Index: dart/tools/bots/bot_utils.py |
diff --git a/dart/tools/bots/bot_utils.py b/dart/tools/bots/bot_utils.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dde5ddf49f7c887974334a879134c617b980f5b6 |
--- /dev/null |
+++ b/dart/tools/bots/bot_utils.py |
@@ -0,0 +1,223 @@ |
+#!/usr/bin/env python |
+# |
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
+# for details. All rights reserved. Use of this source code is governed by a |
+# BSD-style license that can be found in the LICENSE file. |
+ |
+import hashlib |
+import imp |
+import os |
+import subprocess |
+import sys |
+ |
+DART_DIR = os.path.abspath( |
+ os.path.normpath(os.path.join(__file__, '..', '..', '..'))) |
+ |
+def GetUtils(): |
+ '''Dynamically load the tools/utils.py python module.''' |
+ return imp.load_source('utils', os.path.join(DART_DIR, 'tools', 'utils.py')) |
+ |
+utils = GetUtils() |
+ |
+SYSTEM_RENAMES = { |
+ 'win32': 'windows', |
+ 'windows': 'windows', |
+ 'win': 'windows', |
+ |
+ 'linux': 'linux', |
+ 'linux2': 'linux', |
+ 'lucid32': 'linux', |
+ 'lucid64': 'linux', |
+ |
+ 'darwin': 'macos', |
+ 'mac': 'macos', |
+ 'macos': 'macos', |
+} |
+ |
+ARCH_RENAMES = { |
+ '32': 'ia32', |
+ 'ia32': 'ia32', |
+ |
+ '64': 'x64', |
+ 'x64': 'x64', |
+} |
+ |
+class Channel(object): |
+ BLEEDING_EDGE = 'be' |
+ DEV = 'dev' |
+ STABLE = 'stable' |
+ ALL_CHANNELS = [BLEEDING_EDGE, DEV, STABLE] |
+ |
+class ReleaseType(object): |
+ RAW = 'raw' |
+ SIGNED = 'signed' |
+ RELEASE = 'release' |
+ ALL_TYPES = [RAW, SIGNED, RELEASE] |
+ |
+class Mode(object): |
+ RELEASE = 'release' |
+ DEBUG = 'debug' |
+ ALL_MODES = [RELEASE, DEBUG] |
+ |
+class GCSNamer(object): |
+ def __init__(self, channel=Channel.BLEEDING_EDGE, |
+ release_type=ReleaseType.RAW): |
+ assert channel in Channel.ALL_CHANNELS |
+ assert release_type in ReleaseType.ALL_TYPES |
+ |
+ self.channel = channel |
+ self.release_type = release_type |
+ self.bucket = 'gs://dart-archive' |
+ |
+ # Functions for quering complete gs:// filepaths |
+ |
+ def version_filepath(self, revision): |
+ return '%s/channels/%s/%s/%s/VERSION' % (self.bucket, self.channel, |
+ self.release_type, revision) |
+ |
+ def editor_zipfilepath(self, revision, system, arch): |
+ return '/'.join([self.editor_directory(revision), |
+ self.editor_zipfilename(system, arch)]) |
+ |
+ def sdk_zipfilepath(self, revision, system, arch, mode): |
+ return '/'.join([self.sdk_directory(revision), |
+ self.sdk_zipfilename(system, arch, mode)]) |
+ |
+ def dartium_variant_zipfilepath(self, revision, name, system, arch, mode): |
+ return '/'.join([self.dartium_directory(revision), |
+ self.dartium_variant_zipfilename(name, system, arch, mode)]) |
+ |
+ # Functions for querying gs:// directories |
+ |
+ def dartium_directory(self, revision): |
+ return self._variant_directory('dartium', revision) |
+ |
+ def sdk_directory(self, revision): |
+ return self._variant_directory('sdk', revision) |
+ |
+ def editor_directory(self, revision): |
+ return self._variant_directory('editor', revision) |
+ |
+ def editor_eclipse_update_directory(self, revision): |
+ return self._variant_directory('editor-eclipse-update', revision) |
+ |
+ def apidocs_directory(self, revision): |
+ return self._variant_directory('api-docs', revision) |
+ |
+ def misc_directory(self, revision): |
+ return self._variant_directory('misc', revision) |
+ |
+ def _variant_directory(self, name, revision): |
+ return '%s/channels/%s/%s/%s/%s' % (self.bucket, self.channel, |
+ self.release_type, revision, name) |
+ |
+ # Functions for quering filenames |
+ |
+ def apidocs_zipfilename(self): |
+ return 'dart-api-docs.zip' |
+ |
+ def editor_zipfilename(self, system, arch): |
+ return 'darteditor-%s-%s.zip' % ( |
+ SYSTEM_RENAMES[system], ARCH_RENAMES[arch]) |
+ |
+ def sdk_zipfilename(self, system, arch, mode): |
+ assert mode in Mode.ALL_MODES |
+ return 'dartsdk-%s-%s-%s.zip' % ( |
+ SYSTEM_RENAMES[system], ARCH_RENAMES[arch], mode) |
+ |
+ def dartium_variant_zipfilename(self, name, system, arch, mode): |
+ assert name in ['chromedriver', 'dartium', 'content_shell'] |
+ assert mode in Mode.ALL_MODES |
+ return '%s-%s-%s-%s.zip' % ( |
+ name, SYSTEM_RENAMES[system], ARCH_RENAMES[arch], mode) |
+ |
+def run(command, env=None): |
+ print "Running command: ", command |
+ p = subprocess.Popen(command, stdout=subprocess.PIPE, |
+ stderr=subprocess.PIPE, env=env) |
+ (stdout, stderr) = p.communicate() |
+ if p.returncode != 0: |
+ print >> sys.stderr, "Failed to execute '%s'. Exit code: %s." % ( |
+ command, p.returncode) |
+ print >> sys.stderr, "stdout: ", stdout |
+ print >> sys.stderr, "stderr: ", stderr |
+ raise Exception("Failed to execute %s." % command) |
+ |
+class GSUtil(object): |
+ GSUTIL_PATH = None |
+ |
+ def _layzCalculateGSUtilPath(self): |
+ if not GSUtil.GSUTIL_PATH: |
+ dart_gsutil = os.path.join(DART_DIR, 'third_party', 'gsutil', 'gsutil') |
+ buildbot_gsutil = os.path.dirname(utils.GetBuildbotGSUtilPath()) |
+ possible_locations = (list(os.environ['PATH'].split(os.pathsep)) |
+ + [dart_gsutil, buildbot_gsutil]) |
+ for directory in possible_locations: |
+ location = os.path.join(directory, 'gsutil') |
+ if os.path.isfile(location): |
+ GSUtil.GSUTIL_PATH = location |
+ break |
+ assert GSUtil.GSUTIL_PATH |
+ |
+ def execute(self, gsutil_args): |
+ self._layzCalculateGSUtilPath() |
+ |
+ env = dict(os.environ) |
+ # If we're on the buildbot, we use a specific boto file. |
+ if utils.GetUserName() == 'chrome-bot': |
+ boto_config = { |
+ 'linux': '/mnt/data/b/build/site_config/.boto', |
+ 'macos': '/Volumes/data/b/build/site_config/.boto', |
+ 'win32': r'e:\b\build\site_config\.boto', |
+ }[utils.GuessOS()] |
+ env['AWS_CREDENTIAL_FILE'] = boto_config |
+ env['BOTO_CONFIG'] = boto_config |
+ run([sys.executable, GSUtil.GSUTIL_PATH] + gsutil_args, |
+ env=env) |
+ |
+ def upload(self, local_path, remote_path, recursive=False, public=False): |
+ assert remote_path.startswith('gs://') |
+ |
+ args = ['cp'] |
+ if public: |
+ args += ['-a', 'public-read'] |
+ if recursive: |
+ args += ['-R'] |
+ args += [local_path, remote_path] |
+ self.execute(args) |
+ |
+ def remove(self, remote_path, recursive=False): |
+ assert remote_path.startswith('gs://') |
+ |
+ args = ['rm'] |
+ if recursive: |
+ args += ['-R'] |
+ args += [remote_path] |
+ self.execute(args) |
+ |
+def CalculateChecksum(filename): |
+ """Calculate the MD5 checksum for filename.""" |
+ |
+ md5 = hashlib.md5() |
+ |
+ with open(filename, 'rb') as f: |
+ data = f.read(65536) |
+ while len(data) > 0: |
+ md5.update(data) |
+ data = f.read(65536) |
+ |
+ return md5.hexdigest() |
+ |
+def CreateChecksumFile(filename, mangled_filename=None): |
+ """Create and upload an MD5 checksum file for filename.""" |
+ if not mangled_filename: |
+ mangled_filename = os.path.basename(filename) |
+ |
+ checksum = CalculateChecksum(filename) |
+ checksum_filename = '%s.md5sum' % filename |
+ |
+ with open(checksum_filename, 'w') as f: |
+ f.write('%s *%s' % (checksum, mangled_filename)) |
+ |
+ return checksum_filename |
+ |