Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Side by Side Diff: recipe_modules/url/resources/pycurl.py

Issue 2868333004: Add URL recipe module from "depot_tools". (Closed)
Patch Set: fix/texst urllib methods, remove non_step Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2017 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file.
5
6 # NOTE: This was imported from Chromium's "tools/build" at revision:
7 # 65976b6e2a612439681dc42830e90dbcdf550f40
8
9 import argparse
10 import json
11 import logging
12 import os
13 import sys
14 import time
15
16 import requests
17 import requests.adapters
18 import requests.models
19 from requests.packages.urllib3.util.retry import Retry
20
21 # Size of chunks (4MiB).
22 CHUNK_SIZE = 1024 * 1024 * 4
23
24
25 def _download(url, outfile, headers, transient_retry, strip_prefix):
26 s = requests.Session()
27 if transient_retry:
28 # See http://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html
29 retry = Retry(
30 total=10,
31 connect=5,
32 read=5,
33 redirect=5,
34 status_forcelist=range(500, 600),
35 backoff_factor=0.2,
36 )
37 print retry
38 s.mount(url, requests.adapters.HTTPAdapter(max_retries=retry))
39
40
41 logging.info('Connecting...')
42 r = s.get(url, headers=headers, stream=True)
43 if r.status_code != requests.codes.ok:
44 r.raise_for_status()
45
46 if outfile:
47 fd = open(outfile, 'wb')
48 else:
49 fd = sys.stdout
50
51 total = 0
52 with fd:
53 logging.info('Downloading...')
54 for chunk in r.iter_content(CHUNK_SIZE):
55 total += len(chunk)
56
57 if strip_prefix:
58 prefix = chunk[:len(strip_prefix)]
59 if prefix != strip_prefix:
60 raise ValueError(
61 'Expected prefix was not observed: [%s] != [%s]...' % (
62 prefix, strip_prefix))
63 chunk = chunk[len(strip_prefix):]
64 strip_prefix = None
65
66 fd.write(chunk)
67 logging.info('Downloaded %.1f MB so far', total / 1024 / 1024)
68 return r.status_code, total
69
70
71 def main():
72 parser = argparse.ArgumentParser(
73 description='Get a url and print its document.',
74 prog='./runit.py pycurl.py')
75 parser.add_argument('--url', required=True, help='the url to fetch')
76 parser.add_argument('--status-json', metavar='PATH', required=True,
77 help='Write HTTP status result JSON. If set, all complete HTTP '
78 'responses will exit with 0, regardless of their status code.')
79
80 parser.add_argument('--no-transient-retry', action='store_true',
81 help='Do not perform automatic retries on transient failures.')
82 parser.add_argument('--headers-json', type=argparse.FileType('r'),
83 help='A json file containing any headers to include with the request.')
84 parser.add_argument('--outfile', help='write output to this file')
85 parser.add_argument('--strip-prefix', action='store',
86 help='Expect this string at the beginning of the response, and strip it.')
87
88 args = parser.parse_args()
89
90 headers = None
91 if args.headers_json:
92 headers = json.load(args.headers_json)
93
94 if args.strip_prefix and len(args.strip_prefix) > CHUNK_SIZE:
95 raise ValueError('Prefix length (%d) must be <= chunk size (%d)' % (
96 len(args.strip_prefix), CHUNK_SIZE))
97
98 status = {}
99 try:
100 status_code, size = _download(
101 args.url, args.outfile, headers, not args.no_transient_retry,
102 args.strip_prefix)
103 status = {
104 'status_code': status_code,
105 'success': True,
106 'size': size,
107 }
108 except requests.HTTPError as e:
109 body = e.response.text
110 status = {
111 'status_code': e.response.status_code,
112 'success': False,
113 'size': len(body),
114 'error_body': body,
115 }
116
117 with open(args.status_json, 'w') as fd:
118 json.dump(status, fd)
119 return 0
120
121
122 if __name__ == '__main__':
123 logging.basicConfig()
124 logging.getLogger().setLevel(logging.INFO)
125 logging.getLogger("requests").setLevel(logging.DEBUG)
126 sys.exit(main())
127
128
129 ##
130 # The following section is read by "vpython" and used to construct the
131 # VirtualEnv for this tool.
132 #
133 # These imports were lifted from "/bootstrap/venv.cfg".
134 ##
135 # [VPYTHON:BEGIN]
136 #
137 # wheel: <
138 # name: "infra/python/wheels/cryptography/${platform}_${py_version}_${py_abi}"
139 # version: "version:1.8.1"
140 # >
141 #
142 # wheel: <
143 # name: "infra/python/wheels/appdirs-py2_py3"
144 # version: "version:1.4.3"
145 # >
146 #
147 # wheel: <
148 # name: "infra/python/wheels/asn1crypto-py2_py3"
149 # version: "version:0.22.0"
150 # >
151 #
152 # wheel: <
153 # name: "infra/python/wheels/enum34-py2"
154 # version: "version:1.1.6"
155 # >
156 #
157 # wheel: <
158 # name: "infra/python/wheels/cffi/${platform}_${py_version}_${py_abi}"
159 # version: "version:1.10.0"
160 # >
161 #
162 # wheel: <
163 # name: "infra/python/wheels/idna-py2_py3"
164 # version: "version:2.5"
165 # >
166 #
167 # wheel: <
168 # name: "infra/python/wheels/ipaddress-py2"
169 # version: "version:1.0.18"
170 # >
171 #
172 # wheel: <
173 # name: "infra/python/wheels/packaging-py2_py3"
174 # version: "version:16.8"
175 # >
176 #
177 # wheel: <
178 # name: "infra/python/wheels/pyasn1-py2_py3"
179 # version: "version:0.2.3"
180 # >
181 #
182 # wheel: <
183 # name: "infra/python/wheels/pycparser-py2_py3"
184 # version: "version:2.17"
185 # >
186 #
187 # wheel: <
188 # name: "infra/python/wheels/pyopenssl-py2_py3"
189 # version: "version:17.0.0"
190 # >
191 #
192 # wheel: <
193 # name: "infra/python/wheels/pyparsing-py2_py3"
194 # version: "version:2.2.0"
195 # >
196 #
197 # wheel: <
198 # name: "infra/python/wheels/setuptools-py2_py3"
199 # version: "version:34.3.2"
200 # >
201 #
202 # wheel: <
203 # name: "infra/python/wheels/six-py2_py3"
204 # version: "version:1.10.0"
205 # >
206 #
207 # wheel: <
208 # name: "infra/python/wheels/requests-py2_py3"
209 # version: "version:2.13.0"
210 # >
211 #
212 # [VPYTHON:END]
213 ##
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698