1#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Script that reads omahaproxy and gsutil to determine a version of the
7sdk_tools bundle to use.
8
9Please note the differences between this script and update_nacl_manifest.py:
10
11update_sdktools.py is run by a SDK-team developer to assist in updating to a
12new sdk_tools bundle. A file on the developer's hard drive is modified, and
13must be checked in for the new sdk_tools bundle to be used.
14
15update_nacl_manifest.py is customarily run by a cron job, and does not check in
16any changes. Instead it modifies the manifest file in cloud storage."""
17
18
19import collections
20import difflib
21import json
22import optparse
23import re
24import sys
25import urllib2
26
27from manifest_util import DownloadAndComputeHash, DictToJSON
28from update_nacl_manifest import RealDelegate
29
30
31SDK_TOOLS_DESCRIPTION_FORMAT = 'Native Client SDK Tools, revision %d'
32BUCKET_PATH = 'nativeclient-mirror/nacl/nacl_sdk/'
33GS_BUCKET_PATH = 'gs://' + BUCKET_PATH
34HTTPS_BUCKET_PATH = 'https://storage.googleapis.com/' + BUCKET_PATH
35
36
37def GetSdkToolsUrl(revision):
38  return HTTPS_BUCKET_PATH + 'trunk.%d/sdk_tools.tgz' % revision
39
40
41def GetTrunkRevisions(delegate):
42  urls = delegate.GsUtil_ls(GS_BUCKET_PATH)
43  revisions = []
44  for url in urls:
45    m = re.match(GS_BUCKET_PATH + 'trunk\.(\d+)', url)
46    if m:
47      revisions.append((int(m.group(1)), url))
48  return sorted(revisions)
49
50
51def FindMostRecentSdkTools(delegate):
52  for revision, url in reversed(GetTrunkRevisions(delegate)):
53    sdktools_url = url + 'sdk_tools.tgz'
54    if delegate.GsUtil_ls(sdktools_url):
55      return revision, sdktools_url
56  return None
57
58
59def JsonLoadFromString(json_string):
60  if sys.version_info > (2, 7):
61    return json.loads(json_string, object_pairs_hook=collections.OrderedDict)
62  else:
63    return json.loads(json_string)
64
65
66def GetBundleByName(bundles, name):
67  for bundle in bundles:
68    if bundle['name'] == name:
69      return bundle
70  return None
71
72
73def UpdateSdkToolsBundle(sdk_tools_bundle, revision, url, sha1, size):
74  sdk_tools_bundle['description'] = SDK_TOOLS_DESCRIPTION_FORMAT % revision
75  sdk_tools_bundle['revision'] = revision
76  # Update archive for each OS
77  for archive in sdk_tools_bundle['archives']:
78    archive['url'] = url
79    archive['checksum']['sha1'] = sha1
80    archive['size'] = size
81
82
83def UpdateManifest(manifest, revision):
84  sdk_tools_bundle = GetBundleByName(manifest['bundles'], 'sdk_tools')
85  url = GetSdkToolsUrl(revision)
86  sha1, size = DownloadAndComputeHash(urllib2.urlopen(url))
87  UpdateSdkToolsBundle(sdk_tools_bundle, revision, url, sha1, size)
88
89
90def UpdateManifestFileToRevision(filename, revision):
91  with open(filename) as stream:
92    manifest_string = stream.read()
93
94  manifest = JsonLoadFromString(manifest_string)
95  UpdateManifest(manifest, revision)
96  new_manifest_string = DictToJSON(manifest)
97
98  diff_string = ''.join(difflib.unified_diff(manifest_string.splitlines(1),
99                                             new_manifest_string.splitlines(1)))
100
101  print 'diff %s' % filename
102  print diff_string
103  print
104
105  with open(filename, 'w') as stream:
106    stream.write(new_manifest_string)
107
108
109def main(args):
110  parser = optparse.OptionParser(description=__doc__)
111  parser.add_option('-r', '--revision',
112      help='set revision manually, rather than using the latest version')
113  options, args = parser.parse_args(args[1:])
114  if len(args) != 0:
115    parser.error('Unexpected args: %s' % ', '.join(args))
116
117  # TODO(binji): http://crbug.com/169047. Rename RealDelegate to something else.
118  delegate = RealDelegate()
119  if not options.revision:
120    revision, _ = FindMostRecentSdkTools(delegate)
121  else:
122    revision = int(options.revision)
123
124  UpdateManifestFileToRevision('json/naclsdk_manifest0.json', revision)
125  UpdateManifestFileToRevision('json/naclsdk_manifest2.json', revision)
126
127
128if __name__ == '__main__':
129  sys.exit(main(sys.argv))
130