Build API: Allow output with non-zero return codes.
BUG=None
TEST=run_tests
Change-Id: Iec5d02ced71755c3e97d611e2c269ae9e4479ac8
Reviewed-on: https://chromium-review.googlesource.com/1534542
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Alex Klein <saklein@chromium.org>
Reviewed-by: Lann Martin <lannm@chromium.org>
diff --git a/scripts/build_api.py b/scripts/build_api.py
index 9119133..9f41400 100644
--- a/scripts/build_api.py
+++ b/scripts/build_api.py
@@ -8,6 +8,7 @@
from __future__ import print_function
import importlib
+import os
from google.protobuf import json_format
from google.protobuf import symbol_database
@@ -28,10 +29,18 @@
"""Base error class for the module."""
+class InvalidInputFileError(Error):
+ """Raised when the input file cannot be read."""
+
+
class InvalidInputFormatError(Error):
"""Raised when the passed input protobuf can't be parsed."""
+class InvalidOutputFileError(Error):
+ """Raised when the output file cannot be written."""
+
+
# API Service Errors.
class UnknownServiceError(Error):
"""Error raised when the requested service has not been registered."""
@@ -94,6 +103,9 @@
opts.service = parts[0]
opts.method = parts[1]
+ if not os.path.exists(opts.input_json):
+ parser.error('Input file does not exist.')
+
opts.Freeze()
return opts
@@ -142,23 +154,30 @@
return sorted(services)
- def Route(self, service_name, method_name, input_json):
+ def Route(self, service_name, method_name, input_path, output_path):
"""Dispatch the request.
Args:
service_name (str): The fully qualified service name.
method_name (str): The name of the method being called.
- input_json (str): The JSON encoded input message data.
+ input_path (str): The path to the input message file.
+ output_path (str): The path where the output message should be written.
Returns:
- google.protobuf.message.Message: An instance of the method's output
- message class.
+ int: The return code.
Raises:
+ InvalidInputFileError when the input file cannot be read.
+ InvalidOutputFileError when the output file cannot be written.
ServiceModuleNotFoundError when the service module cannot be imported.
MethodNotFoundError when the method cannot be retrieved from the module.
"""
try:
+ input_json = osutils.ReadFile(input_path)
+ except IOError as e:
+ raise InvalidInputFileError('Unable to read input file: %s' % e.message)
+
+ try:
svc, module_name = self._services[service_name]
except KeyError:
raise UnknownServiceError('The %s service has not been registered.'
@@ -194,8 +213,16 @@
method_impl = self._GetMethod(module_name, method_name)
# Successfully located; call and return.
- method_impl(input_msg, output_msg)
- return output_msg
+ return_code = method_impl(input_msg, output_msg)
+ if return_code is None:
+ return_code = 0
+
+ try:
+ osutils.WriteFile(output_path, json_format.MessageToJson(output_msg))
+ except IOError as e:
+ raise InvalidOutputFileError('Cannot write output file: %s' % e.message)
+
+ return return_code
def _HandleChrootAssert(self, service_options, method_options):
"""Check the chroot assert options and execute assertion as needed.
@@ -261,18 +288,8 @@
opts = _ParseArgs(argv, router)
try:
- input_proto = osutils.ReadFile(opts.input_json)
- except IOError as e:
- cros_build_lib.Die('Unable to read input file: %s' % e.message)
-
- try:
- output_msg = router.Route(opts.service, opts.method, input_proto)
+ return router.Route(opts.service, opts.method, opts.input_json,
+ opts.output_json)
except Error as e:
# Error derivatives are handled nicely, but let anything else bubble up.
cros_build_lib.Die(e.message)
-
- output_content = json_format.MessageToJson(output_msg)
- try:
- osutils.WriteFile(opts.output_json, output_content)
- except IOError as e:
- cros_build_lib.Die('Unable to write output file: %s' % e.message)