diff options
| author | Kuldeep Joshi (OpenERP) <kjo@tinyerp.com> | 2012-02-02 15:57:13 +0530 |
|---|---|---|
| committer | Kuldeep Joshi (OpenERP) <kjo@tinyerp.com> | 2012-02-02 15:57:13 +0530 |
| commit | 580bd71dc7a0e1db5e9bf1a716893d637d1bbdbe (patch) | |
| tree | 174a6345ce4e70dad8fde3f65889095728fa0f2d /addons/base_module_doc_rst/wizard/tech_rst_guide.py | |
| parent | c7013988a265a966f03e555939e674e791c5559c (diff) | |
| parent | 48cc23e6e1c16d5c8f37b6bfc9d406449a35587e (diff) | |
[FIX] base_module_record,base_module_doc_rst: change to osv.osv_memory
bzr revid: kjo@tinyerp.com-20120202102713-a0y7medo4izgrd71
Diffstat (limited to 'addons/base_module_doc_rst/wizard/tech_rst_guide.py')
| -rw-r--r-- | addons/base_module_doc_rst/wizard/tech_rst_guide.py | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/addons/base_module_doc_rst/wizard/tech_rst_guide.py b/addons/base_module_doc_rst/wizard/tech_rst_guide.py new file mode 100644 index 00000000000..82513fdc892 --- /dev/null +++ b/addons/base_module_doc_rst/wizard/tech_rst_guide.py @@ -0,0 +1,487 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## +from os.path import join +import base64 +import tempfile +import tarfile +import httplib + +import netsvc +import wizard +import pooler +import os +import tools +from osv import osv,fields + +class RstDoc(object): + def __init__(self, module, objects): + self.dico = { + 'name': module.name, + 'shortdesc': module.shortdesc, + 'latest_version': module.latest_version, + 'website': module.website, + 'description': self._handle_text(module.description.strip() or 'None'), + 'report_list': self._handle_list_items(module.reports_by_module), + 'menu_list': self._handle_list_items(module.menus_by_module), + 'view_list': self._handle_list_items(module.views_by_module), + 'depends': module.dependencies_id, + 'quality_certified': bool(module.certificate) and 'yes' or 'no', + 'official_module': str(module.certificate)[:2] == '00' and 'yes' or 'no', + 'author': module.author, + 'quality_certified_label': self._quality_certified_label(module), + } + self.objects = objects + self.module = module + + def _quality_certified_label(self, module): + label = "" + certificate = module.certificate + if certificate and len(certificate) > 1: + if certificate[:2] == '00': + # addons + label = "(Official, Quality Certified)" + elif certificate[:2] == '01': + # extra addons + label = "(Quality Certified)" + + return label + + def _handle_list_items(self, list_item_as_string): + list_item_as_string = list_item_as_string.strip() + if list_item_as_string: + return [item.replace('*', '\*') for item in list_item_as_string.split('\n')] + else: + return [] + + def _handle_text(self, txt): + lst = [' %s' % line for line in txt.split('\n')] + return '\n'.join(lst) + + def _get_download_links(self): + def _is_connection_status_good(link): + server = "openerp.com" + status_good = False + try: + conn = httplib.HTTPConnection(server) + conn.request("HEAD", link) + res = conn.getresponse() + if res.status in (200, ): + status_good = True + except (Exception, ), e: + logger = netsvc.Logger() + msg = "error connecting to server '%s' with link '%s'. Error message: %s" % (server, link, str(e)) + logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + status_good = False + return status_good + + versions = ('4.2', '5.0', 'trunk') + download_links = [] + for ver in versions: + link = 'http://www.openerp.com/download/modules/%s/%s.zip' % (ver, self.dico['name']) + if _is_connection_status_good(link): + download_links.append(" * `%s <%s>`_" % (ver, link)) + + if download_links: + res = '\n'.join(download_links) + else: + res = "(No download links available)" + return res + + def _write_header(self): + dico = self.dico + title = "%s (*%s*)" % (dico['shortdesc'], dico['name']) + title_underline = "=" * len(title) + dico['title'] = title + dico['title_underline'] = title_underline + dico['download_links'] = self._get_download_links() + + sl = [ + "", + ".. module:: %(name)s", + " :synopsis: %(shortdesc)s %(quality_certified_label)s", + " :noindex:", + ".. ", + "", + ".. raw:: html", + "", + " <br />", + """ <link rel="stylesheet" href="../_static/hide_objects_in_sidebar.css" type="text/css" />""", + "", + """.. tip:: This module is part of the OpenERP software, the leading Open Source """, + """ enterprise management system. If you want to discover OpenERP, check our """, + """ `screencasts <http://openerp.tv>`_ or download """, + """ `OpenERP <http://openerp.com>`_ directly.""", + "", + ".. raw:: html", + "", + """ <div class="js-kit-rating" title="" permalink="" standalone="yes" path="/%s"></div>""" % (dico['name'], ), + """ <script src="http://js-kit.com/ratings.js"></script>""", + "", + "%(title)s", + "%(title_underline)s", + ":Module: %(name)s", + ":Name: %(shortdesc)s", + ":Version: %(latest_version)s", + ":Author: %(author)s", + ":Directory: %(name)s", + ":Web: %(website)s", + ":Official module: %(official_module)s", + ":Quality certified: %(quality_certified)s", + "", + "Description", + "-----------", + "", + "::", + "", + "%(description)s", + "", + "Download links", + "--------------", + "", + "You can download this module as a zip file in the following version:", + "", + "%(download_links)s", + "", + ""] + return '\n'.join(sl) % (dico) + + def _write_reports(self): + sl = ["", + "Reports", + "-------"] + reports = self.dico['report_list'] + if reports: + for report in reports: + if report: + sl.append("") + sl.append(" * %s" % report) + else: + sl.extend(["", "None", ""]) + + sl.append("") + return '\n'.join(sl) + + def _write_menus(self): + sl = ["", + "Menus", + "-------", + ""] + menus = self.dico['menu_list'] + if menus: + for menu in menus: + if menu: + sl.append(" * %s" % menu) + else: + sl.extend(["", "None", ""]) + + sl.append("") + return '\n'.join(sl) + + def _write_views(self): + sl = ["", + "Views", + "-----", + ""] + views = self.dico['view_list'] + if views: + for view in views: + if view: + sl.append(" * %s" % view) + else: + sl.extend(["", "None", ""]) + + sl.append("") + return '\n'.join(sl) + + def _write_depends(self): + sl = ["", + "Dependencies", + "------------", + ""] + depends = self.dico['depends'] + if depends: + for dependency in depends: + sl.append(" * :mod:`%s`" % (dependency.name)) + else: + sl.extend(["", "None", ""]) + sl.append("") + return '\n'.join(sl) + + def _write_objects(self): + def write_field(field_def): + if not isinstance(field_def, tuple): + logger = netsvc.Logger() + msg = "Error on Object %s: field_def: %s [type: %s]" % (obj_name.encode('utf8'), field_def.encode('utf8'), type(field_def)) + logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + return "" + + field_name = field_def[0] + field_dict = field_def[1] + field_required = field_dict.get('required', '') and ', required' + field_readonly = field_dict.get('readonly', '') and ', readonly' + + field_help_s = field_dict.get('help', '').strip() + if field_help_s: + field_help_s = "*%s*" % (field_help_s) + field_help = '\n'.join([' %s' % line.strip() for line in field_help_s.split('\n')]) + else: + field_help = '' + + sl = ["", + ":%s: %s, %s%s%s" % (field_name, field_dict.get('string', 'Unknown'), field_dict['type'], field_required, field_readonly), + "", + field_help, + ] + return '\n'.join(sl) + + sl = ["", + "", + "Objects", + "-------"] + if self.objects: + for obj in self.objects: + obj_name = obj['object'].name + obj_model = obj['object'].model + title = "Object: %s (%s)" % (obj_name, obj_model) + slo = [ + "", + title, + '#' * len(title), + "", + ] + + for field in obj['fields']: + slf = [ + "", + write_field(field), + "", + ] + slo.extend(slf) + sl.extend(slo) + else: + sl.extend(["", "None", ""]) + + return u'\n'.join([a.decode('utf8') for a in sl]) + + def _write_relationship_graph(self, module_name=False): + sl = ["", + "Relationship Graph", + "------------------", + "", + ".. figure:: %s_module.png" % (module_name, ), + " :scale: 50", + " :align: center", + ""] + sl.append("") + return '\n'.join(sl) + + def write(self, module_name=False): + s = '' + s += self._write_header() + s += self._write_depends() + s += self._write_reports() + s += self._write_menus() + s += self._write_views() + s += self._write_objects() + if module_name: + s += self._write_relationship_graph(module_name) + return s + + +class wizard_tech_guide_rst(osv.osv_memory): + _name = "tech.guide.rst" + _columns = { + 'rst_file': fields.binary('File',required = True, readonly = True), + 'name': fields.char("Filename", size=64, required=True, readonly = True), + } + + def _generate(self, cr, uid, context): + pool = pooler.get_pool(cr.dbname) + module_model = pool.get('ir.module.module') + module_ids = context['ids'] + + module_index = [] + + # create a temporary gzipped tarfile: + tgz_tmp_filename = tempfile.mktemp('_rst_module_doc.tgz') + try: + tarf = tarfile.open(tgz_tmp_filename, 'w:gz') + + modules = module_model.browse(cr, uid, module_ids) + for module in modules: + index_dict = { + 'name': module.name, + 'shortdesc': module.shortdesc, + } + module_index.append(index_dict) + + objects = self._get_objects(cr, uid, module) + module.test_views = self._get_views(cr, uid, module.id, context=context) + rstdoc = RstDoc(module, objects) + + # Append Relationship Graph on rst + graph_mod = False + module_name = False + if module.file_graph: + graph_mod = base64.decodestring(module.file_graph) + else: + module_data = module_model.get_relation_graph(cr, uid, module.name, context=context) + if module_data['module_file']: + graph_mod = base64.decodestring(module_data['module_file']) + if graph_mod: + module_name = module.name + try: + tmpdir = tempfile.mkdtemp() + tmp_file_graph = tempfile.NamedTemporaryFile() + tmp_file_graph.write(graph_mod) + tmp_file_graph.file.flush() + tarf.add(tmp_file_graph.name, arcname= module.name + '_module.png') + finally: + tmp_file_graph.close() + + out = rstdoc.write(module_name) + try: + tmp_file = tempfile.NamedTemporaryFile() + tmp_file.write(out.encode('utf8')) + tmp_file.file.flush() # write content to file + tarf.add(tmp_file.name, arcname=module.name + '.rst') + finally: + tmp_file.close() + + # write index file: + tmp_file = tempfile.NamedTemporaryFile() + out = self._create_index(module_index) + tmp_file.write(out.encode('utf8')) + tmp_file.file.flush() + tarf.add(tmp_file.name, arcname='index.rst') + finally: + tarf.close() + + f = open(tgz_tmp_filename, 'rb') + out = f.read() + f.close() + + if os.path.exists(tgz_tmp_filename): + try: + os.unlink(tgz_tmp_filename) + except Exception, e: + logger = netsvc.Logger() + msg = "Temporary file %s could not be deleted. (%s)" % (tgz_tmp_filename, e) + logger.notifyChannel("warning", netsvc.LOG_WARNING, msg) + + return base64.encodestring(out) + + def _get_views(self, cr, uid, module_id, context=None): + pool = pooler.get_pool(cr.dbname) + module_module_obj = pool.get('ir.module.module') + res = {} + model_data_obj = pool.get('ir.model.data') + view_obj = pool.get('ir.ui.view') + report_obj = pool.get('ir.actions.report.xml') + menu_obj = pool.get('ir.ui.menu') + mlist = module_module_obj.browse(cr, uid, [module_id], context=context) + mnames = {} + for m in mlist: + mnames[m.name] = m.id + res[m.id] = { + 'menus_by_module': [], + 'reports_by_module': [], + 'views_by_module': [] + } + view_id = model_data_obj.search(cr, uid, [('module', 'in', mnames.keys()), + ('model', 'in', ('ir.ui.view', 'ir.actions.report.xml', 'ir.ui.menu'))]) + for data_id in model_data_obj.browse(cr, uid, view_id, context): + # We use try except, because views or menus may not exist + try: + key = data_id['model'] + if key == 'ir.ui.view': + v = view_obj.browse(cr, uid, data_id.res_id) + v_dict = { + 'name': v.name, + 'inherit': v.inherit_id, + 'type': v.type} + res[mnames[data_id.module]]['views_by_module'].append(v_dict) + elif key == 'ir.actions.report.xml': + res[mnames[data_id.module]]['reports_by_module'].append(report_obj.browse(cr, uid, data_id.res_id).name) + elif key == 'ir.ui.menu': + res[mnames[data_id.module]]['menus_by_module'].append(menu_obj.browse(cr, uid, data_id.res_id).complete_name) + except (KeyError, ): + pass + return res + + def _create_index(self, module_index): + sl = ["", + ".. _module-technical-guide-link:", + "", + "Module Technical Guide: Introspection report on objects", + "=======================================================", + "", + ".. toctree::", + " :maxdepth: 1", + "", + ] + for mod in module_index: + sl.append(" %s" % mod['name']) + sl.append("") + return '\n'.join(sl) + + def _get_objects(self, cr, uid, module): + res = [] + objects = self._object_find(cr, uid, module) + for obj in objects: + fields = self._fields_find(cr, uid, obj.model) + dico = { + 'object': obj, + 'fields': fields + } + res.append(dico) + return res + + def _object_find(self, cr, uid, module): + pool = pooler.get_pool(cr.dbname) + ids2 = pool.get('ir.model.data').search(cr, uid, [('module', '=', module.name), ('model', '=', 'ir.model')]) + ids = [] + for mod in pool.get('ir.model.data').browse(cr, uid, ids2): + ids.append(mod.res_id) + modobj = pool.get('ir.model') + return modobj.browse(cr, uid, ids) + + def _fields_find(self, cr, uid, obj): + pool = pooler.get_pool(cr.dbname) + modobj = pool.get(obj) + if modobj: + res = modobj.fields_get(cr, uid).items() + return res + else: + logger = netsvc.Logger() + msg = "Object %s not found" % (obj) + logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + return "" + + _defaults ={ + 'rst_file' : _generate, + 'name': 'modules_technical_guide_rst.tgz' + } + +wizard_tech_guide_rst() + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file |
