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

Side by Side Diff: recipe_modules/url/api.py

Issue 2868333004: Add URL recipe module from "depot_tools". (Closed)
Patch Set: response api object 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 # Copyright 2017 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file.
4
5 from recipe_engine import recipe_api
6
7 import urllib
8
9 class UrlApi(recipe_api.RecipeApi):
10 quote = staticmethod(urllib.quote)
iannucci 2017/05/12 00:53:52 buh? staticmethod shouldn't be needed
dnj 2017/05/12 02:15:04 Done.
11 urlencode = staticmethod(urllib.urlencode)
12
13 # JSON prefix used with Gerrit and Gitiles.
14 GERRIT_JSON_PREFIX = ')]}\n'
15
16
17 class Response(object):
iannucci 2017/05/12 00:53:52 note: capture error body and stuff in different fi
dnj 2017/05/12 02:15:04 Done.
18 """Response is an HTTP response object."""
19
20 def __init__(self, method, output, status):
21 self._method = method
22 self._status = status
23 self._result = output
24
25 @property
26 def method(self):
iannucci 2017/05/12 00:53:52 DOOOOGGGGG STRIIING
dnj 2017/05/12 02:15:04 Done.
27 return self._method
28
29 @property
30 def status_code(self):
31 return self._status['status_code']
32
33 def raise_on_error(self):
34 if not self._status['success']:
35 raise ValueError('HTTP status (%d)' % (self.status_code,))
iannucci 2017/05/12 00:53:52 real exception?
dnj 2017/05/12 02:15:04 Done.
36
37 @property
38 def output(self):
39 return self._result
40
41
42 @recipe_api.non_step
43 def join(self, *parts):
44 """Constructs a URL path from composite parts.
45
46 Args:
47 parts (str...): Strings to concastenate. Any leading or trailing slashes
48 will be stripped from intermediate strings to ensure that they join
49 together. Trailing slashes will not be stripped from the last part.
50 """
51 if parts:
52 parts = list(parts)
53 if len(parts) > 1:
54 for i, p in enumerate(parts[:-1]):
55 parts[i] = p.strip('/')
56 parts[-1] = parts[-1].lstrip('/')
57 return '/'.join(parts)
58
59 def get_file(self, url, path, step_name=None, headers=None,
60 transient_retry=True, strip_prefix=None, **kwargs):
61 """GET data at given URL and writes it to file.
62
63 Args:
64 url: URL to request.
65 path (Path): the Path where the content will be written.
66 step_name: optional step name, 'fetch <url>' by default.
67 headers: a {header_name: value} dictionary for HTTP headers.
68 transient_retry (bool): If True (default), transient HTTP errors (>500)
69 will automatically be retried with exponential backoff. If False,
70 exactly one attempt will be made.
71 strip_prefix (str or None): If not None, this prefix must be present at
72 the beginning of the response, and will be stripped from the resulting
73 content (e.g., GERRIT_JSON_PREFIX).
74
75 Returns:
76 Response with "path" as its "output" value.
77 """
78 return self._get_step(url, path, step_name, headers, transient_retry,
79 strip_prefix, False, **kwargs)
80
81 def must_get_file(self, *args, **kwargs):
82 """Like "get_file", but always raises an exception on error."""
83 resp = self.get_file(*args, **kwargs)
84 resp.raise_on_error()
85 return resp
86
87 def get_text(self, url, step_name=None, headers=None, transient_retry=True,
88 **kwargs):
89 """GET data at given URL and writes it to file.
90
91 Args:
92 url: URL to request.
93 step_name: optional step name, 'fetch <url>' by default.
94 headers: a {header_name: value} dictionary for HTTP headers.
95 transient_retry (bool): If True (default), transient HTTP errors (>500)
96 will automatically be retried with exponential backoff. If False,
97 exactly one attempt will be made.
98
99 Returns:
100 Response with a string "output" value.
101 """
102 return self._get_step(url, None, step_name, headers, transient_retry,
103 None, False, **kwargs)
104
105 def must_get_text(self, *args, **kwargs):
106 """Like "get_text", but always raises an exception on error."""
107 resp = self.get_text(*args, **kwargs)
108 resp.raise_on_error()
109 return resp
110
111 def get_json(self, url, step_name=None, headers=None, transient_retry=True,
112 strip_prefix=None, log=False, **kwargs):
iannucci 2017/05/12 00:53:52 no kwargs just passthrough timeout
dnj 2017/05/12 02:15:04 Done.
113 """GET data at given URL and writes it to file.
114
115 Args:
116 url: URL to request.
117 step_name: optional step name, 'fetch <url>' by default.
118 headers: a {header_name: value} dictionary for HTTP headers.
119 transient_retry (bool): If True (default), transient HTTP errors (>500)
120 will automatically be retried with exponential backoff. If False,
121 exactly one attempt will be made.
122 strip_prefix (str or None): If not None, this prefix must be present at
123 the beginning of the response, and will be stripped from the resulting
124 content (e.g., GERRIT_JSON_PREFIX).
125 log (bool): If True, emit the JSON content as a log.
126
127 Returns:
128 Response with JSON "output" value.
129 """
130 return self._get_step(url, None, step_name, headers, transient_retry,
131 strip_prefix, 'log' if log else True, **kwargs)
132
133 def must_get_json(self, *args, **kwargs):
134 """Like "get_json", but always raises an exception on error."""
135 resp = self.get_json(*args, **kwargs)
136 resp.raise_on_error()
137 return resp
138
139 def _get_step(self, url, path, step_name, headers, transient_retry,
140 strip_prefix, as_json, **kwargs):
141 step_name = step_name or 'GET %s' % url
142
143 args = [
144 url,
145 '--status-json', self.m.json.output(add_json_log=False,
146 name='status_json'),
147 ]
148
149 if as_json:
150 log = as_json == 'log'
151 args += ['--outfile', self.m.json.output(add_json_log=log,
152 name='output')]
153 else:
154 args += ['--outfile', self.m.raw_io.output_text(leak_to=path,
155 name='output')]
156
157 if headers:
158 args += ['--headers-json', self.m.json.input(headers)]
159 if strip_prefix:
160 args += ['--strip-prefix', strip_prefix]
161 if not transient_retry:
162 args.append('--no-transient-retry')
163
164 result = self.m.python(
165 step_name,
166 self.resource('pycurl.py'),
167 args=args,
168 venv=True,
169 **kwargs)
170 status = result.json.outputs['status_json']
171
172 output = path
173 if not output:
174 if as_json:
175 output = result.json.outputs['output']
176 else:
177 output = result.raw_io.output_texts['output']
178 return self.Response('GET', output, status)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698