##// END OF EJS Templates
Show proper error on argument parse when using api-cli
marcink -
r2509:955956f4 beta
parent child Browse files
Show More
@@ -1,232 +1,237 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.bin.backup_manager
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Api CLI client for RhodeCode
7 7
8 8 :created_on: Jun 3, 2012
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 from __future__ import with_statement
27 27 import os
28 28 import sys
29 29 import random
30 30 import urllib2
31 31 import pprint
32 32 import argparse
33 33
34 34 try:
35 35 from rhodecode.lib.ext_json import json
36 36 except ImportError:
37 37 try:
38 38 import simplejson as json
39 39 except ImportError:
40 40 import json
41 41
42 42
43 43 CONFIG_NAME = '.rhodecode'
44 44 FORMAT_PRETTY = 'pretty'
45 45 FORMAT_JSON = 'json'
46 46
47 47
48 48 class RcConf(object):
49 49 """
50 50 RhodeCode config for API
51 51
52 52 conf = RcConf()
53 53 conf['key']
54 54
55 55 """
56 56
57 57 def __init__(self, autoload=True, autocreate=False, config=None):
58 58 self._conf_name = CONFIG_NAME
59 59 self._conf = {}
60 60 if autocreate:
61 61 self.make_config(config)
62 62 if autoload:
63 63 self._conf = self.load_config()
64 64
65 65 def __getitem__(self, key):
66 66 return self._conf[key]
67 67
68 68 def __nonzero__(self):
69 69 if self._conf:
70 70 return True
71 71 return False
72 72
73 73 def __eq__(self):
74 74 return self._conf.__eq__()
75 75
76 76 def __repr__(self):
77 77 return 'RcConf<%s>' % self._conf.__repr__()
78 78
79 79 def make_config(self, config):
80 80 """
81 81 Saves given config as a JSON dump in the _conf_name location
82 82
83 83 :param config:
84 84 :type config:
85 85 """
86 86 with open(self._conf_name, 'wb') as f:
87 87 json.dump(config, f, indent=4)
88 88 sys.stdout.write('Updated conf\n')
89 89
90 90 def update_config(self, new_config):
91 91 """
92 92 Reads the JSON config updates it's values with new_config and
93 93 saves it back as JSON dump
94 94
95 95 :param new_config:
96 96 """
97 97 config = {}
98 98 try:
99 99 with open(self._conf_name, 'rb') as conf:
100 100 config = json.load(conf)
101 101 except IOError, e:
102 102 sys.stderr.write(str(e) + '\n')
103 103
104 104 config.update(new_config)
105 105 self.make_config(config)
106 106
107 107 def load_config(self):
108 108 """
109 109 Loads config from file and returns loaded JSON object
110 110 """
111 111 try:
112 112 with open(self._conf_name, 'rb') as conf:
113 113 return json.load(conf)
114 114 except IOError, e:
115 115 #sys.stderr.write(str(e) + '\n')
116 116 pass
117 117
118 118
119 119 def api_call(apikey, apihost, format, method=None, **kw):
120 120 """
121 121 Api_call wrapper for RhodeCode
122 122
123 123 :param apikey:
124 124 :param apihost:
125 125 :param format: formatting, pretty means prints and pprint of json
126 126 json returns unparsed json
127 127 :param method:
128 128 """
129 129 def _build_data(random_id):
130 130 """
131 131 Builds API data with given random ID
132 132
133 133 :param random_id:
134 134 :type random_id:
135 135 """
136 136 return {
137 137 "id": random_id,
138 138 "api_key": apikey,
139 139 "method": method,
140 140 "args": kw
141 141 }
142 142
143 143 if not method:
144 144 raise Exception('please specify method name !')
145 145 id_ = random.randrange(1, 9999)
146 146 req = urllib2.Request('%s/_admin/api' % apihost,
147 147 data=json.dumps(_build_data(id_)),
148 148 headers={'content-type': 'text/plain'})
149 149 if format == FORMAT_PRETTY:
150 150 sys.stdout.write('calling %s to %s \n' % (req.get_data(), apihost))
151 151 ret = urllib2.urlopen(req)
152 152 raw_json = ret.read()
153 153 json_data = json.loads(raw_json)
154 154 id_ret = json_data['id']
155 155 _formatted_json = pprint.pformat(json_data)
156 156 if id_ret == id_:
157 157 if format == FORMAT_JSON:
158 158 sys.stdout.write(str(raw_json))
159 159 else:
160 160 sys.stdout.write('rhodecode returned:\n%s\n' % (_formatted_json))
161 161
162 162 else:
163 163 raise Exception('something went wrong. '
164 164 'ID mismatch got %s, expected %s | %s' % (
165 165 id_ret, id_, _formatted_json))
166 166
167 167
168 168 def argparser(argv):
169 169 usage = ("rhodecode_api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
170 170 "_create_config or METHOD <key:val> <key2:val> ...")
171 171
172 172 parser = argparse.ArgumentParser(description='RhodeCode API cli',
173 173 usage=usage)
174 174
175 175 ## config
176 176 group = parser.add_argument_group('config')
177 177 group.add_argument('--apikey', help='api access key')
178 178 group.add_argument('--apihost', help='api host')
179 179
180 180 group = parser.add_argument_group('API')
181 181 group.add_argument('method', metavar='METHOD', type=str,
182 182 help='API method name to call followed by key:value attributes',
183 183 )
184 184 group.add_argument('--format', dest='format', type=str,
185 185 help='output format default: `pretty` can '
186 186 'be also `%s`' % FORMAT_JSON,
187 187 default=FORMAT_PRETTY
188 188 )
189 189 args, other = parser.parse_known_args()
190 190 return parser, args, other
191 191
192 192
193 193 def main(argv=None):
194 194 """
195 195 Main execution function for cli
196 196
197 197 :param argv:
198 198 :type argv:
199 199 """
200 200 if argv is None:
201 201 argv = sys.argv
202 202
203 203 conf = None
204 204 parser, args, other = argparser(argv)
205 205
206 206 api_credentials_given = (args.apikey and args.apihost)
207 207 if args.method == '_create_config':
208 208 if not api_credentials_given:
209 209 raise parser.error('_create_config requires --apikey and --apihost')
210 210 conf = RcConf(autocreate=True, config={'apikey': args.apikey,
211 211 'apihost': args.apihost})
212 212 sys.stdout.write('Create new config in %s\n' % CONFIG_NAME)
213 213
214 214 if not conf:
215 215 conf = RcConf(autoload=True)
216 216 if not conf:
217 217 if not api_credentials_given:
218 218 parser.error('Could not find config file and missing '
219 219 '--apikey or --apihost in params')
220 220
221 221 apikey = args.apikey or conf['apikey']
222 222 host = args.apihost or conf['apihost']
223 223 method = args.method
224 224 if method == '_create_config':
225 225 sys.exit()
226 margs = dict(map(lambda s: s.split(':', 1), other))
226
227 try:
228 margs = dict(map(lambda s: s.split(':', 1), other))
229 except:
230 sys.stderr.write('Error parsing arguments \n')
231 sys.exit()
227 232
228 233 api_call(apikey, host, args.format, method, **margs)
229 234 return 0
230 235
231 236 if __name__ == '__main__':
232 237 sys.exit(main(sys.argv))
General Comments 0
You need to be logged in to leave comments. Login now