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