|  | #!/usr/bin/env python | 
|  | # Copyright (C) 2015 The Android Open Source Project | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | # http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | from __future__ import print_function | 
|  |  | 
|  | import hashlib | 
|  | import json | 
|  | import optparse | 
|  | import os | 
|  | import shutil | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | import bowerutil | 
|  |  | 
|  | CACHE_DIR = os.path.expanduser(os.path.join( | 
|  | '~', '.gerritcodereview', 'bazel-cache', 'downloaded-artifacts')) | 
|  |  | 
|  |  | 
|  | def bower_cmd(bower, *args): | 
|  | cmd = bower.split(' ') | 
|  | cmd.extend(args) | 
|  | return cmd | 
|  |  | 
|  |  | 
|  | def bower_info(bower, name, package, version): | 
|  | cmd = bower_cmd(bower, '-l=error', '-j', | 
|  | 'info', '%s#%s' % (package, version)) | 
|  | try: | 
|  | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, | 
|  | stderr=subprocess.PIPE) | 
|  | except: | 
|  | sys.stderr.write("error executing: %s\n" % ' '.join(cmd)) | 
|  | raise | 
|  | out, err = p.communicate() | 
|  | if p.returncode: | 
|  | # For python3 support we wrap str around err. | 
|  | sys.stderr.write(str(err)) | 
|  | raise OSError('Command failed: %s' % ' '.join(cmd)) | 
|  |  | 
|  | try: | 
|  | info = json.loads(out) | 
|  | except ValueError: | 
|  | raise ValueError('invalid JSON from %s:\n%s' % (" ".join(cmd), out)) | 
|  | info_name = info.get('name') | 
|  | if info_name != name: | 
|  | raise ValueError( | 
|  | 'expected package name %s, got: %s' % (name, info_name)) | 
|  | return info | 
|  |  | 
|  |  | 
|  | def ignore_deps(info): | 
|  | # Tell bower to ignore dependencies so we just download this component. | 
|  | # This is just an optimization, since we only pick out the component we | 
|  | # need, but it's important when downloading sizable dependency trees. | 
|  | # | 
|  | # As of 1.6.5 I don't think ignoredDependencies can be specified on the | 
|  | # command line with --config, so we have to create .bowerrc. | 
|  | deps = info.get('dependencies') | 
|  | if deps: | 
|  | with open(os.path.join('.bowerrc'), 'w') as f: | 
|  | json.dump({'ignoredDependencies': list(deps.keys())}, f) | 
|  |  | 
|  |  | 
|  | def cache_entry(name, package, version, sha1): | 
|  | if not sha1: | 
|  | sha1 = hashlib.sha1('%s#%s' % (package, version)).hexdigest() | 
|  | return os.path.join(CACHE_DIR, '%s-%s.zip-%s' % (name, version, sha1)) | 
|  |  | 
|  |  | 
|  | def main(args): | 
|  | opts = optparse.OptionParser() | 
|  | opts.add_option('-n', help='short name of component') | 
|  | opts.add_option('-b', help='bower command') | 
|  | opts.add_option('-p', help='full package name of component') | 
|  | opts.add_option('-v', help='version number') | 
|  | opts.add_option('-s', help='expected content sha1') | 
|  | opts.add_option('-o', help='output file location') | 
|  | opts, args_ = opts.parse_args(args) | 
|  |  | 
|  | assert opts.p | 
|  | assert opts.v | 
|  | assert opts.n | 
|  |  | 
|  | cwd = os.getcwd() | 
|  | outzip = os.path.join(cwd, opts.o) | 
|  | cached = cache_entry(opts.n, opts.p, opts.v, opts.s) | 
|  |  | 
|  | if not os.path.exists(cached): | 
|  | info = bower_info(opts.b, opts.n, opts.p, opts.v) | 
|  | ignore_deps(info) | 
|  | subprocess.check_call( | 
|  | bower_cmd( | 
|  | opts.b, '--quiet', 'install', '%s#%s' % (opts.p, opts.v))) | 
|  | bc = os.path.join(cwd, 'bower_components') | 
|  | subprocess.check_call( | 
|  | ['zip', '-q', '--exclude', '.bower.json', '-r', cached, opts.n], | 
|  | cwd=bc) | 
|  |  | 
|  | if opts.s: | 
|  | path = os.path.join(bc, opts.n) | 
|  | sha1 = bowerutil.hash_bower_component( | 
|  | hashlib.sha1(), path).hexdigest() | 
|  | if opts.s != sha1: | 
|  | print(( | 
|  | '%s#%s:\n' | 
|  | 'expected %s\n' | 
|  | 'received %s\n') % (opts.p, opts.v, opts.s, sha1), | 
|  | file=sys.stderr) | 
|  | try: | 
|  | os.remove(cached) | 
|  | except OSError as err: | 
|  | if path.exists(cached): | 
|  | print('error removing %s: %s' % (cached, err), | 
|  | file=sys.stderr) | 
|  | return 1 | 
|  |  | 
|  | shutil.copyfile(cached, outzip) | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main(sys.argv[1:])) |