chromium/native_client_sdk/src/build_tools/update_sdktools.py

#!/usr/bin/env python
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Script that reads omahaproxy and gsutil to determine a version of the
sdk_tools bundle to use.

Please note the differences between this script and update_nacl_manifest.py:

update_sdktools.py is run by a SDK-team developer to assist in updating to a
new sdk_tools bundle. A file on the developer's hard drive is modified, and
must be checked in for the new sdk_tools bundle to be used.

update_nacl_manifest.py is customarily run by a cron job, and does not check in
any changes. Instead it modifies the manifest file in cloud storage."""


import argparse
import collections
import difflib
import json
import re
import sys
import urllib2

from manifest_util import DownloadAndComputeHash, DictToJSON
from update_nacl_manifest import RealDelegate


SDK_TOOLS_DESCRIPTION_FORMAT = 'Native Client SDK Tools, revision %d'
BUCKET_PATH = 'nativeclient-mirror/nacl/nacl_sdk/'
GS_BUCKET_PATH = 'gs://' + BUCKET_PATH
HTTPS_BUCKET_PATH = 'https://storage.googleapis.com/' + BUCKET_PATH


def GetSdkToolsUrl(revision):
  return HTTPS_BUCKET_PATH + 'trunk.%d/sdk_tools.tgz' % revision


def GetTrunkRevisions(delegate):
  urls = delegate.GsUtil_ls(GS_BUCKET_PATH)
  revisions = []
  for url in urls:
    m = re.match(GS_BUCKET_PATH + 'trunk\.(\d+)', url)
    if m:
      revisions.append((int(m.group(1)), url))
  return sorted(revisions)


def FindMostRecentSdkTools(delegate):
  for revision, url in reversed(GetTrunkRevisions(delegate)):
    sdktools_url = url + 'sdk_tools.tgz'
    if delegate.GsUtil_ls(sdktools_url):
      return revision, sdktools_url
  return None


def JsonLoadFromString(json_string):
  if sys.version_info > (2, 7):
    return json.loads(json_string, object_pairs_hook=collections.OrderedDict)
  else:
    return json.loads(json_string)


def GetBundleByName(bundles, name):
  for bundle in bundles:
    if bundle['name'] == name:
      return bundle
  return None


def UpdateSdkToolsBundle(sdk_tools_bundle, revision, url, sha1, size):
  sdk_tools_bundle['description'] = SDK_TOOLS_DESCRIPTION_FORMAT % revision
  sdk_tools_bundle['revision'] = revision
  # Update archive for each OS
  for archive in sdk_tools_bundle['archives']:
    archive['url'] = url
    archive['checksum']['sha1'] = sha1
    archive['size'] = size


def UpdateManifest(manifest, revision):
  sdk_tools_bundle = GetBundleByName(manifest['bundles'], 'sdk_tools')
  url = GetSdkToolsUrl(revision)
  sha1, size = DownloadAndComputeHash(urllib2.urlopen(url))
  UpdateSdkToolsBundle(sdk_tools_bundle, revision, url, sha1, size)


def UpdateManifestFileToRevision(filename, revision):
  with open(filename) as stream:
    manifest_string = stream.read()

  manifest = JsonLoadFromString(manifest_string)
  UpdateManifest(manifest, revision)
  new_manifest_string = DictToJSON(manifest)

  diff_string = ''.join(difflib.unified_diff(manifest_string.splitlines(1),
                                             new_manifest_string.splitlines(1)))

  print 'diff %s' % filename
  print diff_string
  print

  with open(filename, 'w') as stream:
    stream.write(new_manifest_string)


def main(args):
  parser = argparse.ArgumentParser(description=__doc__)
  parser.add_argument('-r', '--revision',
      help='set revision manually, rather than using the latest version')
  options = parser.parse_args(args)

  # TODO(binji): http://crbug.com/169047. Rename RealDelegate to something else.
  delegate = RealDelegate()
  if not options.revision:
    revision, _ = FindMostRecentSdkTools(delegate)
  else:
    revision = int(options.revision)

  UpdateManifestFileToRevision('json/naclsdk_manifest0.json', revision)
  UpdateManifestFileToRevision('json/naclsdk_manifest2.json', revision)
  return 0


if __name__ == '__main__':
  sys.exit(main(sys.argv[1:]))