OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright 2015 Google Inc. |
| 4 # |
| 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 # you may not use this file except in compliance with the License. |
| 7 # You may obtain a copy of the License at |
| 8 # |
| 9 # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 # |
| 11 # Unless required by applicable law or agreed to in writing, software |
| 12 # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 # See the License for the specific language governing permissions and |
| 15 # limitations under the License. |
| 16 |
| 17 """Base script for generated CLI.""" |
| 18 |
| 19 import atexit |
| 20 import code |
| 21 import logging |
| 22 import os |
| 23 import readline |
| 24 import rlcompleter |
| 25 import sys |
| 26 |
| 27 from google.apputils import appcommands |
| 28 import gflags as flags |
| 29 |
| 30 from apitools.base.py import encoding |
| 31 from apitools.base.py import exceptions |
| 32 |
| 33 __all__ = [ |
| 34 'ConsoleWithReadline', |
| 35 'DeclareBaseFlags', |
| 36 'FormatOutput', |
| 37 'SetupLogger', |
| 38 'run_main', |
| 39 ] |
| 40 |
| 41 |
| 42 # TODO(craigcitro): We should move all the flags for the |
| 43 # StandardQueryParameters into this file, so that they can be used |
| 44 # elsewhere easily. |
| 45 |
| 46 _BASE_FLAGS_DECLARED = False |
| 47 _OUTPUT_FORMATTER_MAP = { |
| 48 'protorpc': lambda x: x, |
| 49 'json': encoding.MessageToJson, |
| 50 } |
| 51 |
| 52 |
| 53 def DeclareBaseFlags(): |
| 54 """Declare base flags for all CLIs.""" |
| 55 # TODO(craigcitro): FlagValidators? |
| 56 global _BASE_FLAGS_DECLARED # pylint: disable=global-statement |
| 57 if _BASE_FLAGS_DECLARED: |
| 58 return |
| 59 flags.DEFINE_boolean( |
| 60 'log_request', False, |
| 61 'Log requests.') |
| 62 flags.DEFINE_boolean( |
| 63 'log_response', False, |
| 64 'Log responses.') |
| 65 flags.DEFINE_boolean( |
| 66 'log_request_response', False, |
| 67 'Log requests and responses.') |
| 68 flags.DEFINE_enum( |
| 69 'output_format', |
| 70 'protorpc', |
| 71 _OUTPUT_FORMATTER_MAP.keys(), |
| 72 'Display format for results.') |
| 73 |
| 74 _BASE_FLAGS_DECLARED = True |
| 75 |
| 76 FLAGS = flags.FLAGS |
| 77 |
| 78 |
| 79 def SetupLogger(): |
| 80 if FLAGS.log_request or FLAGS.log_response or FLAGS.log_request_response: |
| 81 logging.basicConfig() |
| 82 logging.getLogger().setLevel(logging.INFO) |
| 83 |
| 84 |
| 85 def FormatOutput(message, output_format=None): |
| 86 """Convert the output to the user-specified format.""" |
| 87 output_format = output_format or FLAGS.output_format |
| 88 formatter = _OUTPUT_FORMATTER_MAP.get(FLAGS.output_format) |
| 89 if formatter is None: |
| 90 raise exceptions.UserError('Unknown output format: %s' % output_format) |
| 91 return formatter(message) |
| 92 |
| 93 |
| 94 class _SmartCompleter(rlcompleter.Completer): |
| 95 |
| 96 def _callable_postfix(self, val, word): |
| 97 if ('(' in readline.get_line_buffer() or |
| 98 not callable(val)): |
| 99 return word |
| 100 else: |
| 101 return word + '(' |
| 102 |
| 103 def complete(self, text, state): |
| 104 if not readline.get_line_buffer().strip(): |
| 105 if not state: |
| 106 return ' ' |
| 107 else: |
| 108 return None |
| 109 return rlcompleter.Completer.complete(self, text, state) |
| 110 |
| 111 |
| 112 class ConsoleWithReadline(code.InteractiveConsole): |
| 113 |
| 114 """InteractiveConsole with readline, tab completion, and history.""" |
| 115 |
| 116 def __init__(self, env, filename='<console>', histfile=None): |
| 117 new_locals = dict(env) |
| 118 new_locals.update({ |
| 119 '_SmartCompleter': _SmartCompleter, |
| 120 'readline': readline, |
| 121 'rlcompleter': rlcompleter, |
| 122 }) |
| 123 code.InteractiveConsole.__init__(self, new_locals, filename) |
| 124 readline.parse_and_bind('tab: complete') |
| 125 readline.set_completer(_SmartCompleter(new_locals).complete) |
| 126 if histfile is not None: |
| 127 histfile = os.path.expanduser(histfile) |
| 128 if os.path.exists(histfile): |
| 129 readline.read_history_file(histfile) |
| 130 atexit.register(lambda: readline.write_history_file(histfile)) |
| 131 |
| 132 |
| 133 def run_main(): # pylint: disable=invalid-name |
| 134 """Function to be used as setuptools script entry point. |
| 135 |
| 136 Appcommands assumes that it always runs as __main__, but launching |
| 137 via a setuptools-generated entry_point breaks this rule. We do some |
| 138 trickery here to make sure that appcommands and flags find their |
| 139 state where they expect to by faking ourselves as __main__. |
| 140 """ |
| 141 |
| 142 # Put the flags for this module somewhere the flags module will look |
| 143 # for them. |
| 144 # pylint: disable=protected-access |
| 145 new_name = flags._GetMainModule() |
| 146 sys.modules[new_name] = sys.modules['__main__'] |
| 147 for flag in FLAGS.FlagsByModuleDict().get(__name__, []): |
| 148 FLAGS._RegisterFlagByModule(new_name, flag) |
| 149 for key_flag in FLAGS.KeyFlagsByModuleDict().get(__name__, []): |
| 150 FLAGS._RegisterKeyFlagForModule(new_name, key_flag) |
| 151 # pylint: enable=protected-access |
| 152 |
| 153 # Now set __main__ appropriately so that appcommands will be |
| 154 # happy. |
| 155 sys.modules['__main__'] = sys.modules[__name__] |
| 156 appcommands.Run() |
| 157 sys.modules['__main__'] = sys.modules.pop(new_name) |
| 158 |
| 159 |
| 160 if __name__ == '__main__': |
| 161 appcommands.Run() |
OLD | NEW |