blob: d5d8b66b74c3139ad646183250f5699adabd08a3 [file] [log] [blame]
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -07001#!/usr/bin/python
2# 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
David Ostrovsky2536d062013-11-14 00:35:07 +010024from util import 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')
28CACHE_DIR = path.join(GERRIT_HOME, 'buck-cache')
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 hashfile(p):
33 d = sha1()
34 with open(p, 'rb') as f:
35 while True:
36 b = f.read(8192)
37 if not b:
38 break
39 d.update(b)
40 return d.hexdigest()
41
David Pursehouse15a9f532014-06-23 10:55:20 +090042
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070043def safe_mkdirs(d):
44 if path.isdir(d):
45 return
46 try:
47 makedirs(d)
48 except OSError as err:
49 if not path.isdir(d):
50 raise err
51
David Pursehouse15a9f532014-06-23 10:55:20 +090052
Shawn Pearce1b89f852013-05-13 20:26:34 -070053def download_properties(root_dir):
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090054 """ Get the download properties.
55
56 First tries to find the properties file in the given root directory,
57 and if not found there, tries in the Gerrit settings folder in the
58 user's home directory.
59
60 Returns a set of download properties, which may be empty.
61
62 """
Shawn Pearce1b89f852013-05-13 20:26:34 -070063 p = {}
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090064 local_prop = path.join(root_dir, LOCAL_PROPERTIES)
65 if not path.isfile(local_prop):
David Pursehouse45286f12013-05-17 13:46:40 +090066 local_prop = path.join(GERRIT_HOME, LOCAL_PROPERTIES)
Shawn Pearce1b89f852013-05-13 20:26:34 -070067 if path.isfile(local_prop):
68 try:
69 with open(local_prop) as fd:
70 for line in fd:
71 if line.startswith('download.'):
72 d = [e.strip() for e in line.split('=', 1)]
73 name, url = d[0], d[1]
74 p[name[len('download.'):]] = url
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090075 except OSError:
Shawn Pearce1b89f852013-05-13 20:26:34 -070076 pass
77 return p
78
David Pursehouse15a9f532014-06-23 10:55:20 +090079
David Pursehouse45286f12013-05-17 13:46:40 +090080def cache_entry(args):
Shawn Pearce1b89f852013-05-13 20:26:34 -070081 if args.v:
82 h = args.v
83 else:
Urs Wolfera11276a2014-04-26 13:20:00 +020084 h = sha1(args.u.encode('utf-8')).hexdigest()
Shawn Pearce1b89f852013-05-13 20:26:34 -070085 name = '%s-%s' % (path.basename(args.o), h)
David Pursehouse45286f12013-05-17 13:46:40 +090086 return path.join(CACHE_DIR, name)
Shawn Pearce1b89f852013-05-13 20:26:34 -070087
David Pursehouse15a9f532014-06-23 10:55:20 +090088
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070089opts = OptionParser()
90opts.add_option('-o', help='local output file')
91opts.add_option('-u', help='URL to download')
92opts.add_option('-v', help='expected content SHA-1')
93opts.add_option('-x', action='append', help='file to delete from ZIP')
94opts.add_option('--exclude_java_sources', action='store_true')
David Ostrovsky6e0a3e52013-10-26 09:55:15 +020095opts.add_option('--unsign', action='store_true')
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070096args, _ = opts.parse_args()
97
98root_dir = args.o
99while root_dir:
100 root_dir, n = path.split(root_dir)
101 if n == 'buck-out':
102 break
103
Shawn Pearce1b89f852013-05-13 20:26:34 -0700104redirects = download_properties(root_dir)
David Pursehouse45286f12013-05-17 13:46:40 +0900105cache_ent = cache_entry(args)
Shawn Pearce1b89f852013-05-13 20:26:34 -0700106src_url = resolve_url(args.u, redirects)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700107
108if not path.exists(cache_ent):
109 try:
110 safe_mkdirs(path.dirname(cache_ent))
David Pursehouse9d9d68f2013-05-16 16:56:03 +0900111 except OSError as err:
112 print('error creating directory %s: %s' %
113 (path.dirname(cache_ent), err), file=stderr)
114 exit(1)
Sasa Zivkov4709fff2013-06-13 17:01:25 +0200115
116 print('Download %s' % src_url, file=stderr)
117 try:
118 check_call(['curl', '--proxy-anyauth', '-sfo', cache_ent, src_url])
119 except OSError as err:
120 print('could not invoke curl: %s\nis curl installed?' % err, file=stderr)
121 exit(1)
David Pursehouse9d9d68f2013-05-16 16:56:03 +0900122 except CalledProcessError as err:
123 print('error using curl: %s' % err, file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700124 exit(1)
125
126if args.v:
127 have = hashfile(cache_ent)
128 if args.v != have:
Chirayu Desai4c5ee482013-05-13 13:48:43 +0530129 print((
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700130 '%s:\n' +
131 'expected %s\n' +
Shawn Pearceeb2eeec2013-05-22 08:54:04 -0700132 'received %s\n') % (src_url, args.v, have), file=stderr)
133 try:
134 remove(cache_ent)
135 except OSError as err:
136 if path.exists(cache_ent):
137 print('error removing %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700138 exit(1)
139
140exclude = []
141if args.x:
142 exclude += args.x
143if args.exclude_java_sources:
144 try:
David Pursehouse15a9f532014-06-23 10:55:20 +0900145 with ZipFile(cache_ent, 'r') as zf:
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700146 for n in zf.namelist():
147 if n.endswith('.java'):
148 exclude.append(n)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700149 except (BadZipfile, LargeZipFile) as err:
David Pursehouse15a9f532014-06-23 10:55:20 +0900150 print('error opening %s: %s' % (cache_ent, err), file=stderr)
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200151 exit(1)
152
153if args.unsign:
154 try:
David Pursehouse15a9f532014-06-23 10:55:20 +0900155 with ZipFile(cache_ent, 'r') as zf:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200156 for n in zf.namelist():
157 if (n.endswith('.RSA')
158 or n.endswith('.SF')
159 or n.endswith('.LIST')):
160 exclude.append(n)
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200161 except (BadZipfile, LargeZipFile) as err:
David Pursehouse15a9f532014-06-23 10:55:20 +0900162 print('error opening %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700163 exit(1)
164
165safe_mkdirs(path.dirname(args.o))
166if exclude:
David Pursehousee277fc32013-08-08 10:44:23 +0900167 try:
168 shutil.copyfile(cache_ent, args.o)
169 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200170 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900171 exit(1)
David Pursehouse14f9aa62013-05-16 17:10:09 +0900172 try:
173 check_call(['zip', '-d', args.o] + exclude)
174 except CalledProcessError as err:
175 print('error removing files from zip: %s' % err, file=stderr)
David Pursehouse8ea06502013-08-08 10:43:14 +0900176 exit(1)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700177else:
178 try:
179 link(cache_ent, args.o)
180 except OSError as err:
David Pursehousee277fc32013-08-08 10:44:23 +0900181 try:
182 shutil.copyfile(cache_ent, args.o)
183 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200184 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900185 exit(1)