summaryrefslogtreecommitdiff
path: root/addons/base_module_doc_rst/wizard/tech_rst_guide.py
diff options
context:
space:
mode:
authorKuldeep Joshi (OpenERP) <kjo@tinyerp.com>2012-02-02 15:57:13 +0530
committerKuldeep Joshi (OpenERP) <kjo@tinyerp.com>2012-02-02 15:57:13 +0530
commit580bd71dc7a0e1db5e9bf1a716893d637d1bbdbe (patch)
tree174a6345ce4e70dad8fde3f65889095728fa0f2d /addons/base_module_doc_rst/wizard/tech_rst_guide.py
parentc7013988a265a966f03e555939e674e791c5559c (diff)
parent48cc23e6e1c16d5c8f37b6bfc9d406449a35587e (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.py487
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