blob: 3e6fca947ba8a757b81915f511de4a44c314abd9 [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
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070031def hashfile(p):
32 d = sha1()
33 with open(p, 'rb') as f:
34 while True:
35 b = f.read(8192)
36 if not b:
37 break
38 d.update(b)
39 return d.hexdigest()
40
41def safe_mkdirs(d):
42 if path.isdir(d):
43 return
44 try:
45 makedirs(d)
46 except OSError as err:
47 if not path.isdir(d):
48 raise err
49
Shawn Pearce1b89f852013-05-13 20:26:34 -070050def download_properties(root_dir):
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090051 """ Get the download properties.
52
53 First tries to find the properties file in the given root directory,
54 and if not found there, tries in the Gerrit settings folder in the
55 user's home directory.
56
57 Returns a set of download properties, which may be empty.
58
59 """
Shawn Pearce1b89f852013-05-13 20:26:34 -070060 p = {}
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090061 local_prop = path.join(root_dir, LOCAL_PROPERTIES)
62 if not path.isfile(local_prop):
David Pursehouse45286f12013-05-17 13:46:40 +090063 local_prop = path.join(GERRIT_HOME, LOCAL_PROPERTIES)
Shawn Pearce1b89f852013-05-13 20:26:34 -070064 if path.isfile(local_prop):
65 try:
66 with open(local_prop) as fd:
67 for line in fd:
68 if line.startswith('download.'):
69 d = [e.strip() for e in line.split('=', 1)]
70 name, url = d[0], d[1]
71 p[name[len('download.'):]] = url
David Pursehouse6fb2c4d2013-05-16 16:51:46 +090072 except OSError:
Shawn Pearce1b89f852013-05-13 20:26:34 -070073 pass
74 return p
75
David Pursehouse45286f12013-05-17 13:46:40 +090076def cache_entry(args):
Shawn Pearce1b89f852013-05-13 20:26:34 -070077 if args.v:
78 h = args.v
79 else:
80 h = sha1(args.u).hexdigest()
81 name = '%s-%s' % (path.basename(args.o), h)
David Pursehouse45286f12013-05-17 13:46:40 +090082 return path.join(CACHE_DIR, name)
Shawn Pearce1b89f852013-05-13 20:26:34 -070083
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070084opts = OptionParser()
85opts.add_option('-o', help='local output file')
86opts.add_option('-u', help='URL to download')
87opts.add_option('-v', help='expected content SHA-1')
88opts.add_option('-x', action='append', help='file to delete from ZIP')
89opts.add_option('--exclude_java_sources', action='store_true')
David Ostrovsky6e0a3e52013-10-26 09:55:15 +020090opts.add_option('--unsign', action='store_true')
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -070091args, _ = opts.parse_args()
92
93root_dir = args.o
94while root_dir:
95 root_dir, n = path.split(root_dir)
96 if n == 'buck-out':
97 break
98
Shawn Pearce1b89f852013-05-13 20:26:34 -070099redirects = download_properties(root_dir)
David Pursehouse45286f12013-05-17 13:46:40 +0900100cache_ent = cache_entry(args)
Shawn Pearce1b89f852013-05-13 20:26:34 -0700101src_url = resolve_url(args.u, redirects)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700102
103if not path.exists(cache_ent):
104 try:
105 safe_mkdirs(path.dirname(cache_ent))
David Pursehouse9d9d68f2013-05-16 16:56:03 +0900106 except OSError as err:
107 print('error creating directory %s: %s' %
108 (path.dirname(cache_ent), err), file=stderr)
109 exit(1)
Sasa Zivkov4709fff2013-06-13 17:01:25 +0200110
111 print('Download %s' % src_url, file=stderr)
112 try:
113 check_call(['curl', '--proxy-anyauth', '-sfo', cache_ent, src_url])
114 except OSError as err:
115 print('could not invoke curl: %s\nis curl installed?' % err, file=stderr)
116 exit(1)
David Pursehouse9d9d68f2013-05-16 16:56:03 +0900117 except CalledProcessError as err:
118 print('error using curl: %s' % err, file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700119 exit(1)
120
121if args.v:
122 have = hashfile(cache_ent)
123 if args.v != have:
Chirayu Desai4c5ee482013-05-13 13:48:43 +0530124 print((
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700125 '%s:\n' +
126 'expected %s\n' +
Shawn Pearceeb2eeec2013-05-22 08:54:04 -0700127 'received %s\n') % (src_url, args.v, have), file=stderr)
128 try:
129 remove(cache_ent)
130 except OSError as err:
131 if path.exists(cache_ent):
132 print('error removing %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700133 exit(1)
134
135exclude = []
136if args.x:
137 exclude += args.x
138if args.exclude_java_sources:
139 try:
140 zf = ZipFile(cache_ent, 'r')
141 try:
142 for n in zf.namelist():
143 if n.endswith('.java'):
144 exclude.append(n)
145 finally:
146 zf.close()
147 except (BadZipfile, LargeZipFile) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200148 print('error opening %s: %s' % (cache_ent, err), file=stderr)
149 exit(1)
150
151if args.unsign:
152 try:
153 zf = ZipFile(cache_ent, 'r')
154 try:
155 for n in zf.namelist():
156 if (n.endswith('.RSA')
157 or n.endswith('.SF')
158 or n.endswith('.LIST')):
159 exclude.append(n)
160 finally:
161 zf.close()
162 except (BadZipfile, LargeZipFile) as err:
163 print('error opening %s: %s' % (cache_ent, err), file=stderr)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700164 exit(1)
165
166safe_mkdirs(path.dirname(args.o))
167if exclude:
David Pursehousee277fc32013-08-08 10:44:23 +0900168 try:
169 shutil.copyfile(cache_ent, args.o)
170 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200171 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900172 exit(1)
David Pursehouse14f9aa62013-05-16 17:10:09 +0900173 try:
174 check_call(['zip', '-d', args.o] + exclude)
175 except CalledProcessError as err:
176 print('error removing files from zip: %s' % err, file=stderr)
David Pursehouse8ea06502013-08-08 10:43:14 +0900177 exit(1)
Shawn Pearcefd6bb9f2013-05-08 14:14:24 -0700178else:
179 try:
180 link(cache_ent, args.o)
181 except OSError as err:
David Pursehousee277fc32013-08-08 10:44:23 +0900182 try:
183 shutil.copyfile(cache_ent, args.o)
184 except (shutil.Error, IOError) as err:
David Ostrovsky6e0a3e52013-10-26 09:55:15 +0200185 print('error copying to %s: %s' % (args.o, err), file=stderr)
David Pursehousee277fc32013-08-08 10:44:23 +0900186 exit(1)