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 7 sdk_tools bundle to use. 8 9 Please note the differences between this script and update_nacl_manifest.py: 10 11 update_sdktools.py is run by a SDK-team developer to assist in updating to a 12 new sdk_tools bundle. A file on the developer's hard drive is modified, and 13 must be checked in for the new sdk_tools bundle to be used. 14 15 update_nacl_manifest.py is customarily run by a cron job, and does not check in 16 any changes. Instead it modifies the manifest file in cloud storage.""" 17 18 19 import collections 20 import difflib 21 import json 22 import optparse 23 import re 24 import sys 25 import urllib2 26 27 from manifest_util import DownloadAndComputeHash, DictToJSON 28 from update_nacl_manifest import RealDelegate 29 30 31 SDK_TOOLS_DESCRIPTION_FORMAT = 'Native Client SDK Tools, revision %d' 32 BUCKET_PATH = 'nativeclient-mirror/nacl/nacl_sdk/' 33 GS_BUCKET_PATH = 'gs://' + BUCKET_PATH 34 HTTPS_BUCKET_PATH = 'https://storage.googleapis.com/' + BUCKET_PATH 35 36 37 def GetSdkToolsUrl(revision): 38 return HTTPS_BUCKET_PATH + 'trunk.%d/sdk_tools.tgz' % revision 39 40 41 def 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 51 def 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 59 def 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 66 def GetBundleByName(bundles, name): 67 for bundle in bundles: 68 if bundle['name'] == name: 69 return bundle 70 return None 71 72 73 def 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 83 def 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 90 def 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 109 def 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 128 if __name__ == '__main__': 129 sys.exit(main(sys.argv)) 130