Skip to content

Commit 8eeed51

Browse files
committed
Save patches to files before applying
This allows us to minimize the possibility of unicode/bytes issues on different Python versions and to avoid reading entire patches into memory. Signed-off-by: Stephen Finucane <[email protected]> Fixes: #6
1 parent 5830f63 commit 8eeed51

File tree

6 files changed

+46
-8
lines changed

6 files changed

+46
-8
lines changed

git_pw/api.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"""
44

55
import logging
6+
import os
67
import sys
8+
import tempfile
79

810
import requests
911

@@ -88,13 +90,14 @@ def _handle_error(operation, exc):
8890
sys.exit(1)
8991

9092

91-
def get(url, params=None): # type: (str, dict) -> requests.Response
93+
def get(url, params=None, stream=False):
94+
# type: (str, dict, bool) -> requests.Response
9295
"""Make GET request and handle errors."""
9396
LOG.debug('GET %s', url)
9497

9598
try:
9699
rsp = requests.get(url, auth=_get_auth(), headers=_get_headers(),
97-
params=params)
100+
params=params, stream=stream)
98101
rsp.raise_for_status()
99102
except requests.exceptions.RequestException as exc:
100103
_handle_error('fetch', exc)
@@ -120,6 +123,31 @@ def put(url, data): # type: (str, dict) -> requests.Response
120123
return rsp
121124

122125

126+
def download(url, params=None): # type: (str, dict) -> None
127+
"""Retrieve a specific API resource and save it to a file.
128+
129+
GET /{resource}/{resourceID}/
130+
131+
Arguments:
132+
resource_type (str): The resource endpoint name.
133+
resource_id (int/str): The ID for the specific resource.
134+
params (dict/list): Additional parameters.
135+
136+
Returns:
137+
A path to an output file containing the content.
138+
"""
139+
output_fd, output_path = tempfile.mkstemp(suffix='.patch')
140+
141+
rsp = get(url, params, stream=True)
142+
with os.fdopen(output_fd, 'w') as output_file:
143+
LOG.debug('Saving to %s', output_path)
144+
# we use iter_content because patches can be binary
145+
for block in rsp.iter_content(1024):
146+
output_file.write(block)
147+
148+
return output_path
149+
150+
123151
def index(resource_type, params=None): # type: (str, dict) -> dict
124152
"""List API resources.
125153
@@ -164,7 +192,7 @@ def detail(resource_type, resource_id, params=None):
164192
url = '/'.join([_get_server(), 'api', resource_type,
165193
str(resource_id), ''])
166194

167-
return get(url, params).json()
195+
return get(url, params, stream=False).json()
168196

169197

170198
def update(resource_type, resource_id, data):

git_pw/bundle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def apply_cmd(bundle_id, args):
2525
LOG.info('Applying bundle: id=%d', bundle_id)
2626

2727
bundle = api.detail('bundles', bundle_id)
28-
mbox = api.get(bundle['mbox']).text
28+
mbox = api.download(bundle['mbox']).text
2929

3030
utils.git_am(mbox, args)
3131

git_pw/patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def apply_cmd(patch_id, series, deps, args):
3838
elif not deps:
3939
series = None
4040

41-
mbox = api.get(patch['mbox'], {'series': series}).content
41+
mbox = api.download(patch['mbox'], {'series': series})
4242

4343
utils.git_am(mbox, args)
4444

git_pw/series.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def apply_cmd(series_id, args):
2626
LOG.info('Applying series: id=%d, args=%s', series_id, ' '.join(args))
2727

2828
series = api.detail('series', series_id)
29-
mbox = api.get(series['mbox']).text
29+
mbox = api.download(series['mbox'])
3030

3131
utils.git_am(mbox, args)
3232

git_pw/utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@ def git_am(mbox, args):
2020
cmd.append('-3')
2121
cmd.append(mbox)
2222

23-
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
24-
p.communicate(mbox)
23+
try:
24+
subprocess.check_output(cmd, stderr=subprocess.STDOUT)
25+
except subprocess.CalledProcessError as exc:
26+
print(exc.output)
27+
sys.exit(exc.returncode)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
fixes:
3+
- |
4+
The ``git pw {patch,series,bundle} apply`` commands will now save the
5+
downloaded patches before applying them. This avoids ascii/unicode issues
6+
on different versions of Python and avoids the need to load the entire
7+
patch into memory.

0 commit comments

Comments
 (0)