Skip to content

Commit

Permalink
Save patches to files before applying
Browse files Browse the repository at this point in the history
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
  • Loading branch information
stephenfin committed Dec 11, 2017
1 parent 5830f63 commit 8eeed51
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 8 deletions.
34 changes: 31 additions & 3 deletions git_pw/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"""

import logging
import os
import sys
import tempfile

import requests

Expand Down Expand Up @@ -88,13 +90,14 @@ def _handle_error(operation, exc):
sys.exit(1)


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

try:
rsp = requests.get(url, auth=_get_auth(), headers=_get_headers(),
params=params)
params=params, stream=stream)
rsp.raise_for_status()
except requests.exceptions.RequestException as exc:
_handle_error('fetch', exc)
Expand All @@ -120,6 +123,31 @@ def put(url, data): # type: (str, dict) -> requests.Response
return rsp


def download(url, params=None): # type: (str, dict) -> None
"""Retrieve a specific API resource and save it to a file.
GET /{resource}/{resourceID}/
Arguments:
resource_type (str): The resource endpoint name.
resource_id (int/str): The ID for the specific resource.
params (dict/list): Additional parameters.
Returns:
A path to an output file containing the content.
"""
output_fd, output_path = tempfile.mkstemp(suffix='.patch')

rsp = get(url, params, stream=True)
with os.fdopen(output_fd, 'w') as output_file:
LOG.debug('Saving to %s', output_path)
# we use iter_content because patches can be binary
for block in rsp.iter_content(1024):
output_file.write(block)

return output_path


def index(resource_type, params=None): # type: (str, dict) -> dict
"""List API resources.
Expand Down Expand Up @@ -164,7 +192,7 @@ def detail(resource_type, resource_id, params=None):
url = '/'.join([_get_server(), 'api', resource_type,
str(resource_id), ''])

return get(url, params).json()
return get(url, params, stream=False).json()


def update(resource_type, resource_id, data):
Expand Down
2 changes: 1 addition & 1 deletion git_pw/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def apply_cmd(bundle_id, args):
LOG.info('Applying bundle: id=%d', bundle_id)

bundle = api.detail('bundles', bundle_id)
mbox = api.get(bundle['mbox']).text
mbox = api.download(bundle['mbox']).text

utils.git_am(mbox, args)

Expand Down
2 changes: 1 addition & 1 deletion git_pw/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def apply_cmd(patch_id, series, deps, args):
elif not deps:
series = None

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

utils.git_am(mbox, args)

Expand Down
2 changes: 1 addition & 1 deletion git_pw/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def apply_cmd(series_id, args):
LOG.info('Applying series: id=%d, args=%s', series_id, ' '.join(args))

series = api.detail('series', series_id)
mbox = api.get(series['mbox']).text
mbox = api.download(series['mbox'])

utils.git_am(mbox, args)

Expand Down
7 changes: 5 additions & 2 deletions git_pw/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ def git_am(mbox, args):
cmd.append('-3')
cmd.append(mbox)

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

0 comments on commit 8eeed51

Please sign in to comment.