##// 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 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 def __init__(self, autoload=True, autocreate=False, config=None):
58 self._conf_name = CONFIG_NAME
57 def __init__(self, config_location=None, autoload=True, autocreate=False,
58 config=None):
59 self._conf_name = CONFIG_NAME if not config_location else config_location
59 60 self._conf = {}
60 61 if autocreate:
61 62 self.make_config(config)
62 63 if autoload:
63 64 self._conf = self.load_config()
64 65
65 66 def __getitem__(self, key):
66 67 return self._conf[key]
67 68
68 69 def __nonzero__(self):
69 70 if self._conf:
70 71 return True
71 72 return False
72 73
73 74 def __eq__(self):
74 75 return self._conf.__eq__()
75 76
76 77 def __repr__(self):
77 78 return 'RcConf<%s>' % self._conf.__repr__()
78 79
79 80 def make_config(self, config):
80 81 """
81 82 Saves given config as a JSON dump in the _conf_name location
82 83
83 84 :param config:
84 85 :type config:
85 86 """
87 update = False
88 if os.path.exists(self._conf_name):
89 update = True
86 90 with open(self._conf_name, 'wb') as f:
87 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 98 def update_config(self, new_config):
91 99 """
92 100 Reads the JSON config updates it's values with new_config and
93 101 saves it back as JSON dump
94 102
95 103 :param new_config:
96 104 """
97 105 config = {}
98 106 try:
99 107 with open(self._conf_name, 'rb') as conf:
100 108 config = json.load(conf)
101 109 except IOError, e:
102 110 sys.stderr.write(str(e) + '\n')
103 111
104 112 config.update(new_config)
105 113 self.make_config(config)
106 114
107 115 def load_config(self):
108 116 """
109 117 Loads config from file and returns loaded JSON object
110 118 """
111 119 try:
112 120 with open(self._conf_name, 'rb') as conf:
113 121 return json.load(conf)
114 122 except IOError, e:
115 123 #sys.stderr.write(str(e) + '\n')
116 124 pass
117 125
118 126
119 127 def api_call(apikey, apihost, format, method=None, **kw):
120 128 """
121 129 Api_call wrapper for RhodeCode
122 130
123 131 :param apikey:
124 132 :param apihost:
125 133 :param format: formatting, pretty means prints and pprint of json
126 134 json returns unparsed json
127 135 :param method:
128 136 """
129 137 def _build_data(random_id):
130 138 """
131 139 Builds API data with given random ID
132 140
133 141 :param random_id:
134 142 :type random_id:
135 143 """
136 144 return {
137 145 "id": random_id,
138 146 "api_key": apikey,
139 147 "method": method,
140 148 "args": kw
141 149 }
142 150
143 151 if not method:
144 152 raise Exception('please specify method name !')
145 153 id_ = random.randrange(1, 9999)
146 154 req = urllib2.Request('%s/_admin/api' % apihost,
147 155 data=json.dumps(_build_data(id_)),
148 156 headers={'content-type': 'text/plain'})
149 157 if format == FORMAT_PRETTY:
150 158 sys.stdout.write('calling %s to %s \n' % (req.get_data(), apihost))
151 159 ret = urllib2.urlopen(req)
152 160 raw_json = ret.read()
153 161 json_data = json.loads(raw_json)
154 162 id_ret = json_data['id']
155 163 _formatted_json = pprint.pformat(json_data)
156 164 if id_ret == id_:
157 165 if format == FORMAT_JSON:
158 166 sys.stdout.write(str(raw_json))
159 167 else:
160 168 sys.stdout.write('rhodecode returned:\n%s\n' % (_formatted_json))
161 169
162 170 else:
163 171 raise Exception('something went wrong. '
164 172 'ID mismatch got %s, expected %s | %s' % (
165 173 id_ret, id_, _formatted_json))
166 174
167 175
168 176 def argparser(argv):
169 usage = ("rhodecode_api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
170 "_create_config or METHOD <key:val> <key2:val> ...")
177 usage = (
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 183 parser = argparse.ArgumentParser(description='RhodeCode API cli',
173 184 usage=usage)
174 185
175 186 ## config
176 187 group = parser.add_argument_group('config')
177 188 group.add_argument('--apikey', help='api access key')
178 189 group.add_argument('--apihost', help='api host')
190 group.add_argument('--config', help='config file')
179 191
180 192 group = parser.add_argument_group('API')
181 193 group.add_argument('method', metavar='METHOD', type=str,
182 194 help='API method name to call followed by key:value attributes',
183 195 )
184 196 group.add_argument('--format', dest='format', type=str,
185 197 help='output format default: `pretty` can '
186 198 'be also `%s`' % FORMAT_JSON,
187 199 default=FORMAT_PRETTY
188 200 )
189 201 args, other = parser.parse_known_args()
190 202 return parser, args, other
191 203
192 204
193 205 def main(argv=None):
194 206 """
195 207 Main execution function for cli
196 208
197 209 :param argv:
198 210 :type argv:
199 211 """
200 212 if argv is None:
201 213 argv = sys.argv
202 214
203 215 conf = None
204 216 parser, args, other = argparser(argv)
205 217
206 218 api_credentials_given = (args.apikey and args.apihost)
207 219 if args.method == '_create_config':
208 220 if not api_credentials_given:
209 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 224 'apihost': args.apihost})
212 sys.stdout.write('Create new config in %s\n' % CONFIG_NAME)
213 225
214 226 if not conf:
215 conf = RcConf(autoload=True)
227 conf = RcConf(config_location=args.config, autoload=True)
216 228 if not conf:
217 229 if not api_credentials_given:
218 230 parser.error('Could not find config file and missing '
219 231 '--apikey or --apihost in params')
220 232
221 233 apikey = args.apikey or conf['apikey']
222 234 host = args.apihost or conf['apihost']
223 235 method = args.method
224 236 if method == '_create_config':
225 237 sys.exit()
226 238
227 239 try:
228 240 margs = dict(map(lambda s: s.split(':', 1), other))
229 241 except:
230 242 sys.stderr.write('Error parsing arguments \n')
231 243 sys.exit()
232 244
233 245 api_call(apikey, host, args.format, method, **margs)
234 246 return 0
235 247
236 248 if __name__ == '__main__':
237 249 sys.exit(main(sys.argv))
General Comments 0
You need to be logged in to leave comments. Login now