blob: c9c6ef0de0b547329e276a57e5c0724323c511a6 [file] [log] [blame]
Björn Pedersenc357ceb2015-05-27 10:17:36 +02001#!/usr/bin/env python
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -07002# Copyright (C) 2013 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Chirayu Desai4c5ee482013-05-13 13:48:43 +053016from __future__ import print_function
17
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070018from hashlib import sha1
19from optparse import OptionParser
Shawn Pearcef98b3792013-08-06 12:20:30 -070020from os import link, makedirs, path, remove
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070021import shutil
David Pursehouse28798772013-05-09 14:58:20 +010022from subprocess import check_call, CalledProcessError
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070023from sys import stderr
Dave Borowitz868f7642015-11-18 15:25:24 -050024from util import hash_file, resolve_url
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070025from zipfile import ZipFile, BadZipfile, LargeZipFile
26
David Pursehouse45286f12013-05-17 13:46:40 +090027GERRIT_HOME = path.expanduser('~/.gerritcodereview')
Christian Aistleitner6f6de0d2015-03-26 14:25:03 +010028CACHE_DIR = path.join(GERRIT_HOME, 'buck-cache', 'downloaded-artifacts')
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090029LOCAL_PROPERTIES = 'local.properties'
30
David Pursehouse15a9f532014-06-23 10:55:20 +090031
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070032def safe_mkdirs(d):
33 if path.isdir(d):
34 return
35 try:
36 makedirs(d)
37 except OSError as err:
38 if not path.isdir(d):
39 raise err
40
David Pursehouse15a9f532014-06-23 10:55:20 +090041
Shawn Pearce1b89f852013-05-13 20:26:34 -070042def download_properties(root_dir):
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090043 """ Get the download properties.
44
45 First tries to find the properties file in the given root directory,
46 and if not found there, tries in the Gerrit settings folder in the
47 user's home directory.
48
49 Returns a set of download properties, which may be empty.
50
51 """
Shawn Pearce1b89f852013-05-13 20:26:34 -070052 p = {}
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090053 local_prop = path.join(root_dir, LOCAL_PROPERTIES)
54 if not path.isfile(local_prop):
David Pursehouse45286f12013-05-17 13:46:40 +090055 local_prop = path.join(GERRIT_HOME, LOCAL_PROPERTIES)
Shawn Pearce1b89f852013-05-13 20:26:34 -070056 if path.isfile(local_prop):
57 try:
58 with open(local_prop) as fd:
59 for line in fd:
60 if line.startswith('download.'):
61 d = [e.strip() for e in line.split('=', 1)]
62 name, url = d[0], d[1]
63 p[name[len('download.'):]] = url
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090064 except OSError:
Shawn Pearce1b89f852013-05-13 20:26:34 -070065 pass
66 return p
67
David Pursehouse15a9f532014-06-23 10:55:20 +090068
David Pursehouse45286f12013-05-17 13:46:40 +090069def cache_entry(args):
Shawn Pearce1b89f852013-05-13 20:26:34 -070070 if args.v:
71 h = args.v
72 else:
Urs Wolfera11276a2014-04-26 13:20:00 +020073 h = sha1(args.u.encode('utf-8')).hexdigest()
Shawn Pearce1b89f852013-05-13 20:26:34 -070074 name = '%s-%s' % (path.basename(args.o), h)
David Pursehouse45286f12013-05-17 13:46:40 +090075 return path.join(CACHE_DIR, name)
Shawn Pearce1b89f852013-05-13 20:26:34 -070076
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070077opts = OptionParser()
78opts.add_option('-o', help='local output file')
79opts.add_option('-u', help='URL to download')
80opts.add_option('-v', help='expected content SHA-1')
81opts.add_option('-x', action='append', help='file to delete from ZIP')
82opts.add_option('--exclude_java_sources', action='store_true')
David Ostrovsky6e0a3e52013-10-26 09:55:15 +020083opts.add_option('--unsign', action='store_true')
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070084args, _ = opts.parse_args()
85
86root_dir = args.o
Han-Wen Nienhuys28e7a6d2016-09-21 15:03:54 +020087while root_dir and root_dir != "/":
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070088 root_dir, n = path.split(root_dir)
89 if n == 'buck-out':
90 break
91
Shawn Pearce1b89f852013-05-13 20:26:34 -070092redirects = download_properties(root_dir)
David Pursehouse45286f12013-05-17 13:46:40 +090093cache_ent = cache_entry(args)
Shawn Pearce1b89f852013-05-13 20:26:34 -070094src_url = resolve_url(args.u, redirects)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070095
96if not path.exists(cache_ent):
97 try:
98 safe_mkdirs(path.dirname(cache_ent))
David Pursehouse9d9d68f2013-05-16 16:56:03 +090099 except OSError as err:
100 print('error creating directory %s: %s' %
101 (path.dirname(cache_ent), err), file=stderr)
102 exit(1)
Sasa Zivkov4709fff2013-06-13 17:01:25 +0200103
104 print('Download %s' % src_url, file=stderr)
105 try:
David Ostrovsky0883d972016-11-14 09:10:50 -0800106 check_call(['curl', '--proxy-anyauth', '-ksSfo', cache_ent, src_url])
Sasa Zivkov4709fff2013-06-13 17:01:25 +0200107 except OSError as err:
108 print('could not invoke curl: %s\nis curl installed?' % err, file=stderr)
109 exit(1)
David Pursehouse9d9d68f2013-05-16 16:56:03 +0900110 except CalledProcessError as err:
111 print('error using curl: %s' % err, file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700112 exit(1)
113
114if args.v:
Dave Borowitz868f7642015-11-18 15:25:24 -0500115 have = hash_file(sha1(), cache_ent).hexdigest()
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700116 if args.v != have:
Chirayu Desai4c5ee482013-05-13 13:48:43 +0530117 print((
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700118 '%s:\n' +
119 'expected %s\n' +
Shawn Pearceeb2eeec2013-05-22 08:54:04 -0700120 'received %s\n') % (src_url, args.v, have), file=stderr)
121 try:
122 remove(cache_ent)
123 except OSError as err:
124 if path.exists(cache_ent):
125 print('error removing %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700126 exit(1)
127
128exclude = []
129if args.x:
130 exclude += args.x
131if args.exclude_java_sources:
132 try:
David Pursehouse15a9f532014-06-23 10:55:20 +0900133 with ZipFile(cache_ent, 'r') as zf:
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700134 for n in zf.namelist():
135 if n.endswith('.java'):
136 exclude.append(n)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700137 except (BadZipfile, LargeZipFile) as err:
David Pursehouse15a9f532014-06-23 10:55:20 +0900138 print('error opening %s: %s' % (cache_ent, err), file=stderr)
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200139 exit(1)
140
141if args.unsign:
142 try:
David Pursehouse15a9f532014-06-23 10:55:20 +0900143 with ZipFile(cache_ent, 'r') as zf:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200144 for n in zf.namelist():
145 if (n.endswith('.RSA')
146 or n.endswith('.SF')
147 or n.endswith('.LIST')):
148 exclude.append(n)
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200149 except (BadZipfile, LargeZipFile) as err:
David Pursehouse15a9f532014-06-23 10:55:20 +0900150 print('error opening %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700151 exit(1)
152
153safe_mkdirs(path.dirname(args.o))
154if exclude:
David Pursehousee277fc32013-08-08 10:44:23 +0900155 try:
156 shutil.copyfile(cache_ent, args.o)
157 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200158 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900159 exit(1)
David Pursehouse14f9aa62013-05-16 17:10:09 +0900160 try:
161 check_call(['zip', '-d', args.o] + exclude)
162 except CalledProcessError as err:
163 print('error removing files from zip: %s' % err, file=stderr)
David Pursehouse8ea06502013-08-08 10:43:14 +0900164 exit(1)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700165else:
166 try:
167 link(cache_ent, args.o)
168 except OSError as err:
David Pursehousee277fc32013-08-08 10:44:23 +0900169 try:
170 shutil.copyfile(cache_ent, args.o)
171 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200172 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900173 exit(1)