Home | History | Annotate | Download | only in build_tools
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Common utilities for all buildbot scripts that specifically don't rely
      6 on having a full chromium checkout.
      7 """
      8 
      9 import os
     10 import subprocess
     11 import sys
     12 
     13 from build_paths import SDK_SRC_DIR, NACL_DIR
     14 
     15 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
     16 import oshelpers
     17 import getos
     18 
     19 def IsSDKBuilder():
     20   """Returns True if this script is running on an SDK builder.
     21 
     22   False means it is either running on a trybot, or a user's machine.
     23 
     24   Trybot names:
     25     (win|mac|linux)_nacl_sdk
     26 
     27   Builder names:
     28     (windows|mac|linux)-sdk-multi(rel)?"""
     29   return '-sdk-multi' in os.getenv('BUILDBOT_BUILDERNAME', '')
     30 
     31 
     32 def IsSDKTrybot():
     33   """Returns True if this script is running on an SDK trybot.
     34 
     35   False means it is either running on an SDK builder, or a user's machine.
     36 
     37   See IsSDKBuilder above for trybot/buildbot names."""
     38   return '_nacl_sdk' in os.getenv('BUILDBOT_BUILDERNAME', '')
     39 
     40 
     41 def ErrorExit(msg):
     42   """Write and error to stderr, then exit with 1 signaling failure."""
     43   sys.stderr.write(str(msg) + '\n')
     44   sys.exit(1)
     45 
     46 
     47 def GetWindowsEnvironment():
     48   sys.path.append(os.path.join(NACL_DIR, 'buildbot'))
     49   import buildbot_standard
     50 
     51   # buildbot_standard.SetupWindowsEnvironment expects a "context" object. We'll
     52   # fake enough of that here to work.
     53   class FakeContext(object):
     54     def __init__(self):
     55       self.env = os.environ
     56 
     57     def GetEnv(self, key):
     58       return self.env[key]
     59 
     60     def __getitem__(self, key):
     61       return self.env[key]
     62 
     63     def SetEnv(self, key, value):
     64       self.env[key] = value
     65 
     66     def __setitem__(self, key, value):
     67       self.env[key] = value
     68 
     69   context = FakeContext()
     70   buildbot_standard.SetupWindowsEnvironment(context)
     71 
     72   # buildbot_standard.SetupWindowsEnvironment adds the directory which contains
     73   # vcvarsall.bat to the path, but not the directory which contains cl.exe,
     74   # link.exe, etc.
     75   # Running vcvarsall.bat adds the correct directories to the path, which we
     76   # extract below.
     77   process = subprocess.Popen('vcvarsall.bat x86 > NUL && set',
     78       stdout=subprocess.PIPE, env=context.env, shell=True)
     79   stdout, _ = process.communicate()
     80 
     81   # Parse environment from "set" command above.
     82   # It looks like this:
     83   # KEY1=VALUE1\r\n
     84   # KEY2=VALUE2\r\n
     85   # ...
     86   return dict(line.split('=') for line in stdout.split('\r\n')[:-1])
     87 
     88 
     89 def BuildStep(name):
     90   """Annotate a buildbot build step."""
     91   sys.stdout.flush()
     92   print '\n@@@BUILD_STEP %s@@@' % name
     93   sys.stdout.flush()
     94 
     95 
     96 def Run(args, cwd=None, env=None, shell=False):
     97   """Start a process with the provided arguments.
     98 
     99   Starts a process in the provided directory given the provided arguments. If
    100   shell is not False, the process is launched via the shell to provide shell
    101   interpretation of the arguments.  Shell behavior can differ between platforms
    102   so this should be avoided when not using platform dependent shell scripts."""
    103 
    104   # We need to modify the environment to build host on Windows.
    105   if not env and getos.GetPlatform() == 'win':
    106     env = GetWindowsEnvironment()
    107 
    108   print 'Running: ' + ' '.join(args)
    109   sys.stdout.flush()
    110   sys.stderr.flush()
    111   try:
    112     subprocess.check_call(args, cwd=cwd, env=env, shell=shell)
    113   except subprocess.CalledProcessError as e:
    114     sys.stdout.flush()
    115     sys.stderr.flush()
    116     ErrorExit('buildbot_common: %s' % e)
    117 
    118   sys.stdout.flush()
    119   sys.stderr.flush()
    120 
    121 
    122 def CopyDir(src, dst, excludes=('.svn', '*/.svn')):
    123   """Recursively copy a directory using."""
    124   args = ['-r', src, dst]
    125   for exc in excludes:
    126     args.append('--exclude=' + exc)
    127   print 'cp -r %s %s' % (src, dst)
    128   if os.path.abspath(src) == os.path.abspath(dst):
    129     ErrorExit('ERROR: Copying directory onto itself: ' + src)
    130   oshelpers.Copy(args)
    131 
    132 
    133 def CopyFile(src, dst):
    134   print 'cp %s %s' % (src, dst)
    135   if os.path.abspath(src) == os.path.abspath(dst):
    136     ErrorExit('ERROR: Copying file onto itself: ' + src)
    137   args = [src, dst]
    138   oshelpers.Copy(args)
    139 
    140 
    141 def RemoveDir(dst):
    142   """Remove the provided path."""
    143   print 'rm -fr ' + dst
    144   oshelpers.Remove(['-fr', dst])
    145 
    146 
    147 def MakeDir(dst):
    148   """Create the path including all parent directories as needed."""
    149   print 'mkdir -p ' + dst
    150   oshelpers.Mkdir(['-p', dst])
    151 
    152 
    153 def Move(src, dst):
    154   """Move the path src to dst."""
    155   print 'mv -f %s %s' % (src, dst)
    156   oshelpers.Move(['-f', src, dst])
    157 
    158 
    159 def RemoveFile(dst):
    160   """Remove the provided file."""
    161   print 'rm ' + dst
    162   oshelpers.Remove(['-f', dst])
    163 
    164 
    165 BOT_GSUTIL = '/b/build/scripts/slave/gsutil'
    166 # On Windows, the current working directory may be on a different drive than
    167 # gsutil.
    168 WIN_BOT_GSUTIL = 'E:' + BOT_GSUTIL
    169 LOCAL_GSUTIL = 'gsutil'
    170 
    171 
    172 def GetGsutil():
    173   if os.environ.get('BUILDBOT_BUILDERNAME') \
    174      and not os.environ.get('BUILDBOT_FAKE'):
    175     if getos.GetPlatform() == 'win':
    176       return WIN_BOT_GSUTIL
    177     return BOT_GSUTIL
    178   else:
    179     return LOCAL_GSUTIL
    180 
    181 
    182 def Archive(filename, bucket_path, cwd=None, step_link=True):
    183   """Upload the given filename to Google Store."""
    184   full_dst = 'gs://%s/%s' % (bucket_path, filename)
    185 
    186   # Since GetGsutil() might just return 'gsutil' and expect it to be looked
    187   # up in the PATH, we must pass shell=True on windows.
    188   # Without shell=True the windows implementation of subprocess.call will not
    189   # search the PATH for the executable: http://bugs.python.org/issue8557
    190   shell = getos.GetPlatform() == 'win'
    191 
    192   cmd = [GetGsutil(), 'cp', '-a', 'public-read', filename, full_dst]
    193   Run(cmd, shell=shell, cwd=cwd)
    194   url = 'https://commondatastorage.googleapis.com/'\
    195         '%s/%s' % (bucket_path, filename)
    196   if step_link:
    197     print '@@@STEP_LINK@download@%s@@@' % url
    198     sys.stdout.flush()
    199