[FIX] expression: translated search as params are flatten, we need to expand "%s...
[odoo/odoo.git] / openerp / addons / base_quality_interrogation.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 ##############################################################################
4 #    
5 #    OpenERP, Open Source Management Solution
6 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
20 #
21 ##############################################################################
22
23 import xmlrpclib
24 import optparse
25 import sys
26 import threading
27 import os
28 import time
29 import base64
30 import socket
31 import string
32
33 admin_passwd = 'admin'
34 waittime = 10
35 wait_count = 0
36 wait_limit = 12
37
38 def to_decode(s):
39     try:
40         return s.encode('utf-8')
41     except UnicodeError:
42         try:
43             return s.encode('latin')
44         except UnicodeError:
45             try:
46                 return s.decode('ascii')
47             except UnicodeError:
48                 return s
49
50 def start_server(root_path, port, netport, addons_path):
51     os.system('python2.5 %sopenerp-server  --pidfile=openerp.pid  --no-xmlrpcs --xmlrpc-port=%s --netrpc-port=%s --addons-path=%s' %(root_path, str(port),str(netport),addons_path))
52 def clean():
53     if os.path.isfile('openerp.pid'):
54         ps = open('openerp.pid')
55         if ps:
56             pid = int(ps.read())
57             ps.close()
58             if pid:
59                 os.kill(pid,9)
60
61 def execute(connector, method, *args):
62     global wait_count
63     res = False
64     try:
65         res = getattr(connector,method)(*args)
66     except socket.error,e:
67         if e.args[0] == 111:
68             if wait_count > wait_limit:
69                 print "Server is taking too long to start, it has exceeded the maximum limit of %d seconds." % wait_limit
70                 clean()
71                 sys.exit(1)
72             print 'Please wait %d sec to start server....' % waittime
73             wait_count += 1
74             time.sleep(waittime)
75             res = execute(connector, method, *args)
76         else:
77             raise e
78     wait_count = 0
79     return res
80
81 def login(uri, dbname, user, pwd):
82     conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/common')
83     uid = execute(conn,'login',dbname, user, pwd)
84     return uid
85
86 def import_translate(uri, user, pwd, dbname, translate_in):
87     uid = login(uri, dbname, user, pwd)
88     if uid:
89         conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/wizard')
90         wiz_id = execute(conn,'create',dbname, uid, pwd, 'base.language.import')
91         for trans_in in translate_in:
92             lang,ext = os.path.splitext(trans_in.split('/')[-1])
93             state = 'init'
94             datas = {'form':{}}
95             while state!='end':
96                 res = execute(conn,'execute',dbname, uid, pwd, wiz_id, datas, state, {})
97                 if 'datas' in res:
98                     datas['form'].update( res['datas'].get('form',{}) )
99                 if res['type']=='form':
100                     for field in res['fields'].keys():
101                         datas['form'][field] = res['fields'][field].get('value', False)
102                     state = res['state'][-1][0]
103                     trans_obj = open(trans_in)
104                     datas['form'].update({
105                         'name': lang,
106                         'code': lang,
107                         'data' : base64.encodestring(trans_obj.read())
108                     })
109                     trans_obj.close()
110                 elif res['type']=='action':
111                     state = res['state']
112
113
114 def check_quality(uri, user, pwd, dbname, modules, quality_logs):
115     uid = login(uri, dbname, user, pwd)
116     quality_logs += 'quality-logs'
117     if uid:
118         conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/object')
119         final = {}
120         for module in modules:
121             qualityresult = {}
122             test_detail = {}
123             quality_result = execute(conn,'execute', dbname, uid, pwd,'module.quality.check','check_quality',module)
124             detail_html = ''
125             html = '''<html><body><a name="TOP"></a>'''
126             html +="<h1> Module: %s </h1>"%(quality_result['name'])
127             html += "<h2> Final score: %s</h2>"%(quality_result['final_score'])
128             html += "<div id='tabs'>"
129             html += "<ul>"
130             for x,y,detail in quality_result['check_detail_ids']:
131                 test = detail.get('name')
132                 msg = detail.get('message','')
133                 score = round(float(detail.get('score',0)),2)
134                 html += "<li><a href=\"#%s\">%s</a></li>"%(test.replace(' ','-'),test)
135                 detail_html +='''<div id=\"%s\"><h3>%s (Score : %s)</h3><font color=red><h5>%s</h5></font>%s</div>'''%(test.replace(' ', '-'), test, score, msg, detail.get('detail', ''))
136                 test_detail[test] = (score,msg,detail.get('detail',''))
137             html += "</ul>"
138             html += "%s"% detail_html
139             html += "</div></body></html>"
140             if not os.path.isdir(quality_logs):
141                 os.mkdir(quality_logs)
142             fp = open('%s/%s.html'%(quality_logs,module),'wb')
143             fp.write(to_decode(html))
144             fp.close()
145             #final[quality_result['name']] = (quality_result['final_score'],html,test_detail)
146
147         #fp = open('quality_log.pck','wb')
148         #pck_obj = pickle.dump(final,fp)
149         #fp.close()
150         #print "LOG PATH%s"%(os.path.realpath('quality_log.pck'))
151         return True
152     else:
153         print 'Login Failed...'
154         clean()
155         sys.exit(1)
156
157
158
159 def wait(id,url=''):
160     progress=0.0
161     sock2 = xmlrpclib.ServerProxy(url+'/xmlrpc/db')
162     while not progress==1.0:
163         progress,users = execute(sock2,'get_progress',admin_passwd, id)
164     return True
165
166
167 def create_db(uri, dbname, user='admin', pwd='admin', lang='en_US'):
168     conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/db')
169     obj_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/object')
170     wiz_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/wizard')
171     login_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/common')
172     db_list = execute(conn, 'list')
173     if dbname in db_list:
174         drop_db(uri, dbname)
175     id = execute(conn,'create',admin_passwd, dbname, True, lang)
176     wait(id,uri)    
177     install_module(uri, dbname, ['base_module_quality'],user=user,pwd=pwd)
178     return True
179
180 def drop_db(uri, dbname):
181     conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/db')
182     db_list = execute(conn,'list')
183     if dbname in db_list:
184         execute(conn, 'drop', admin_passwd, dbname)
185     return True
186
187 def make_links(uri, uid, dbname, source, destination, module, user, pwd):
188     if module in ('base','quality_integration_server'):
189         return True
190     if os.path.islink(destination + '/' + module):
191         os.unlink(destination + '/' + module)                
192     for path in source:
193         if os.path.isdir(path + '/' + module):
194             os.symlink(path + '/' + module, destination + '/' + module)
195             obj_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/object')
196             execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'update_list')
197             module_ids = execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'search', [('name','=',module)])
198             if len(module_ids):
199                 data = execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'read', module_ids[0],['name','dependencies_id'])
200                 dep_datas = execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module.dependency', 'read', data['dependencies_id'],['name'])
201                 for dep_data in dep_datas:
202                     make_links(uri, uid, dbname, source, destination, dep_data['name'], user, pwd)
203     return False
204
205 def install_module(uri, dbname, modules, addons='', extra_addons='',  user='admin', pwd='admin'):
206     uid = login(uri, dbname, user, pwd)
207     if extra_addons:
208         extra_addons = extra_addons.split(',')
209     if uid:
210         if addons and extra_addons:
211             for module in modules:
212                 make_links(uri, uid, dbname, extra_addons, addons, module, user, pwd)
213
214         obj_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/object')
215         wizard_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/wizard')
216         module_ids = execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'search', [('name','in',modules)])
217         execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'button_install', module_ids)
218         wiz_id = execute(wizard_conn, 'create', dbname, uid, pwd, 'module.upgrade.simple')
219         state = 'init'
220         datas = {}
221         #while state!='menu':
222         while state!='end':
223             res = execute(wizard_conn, 'execute', dbname, uid, pwd, wiz_id, datas, state, {})
224             if state == 'init':
225                 state = 'start'
226             elif state == 'start':
227                 state = 'end'
228     return True
229
230 def upgrade_module(uri, dbname, modules, user='admin', pwd='admin'):
231     uid = login(uri, dbname, user, pwd)
232     if uid:
233         obj_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/object')
234         wizard_conn = xmlrpclib.ServerProxy(uri + '/xmlrpc/wizard')
235         module_ids = execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'search', [('name','in',modules)])
236         execute(obj_conn, 'execute', dbname, uid, pwd, 'ir.module.module', 'button_upgrade', module_ids)
237         wiz_id = execute(wizard_conn, 'create', dbname, uid, pwd, 'module.upgrade.simple')
238         state = 'init'
239         datas = {}
240         #while state!='menu':
241         while state!='end':
242             res = execute(wizard_conn, 'execute', dbname, uid, pwd, wiz_id, datas, state, {})
243             if state == 'init':
244                 state = 'start'
245             elif state == 'start':
246                 state = 'end'
247
248     return True
249
250
251
252
253
254 usage = """%prog command [options]
255
256 Basic Commands:
257     start-server         Start Server
258     create-db            Create new database
259     drop-db              Drop database
260     install-module       Install module
261     upgrade-module       Upgrade module
262     install-translation  Install translation file
263     check-quality        Calculate quality and dump quality result into quality_log.pck using pickle
264 """
265 parser = optparse.OptionParser(usage)
266 parser.add_option("--modules", dest="modules",
267                      help="specify modules to install or check quality")
268 parser.add_option("--addons-path", dest="addons_path", help="specify the addons path")
269 parser.add_option("--quality-logs", dest="quality_logs", help="specify the path of quality logs files which has to stores")
270 parser.add_option("--root-path", dest="root_path", help="specify the root path")
271 parser.add_option("-p", "--port", dest="port", help="specify the TCP port", type="int")
272 parser.add_option("--net_port", dest="netport",help="specify the TCP port for netrpc")
273 parser.add_option("-d", "--database", dest="db_name", help="specify the database name")
274 parser.add_option("--login", dest="login", help="specify the User Login")
275 parser.add_option("--password", dest="pwd", help="specify the User Password")
276 parser.add_option("--translate-in", dest="translate_in",
277                      help="specify .po files to import translation terms")
278 parser.add_option("--extra-addons", dest="extra_addons",
279                      help="specify extra_addons and trunkCommunity modules path ")
280
281 (opt, args) = parser.parse_args()
282 if len(args) != 1:
283     parser.error("incorrect number of arguments")
284 command = args[0]
285 if command not in ('start-server','create-db','drop-db','install-module','upgrade-module','check-quality','install-translation'):
286     parser.error("incorrect command")
287
288 def die(cond, msg):
289     if cond:
290         print msg
291         sys.exit(1)
292
293 die(opt.modules and (not opt.db_name),
294         "the modules option cannot be used without the database (-d) option")
295
296 die(opt.translate_in and (not opt.db_name),
297         "the translate-in option cannot be used without the database (-d) option")
298
299 options = {
300     'addons-path' : opt.addons_path or 'addons',
301     'quality-logs' : opt.quality_logs or '',
302     'root-path' : opt.root_path or '',
303     'translate-in': [],
304     'port' : opt.port or 8069,
305     'netport':opt.netport or 8070,
306     'database': opt.db_name or 'terp',
307     'modules' : map(string.strip, opt.modules.split(',')) if opt.modules else [],
308     'login' : opt.login or 'admin',
309     'pwd' : opt.pwd or '',
310     'extra-addons':opt.extra_addons or []
311 }
312 # Hint:i18n-import=purchase:ar_AR.po+sale:fr_FR.po,nl_BE.po
313 if opt.translate_in:
314     translate = opt.translate_in
315     for module_name,po_files in map(lambda x:tuple(x.split(':')),translate.split('+')):
316         for po_file in po_files.split(','):
317             if module_name == 'base':
318                 po_link = '%saddons/%s/i18n/%s'%(options['root-path'],module_name,po_file)
319             else:
320                 po_link = '%s/%s/i18n/%s'%(options['addons-path'], module_name, po_file)
321             options['translate-in'].append(po_link)
322
323 uri = 'http://localhost:' + str(options['port'])
324
325 server_thread = threading.Thread(target=start_server,
326                 args=(options['root-path'], options['port'],options['netport'], options['addons-path']))
327 try:
328     server_thread.start()
329     if command == 'create-db':
330         create_db(uri, options['database'], options['login'], options['pwd'])
331     if command == 'drop-db':
332         drop_db(uri, options['database'])
333     if command == 'install-module':
334         install_module(uri, options['database'], options['modules'],options['addons-path'],options['extra-addons'],options['login'], options['pwd'])
335     if command == 'upgrade-module':
336         upgrade_module(uri, options['database'], options['modules'], options['login'], options['pwd'])
337     if command == 'check-quality':
338         check_quality(uri, options['login'], options['pwd'], options['database'], options['modules'], options['quality-logs'])
339     if command == 'install-translation':
340         import_translate(uri, options['login'], options['pwd'], options['database'], options['translate-in'])
341     clean()
342     sys.exit(0)
343
344 except xmlrpclib.Fault, e:
345     print e.faultString
346     clean()
347     sys.exit(1)
348 except Exception, e:
349     print e
350     clean()
351     sys.exit(1)
352
353 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: