text: #!/usr/bin/env python
  # Copyright 2014 The Chromium Authors. All rights reserved.
  # Use of this source code is governed by a BSD-style license that can be
  # found in the LICENSE file.
  
  # Modified from go/bootstrap.py in Chromium infrastructure's repository to patch
  # out everything but the core toolchain.
  #
  # https://chromium.googlesource.com/infra/infra/
  
  """Prepares a local hermetic Go installation.
  
  - Downloads and unpacks the Go toolset in ../golang.
  """
  
  import contextlib
  import logging
  import os
  import platform
  import shutil
  import stat
  import subprocess
  import sys
  import tarfile
  import tempfile
  import urllib
  import zipfile
  
  # TODO(vadimsh): Migrate to new golang.org/x/ paths once Golang moves to
  # git completely.
  
  LOGGER = logging.getLogger(__name__)
  
  
  # /path/to/util/bot
  ROOT = os.path.dirname(os.path.abspath(__file__))
  
  # Where to install Go toolset to. GOROOT would be <TOOLSET_ROOT>/go.
  TOOLSET_ROOT = os.path.join(os.path.dirname(ROOT), 'golang')
  
  # Default workspace with infra go code.
  WORKSPACE = os.path.join(ROOT, 'go')
  
  # Platform depended suffix for executable files.
  EXE_SFX = '.exe' if sys.platform == 'win32' else ''
  
  # Pinned version of Go toolset to download.
  TOOLSET_VERSION = 'go1.12.1'
  
  # Platform dependent portion of a download URL. See http://golang.org/dl/.
  TOOLSET_VARIANTS = {
    ('darwin', 'x86-64'): 'darwin-amd64.tar.gz',
    ('linux2', 'x86-32'): 'linux-386.tar.gz',
    ('linux2', 'x86-64'): 'linux-amd64.tar.gz',
    ('win32', 'x86-32'): 'windows-386.zip',
    ('win32', 'x86-64'): 'windows-amd64.zip',
  }
  
  # Download URL root.
  DOWNLOAD_URL_PREFIX = 'https://storage.googleapis.com/golang'
  
  
  class Failure(Exception):
    """Bootstrap failed."""
  
  
  def get_toolset_url():
    """URL of a platform specific Go toolset archive."""
    # TODO(vadimsh): Support toolset for cross-compilation.
    arch = {
      'amd64': 'x86-64',
      'x86_64': 'x86-64',
      'i386': 'x86-32',
      'x86': 'x86-32',
    }.get(platform.machine().lower())
    variant = TOOLSET_VARIANTS.get((sys.platform, arch))
    if not variant:
      # TODO(vadimsh): Compile go lang from source.
      raise Failure('Unrecognized platform')
    return '%s/%s.%s' % (DOWNLOAD_URL_PREFIX, TOOLSET_VERSION, variant)
  
  
  def read_file(path):
    """Returns contents of a given file or None if not readable."""
    assert isinstance(path, (list, tuple))
    try:
      with open(os.path.join(*path), 'r') as f:
        return f.read()
    except IOError:
      return None
  
  
  def write_file(path, data):
    """Writes |data| to a file."""
    assert isinstance(path, (list, tuple))
    with open(os.path.join(*path), 'w') as f:
      f.write(data)
  
  
  def remove_directory(path):
    """Recursively removes a directory."""
    assert isinstance(path, (list, tuple))
    p = os.path.join(*path)
    if not os.path.exists(p):
      return
    LOGGER.info('Removing %s', p)
    # Crutch to remove read-only file (.git/* in particular) on Windows.
    def onerror(func, path, _exc_info):
      if not os.access(path, os.W_OK):
        os.chmod(path, stat.S_IWUSR)
        func(path)
      else:
        raise
    shutil.rmtree(p, onerror=onerror if sys.platform == 'win32' else None)
  
  
  def install_toolset(toolset_root, url):
    """Downloads and installs Go toolset.
  
    GOROOT would be <toolset_root>/go/.
    """
    if not os.path.exists(toolset_root):
      os.makedirs(toolset_root)
    pkg_path = os.path.join(toolset_root, url[url.rfind('/')+1:])
  
    LOGGER.info('Downloading %s...', url)
    download_file(url, pkg_path)
  
    LOGGER.info('Extracting...')
    if pkg_path.endswith('.zip'):
      with zipfile.ZipFile(pkg_path, 'r') as f:
        f.extractall(toolset_root)
    elif pkg_path.endswith('.tar.gz'):
      with tarfile.open(pkg_path, 'r:gz') as f:
        f.extractall(toolset_root)
    else:
      raise Failure('Unrecognized archive format')
  
    LOGGER.info('Validating...')
    if not check_hello_world(toolset_root):
      raise Failure('Something is not right, test program doesn\'t work')
  
  
  def download_file(url, path):
    """Fetches |url| to |path|."""
    last_progress = [0]
    def report(a, b, c):
      progress = int(a * b * 100.0 / c)
      if progress != last_progress[0]:
        print >> sys.stderr, 'Downloading... %d%%' % progress
        last_progress[0] = progress
    # TODO(vadimsh): Use something less crippled, something that validates SSL.
    urllib.urlretrieve(url, path, reporthook=report)
  
  
  @contextlib.contextmanager
  def temp_dir(path):
    """Creates a temporary directory, then deletes it."""
    tmp = tempfile.mkdtemp(dir=path)
    try:
      yield tmp
    finally:
      remove_directory([tmp])
  
  
  def check_hello_world(toolset_root):
    """Compiles and runs 'hello world' program to verify that toolset works."""
    with temp_dir(toolset_root) as tmp:
      path = os.path.join(tmp, 'hello.go')
      write_file([path], r"""
          package main
          func main() { println("hello, world\n") }
      """)
      out = subprocess.check_output(
          [get_go_exe(toolset_root), 'run', path],
          env=get_go_environ(toolset_root, tmp),
          stderr=subprocess.STDOUT)
      if out.strip() != 'hello, world':
        LOGGER.error('Failed to run sample program:\n%s', out)
        return False
      return True
  
  
  def ensure_toolset_installed(toolset_root):
    """Installs or updates Go toolset if necessary.
  
    Returns True if new toolset was installed.
    """
    installed = read_file([toolset_root, 'INSTALLED_TOOLSET'])
    available = get_toolset_url()
    if installed == available:
      LOGGER.debug('Go toolset is up-to-date: %s', TOOLSET_VERSION)
      return False
  
    LOGGER.info('Installing Go toolset.')
    LOGGER.info('  Old toolset is %s', installed)
    LOGGER.info('  New toolset is %s', available)
    remove_directory([toolset_root])
    install_toolset(toolset_root, available)
    LOGGER.info('Go toolset installed: %s', TOOLSET_VERSION)
    write_file([toolset_root, 'INSTALLED_TOOLSET'], available)
    return True
  
  
  def get_go_environ(
      toolset_root,
      workspace=None):
    """Returns a copy of os.environ with added GO* environment variables.
  
    Overrides GOROOT, GOPATH and GOBIN. Keeps everything else. Idempotent.
  
    Args:
      toolset_root: GOROOT would be <toolset_root>/go.
      workspace: main workspace directory or None if compiling in GOROOT.
    """
    env = os.environ.copy()
    env['GOROOT'] = os.path.join(toolset_root, 'go')
    if workspace:
      env['GOBIN'] = os.path.join(workspace, 'bin')
    else:
      env.pop('GOBIN', None)
  
    all_go_paths = []
    if workspace:
      all_go_paths.append(workspace)
    env['GOPATH'] = os.pathsep.join(all_go_paths)
  
    # New PATH entries.
    paths_to_add = [
      os.path.join(env['GOROOT'], 'bin'),
      env.get('GOBIN'),
    ]
  
    # Make sure not to add duplicates entries to PATH over and over again when
    # get_go_environ is invoked multiple times.
    path = env['PATH'].split(os.pathsep)
    paths_to_add = [p for p in paths_to_add if p and p not in path]
    env['PATH'] = os.pathsep.join(paths_to_add + path)
  
    return env
  
  
  def get_go_exe(toolset_root):
    """Returns path to go executable."""
    return os.path.join(toolset_root, 'go', 'bin', 'go' + EXE_SFX)
  
  
  def bootstrap(logging_level):
    """Installs all dependencies in default locations.
  
    Supposed to be called at the beginning of some script (it modifies logger).
  
    Args:
      logging_level: logging level of bootstrap process.
    """
    logging.basicConfig()
    LOGGER.setLevel(logging_level)
    ensure_toolset_installed(TOOLSET_ROOT)
  
  
  def prepare_go_environ():
    """Returns dict with environment variables to set to use Go toolset.
  
    Installs or updates the toolset if necessary.
    """
    bootstrap(logging.INFO)
    return get_go_environ(TOOLSET_ROOT, WORKSPACE)
  
  
  def find_executable(name, workspaces):
    """Returns full path to an executable in some bin/ (in GOROOT or GOBIN)."""
    basename = name
    if EXE_SFX and basename.endswith(EXE_SFX):
      basename = basename[:-len(EXE_SFX)]
    roots = [os.path.join(TOOLSET_ROOT, 'go', 'bin')]
    for path in workspaces:
      roots.extend([
        os.path.join(path, 'bin'),
      ])
    for root in roots:
      full_path = os.path.join(root, basename + EXE_SFX)
      if os.path.exists(full_path):
        return full_path
    return name
  
  
  def main(args):
    if args:
      print >> sys.stderr, sys.modules[__name__].__doc__,
      return 2
    bootstrap(logging.DEBUG)
    return 0
  
  
  if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
  