Chromium Code Reviews| Index: recipe_modules/raw_io/api.py |
| diff --git a/recipe_modules/raw_io/api.py b/recipe_modules/raw_io/api.py |
| index f788a5f2491b8df9d60f662c703e0cf971c63e21..a6af03d688d4bfcaaf0c786f1b13b9d3b7dadc7e 100644 |
| --- a/recipe_modules/raw_io/api.py |
| +++ b/recipe_modules/raw_io/api.py |
| @@ -1,3 +1,4 @@ |
| +# -*- encoding: utf-8 -*- |
| # Copyright 2014 The LUCI Authors. All rights reserved. |
| # Use of this source code is governed under the Apache License, Version 2.0 |
| # that can be found in the LICENSE file. |
| @@ -30,7 +31,8 @@ class InputDataPlaceholder(recipe_util.InputPlaceholder): |
| self._backing_file = self.data |
| else: # pragma: no cover |
| input_fd, self._backing_file = tempfile.mkstemp(suffix=self.suffix) |
| - os.write(input_fd, self.data.encode('utf-8')) |
| + |
| + os.write(input_fd, self.encode_data(self.data)) |
| os.close(input_fd) |
| return [self._backing_file] |
| @@ -43,6 +45,18 @@ class InputDataPlaceholder(recipe_util.InputPlaceholder): |
| pass |
| self._backing_file = None |
| + def encode_data(self, data): |
| + return data |
| + |
| +class InputTextPlaceholder(InputDataPlaceholder): |
| + def encode_data(self, data): |
| + # Sometimes users give us invalid utf-8 data. They shouldn't, but it does |
| + # happen every once and a while. Just ignore it, and replace with �. |
| + # We're assuming users only want to write text data out. |
| + decoded = self.data.decode('utf-8', 'replace') |
| + return decoded.encode('utf-8') |
| + |
| + |
| class OutputDataPlaceholder(recipe_util.OutputPlaceholder): |
| def __init__(self, suffix, leak_to, name=None): |
| @@ -81,6 +95,12 @@ class OutputDataPlaceholder(recipe_util.OutputPlaceholder): |
| os.unlink(self._backing_file) |
| self._backing_file = None |
| + def decode(self, result): |
| + return result |
| + |
| +class OutputTextPlaceholder(OutputDataPlaceholder): |
| + def decode(self, result): |
| + return result.decode('utf-8', 'replace') |
| class OutputDataDirPlaceholder(recipe_util.OutputPlaceholder): |
| def __init__(self, suffix, leak_to, name=None): |
| @@ -138,6 +158,14 @@ class RawIOApi(recipe_api.RecipeApi): |
| @recipe_util.returns_placeholder |
| @staticmethod |
| + def input_text(data, suffix=''): |
|
iannucci
2017/02/02 02:23:30
docstring (and for input above)
|
| + return InputTextPlaceholder(data, suffix) |
| + |
| + # TODO(martiniss): Remove this once downstream callers are using text_input |
| + # input = text_input |
| + |
| + @recipe_util.returns_placeholder |
| + @staticmethod |
| def output(suffix='', leak_to=None, name=None): |
| """Returns a Placeholder for use as a step argument, or for std{out,err}. |
| @@ -152,6 +180,22 @@ class RawIOApi(recipe_api.RecipeApi): |
| @recipe_util.returns_placeholder |
| @staticmethod |
| + def output_text(suffix='', leak_to=None, name=None): |
| + """Returns a Placeholder for use as a step argument, or for std{out,err}. |
|
iannucci
2017/02/02 02:23:30
document encoding difference here and text_input.
|
| + |
| + If 'leak_to' is None, the placeholder is backed by a temporary file with |
| + a suffix 'suffix'. The file is deleted when the step finishes. |
| + |
| + If 'leak_to' is not None, then it should be a Path and placeholder |
| + redirects IO to a file at that path. Once step finishes, the file is |
| + NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case. |
| + """ |
| + return OutputTextPlaceholder(suffix, leak_to, name=name) |
| + |
| + #output = output_text |
| + |
| + @recipe_util.returns_placeholder |
| + @staticmethod |
| def output_dir(suffix='', leak_to=None, name=None): |
| """Returns a directory Placeholder for use as a step argument. |