[MERGE] apps by chs

bzr revid: al@openerp.com-20121220144322-ign0s0u0rbufhedi
This commit is contained in:
Antony Lesuisse
2012-12-20 15:43:22 +01:00
21 changed files with 591 additions and 225 deletions
+20 -13
View File
@@ -1,14 +1,21 @@
.*
*.egg-info
*.orig
*.vim
.*.swp
.bzrignore
.idea
.project
.pydevproject
.ropeproject
.settings
.DS_Store
openerp/addons/*
openerp/filestore*
.Python
*.pyc
*.pyo
bin/*
build/
RE:^bin/
RE:^dist/
RE:^include/
RE:^share/
RE:^man/
RE:^lib/
RE:^addons/\w+/doc/_build/
include/
lib/
share/
doc/_build/*
win32/*.bat
win32/meta.py
+4 -1
View File
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010, 2012 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -102,5 +102,8 @@ The kernel of OpenERP, needed for all installation.
'installable': True,
'auto_install': True,
'css': ['static/src/css/modules.css'],
'js': [
'static/src/js/apps.js',
],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+176 -85
View File
@@ -24,12 +24,22 @@ from docutils.transforms import Transform, writer_aux
from docutils.writers.html4css1 import Writer
import imp
import logging
import os
import re
import shutil
import tempfile
import urllib
import urllib2
import zipfile
import zipimport
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO # NOQA
import openerp
from openerp import modules, pooler, release, tools, addons
from openerp import modules, pooler, tools, addons
from openerp.modules.db import create_categories
from openerp.tools.parse_version import parse_version
from openerp.tools.translate import _
@@ -43,14 +53,29 @@ ACTION_DICT = {
'res_model': 'base.module.upgrade',
'target': 'new',
'type': 'ir.actions.act_window',
'nodestroy':True,
'nodestroy': True,
}
def backup(path, raise_exception=True):
path = os.path.normpath(path)
if not os.path.exists(path):
if not raise_exception:
return None
raise OSError('path does not exists')
cnt = 1
while True:
bck = '%s~%d' % (path, cnt)
if not os.path.exists(bck):
shutil.move(path, bck)
return bck
cnt += 1
class module_category(osv.osv):
_name = "ir.module.category"
_description = "Application"
def _module_nbr(self,cr,uid, ids, prop, unknow_none, context):
def _module_nbr(self, cr, uid, ids, prop, unknow_none, context):
cr.execute('SELECT category_id, COUNT(*) \
FROM ir_module_module \
WHERE category_id IN %(ids)s \
@@ -58,7 +83,7 @@ class module_category(osv.osv):
FROM ir_module_category \
WHERE parent_id IN %(ids)s) \
GROUP BY category_id', {'ids': tuple(ids)}
)
)
result = dict(cr.fetchall())
for id in ids:
cr.execute('select id from ir_module_category where parent_id=%s', (id,))
@@ -71,16 +96,16 @@ class module_category(osv.osv):
'parent_id': fields.many2one('ir.module.category', 'Parent Application', select=True),
'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Child Applications'),
'module_nr': fields.function(_module_nbr, string='Number of Modules', type='integer'),
'module_ids' : fields.one2many('ir.module.module', 'category_id', 'Modules'),
'description' : fields.text("Description", translate=True),
'sequence' : fields.integer('Sequence'),
'visible' : fields.boolean('Visible'),
'module_ids': fields.one2many('ir.module.module', 'category_id', 'Modules'),
'description': fields.text("Description", translate=True),
'sequence': fields.integer('Sequence'),
'visible': fields.boolean('Visible'),
'xml_id': fields.function(osv.osv.get_external_id, type='char', size=128, string="External ID"),
}
_order = 'name'
_defaults = {
'visible' : 1,
'visible': 1,
}
class MyFilterMessages(Transform):
@@ -119,7 +144,6 @@ class module(osv.osv):
info = {}
try:
info = modules.load_information_from_description_file(name)
info['version'] = release.major_version + '.' + info['version']
except Exception:
_logger.debug('Error when trying to fetch informations for '
'module %s', name, exc_info=True)
@@ -134,9 +158,10 @@ class module(osv.osv):
return res
def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context=None):
res = dict.fromkeys(ids, '')
default_version = modules.adapt_version('1.0')
res = dict.fromkeys(ids, default_version)
for m in self.browse(cr, uid, ids):
res[m.id] = self.get_module_info(m.name).get('version', '')
res[m.id] = self.get_module_info(m.name).get('version', default_version)
return res
def _get_views(self, cr, uid, ids, field_name=None, arg=None, context=None):
@@ -167,9 +192,11 @@ class module(osv.osv):
continue
# then, search and group ir.model.data records
imd_models = dict( [(m,[]) for m in dmodels])
imd_ids = model_data_obj.search(cr,uid,[('module','=', module_rec.name),
('model','in',tuple(dmodels))])
imd_models = dict([(m, []) for m in dmodels])
imd_ids = model_data_obj.search(cr, uid, [
('module', '=', module_rec.name),
('model', 'in', tuple(dmodels))
])
for imd_res in model_data_obj.read(cr, uid, imd_ids, ['model', 'res_id'], context=context):
imd_models[imd_res['model']].append(imd_res['res_id'])
@@ -181,7 +208,7 @@ class module(osv.osv):
view_ids = imd_models.get('ir.ui.view', [])
for v in view_obj.browse(cr, uid, view_ids, context=context):
aa = v.inherit_id and '* INHERIT ' or ''
res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')')
res_mod_dic['views_by_module'].append('%s%s (%s)' % (aa, v.name, v.type))
report_ids = imd_models.get('ir.actions.report.xml', [])
for rx in report_obj.browse(cr, uid, report_ids, context=context):
@@ -191,15 +218,13 @@ class module(osv.osv):
for um in menu_obj.browse(cr, uid, menu_ids, context=context):
res_mod_dic['menus_by_module'].append(um.complete_name)
except KeyError, e:
_logger.warning(
'Data not found for items of %s', module_rec.name)
_logger.warning('Data not found for items of %s', module_rec.name)
except AttributeError, e:
_logger.warning(
'Data not found for items of %s %s', module_rec.name, str(e))
_logger.warning('Data not found for items of %s %s', module_rec.name, str(e))
except Exception, e:
_logger.warning('Unknown error while fetching data of %s',
module_rec.name, exc_info=True)
for key, _ in res.iteritems():
_logger.warning('Unknown error while fetching data of %s', module_rec.name, exc_info=True)
for key in res.iterkeys():
for k, v in res[key].iteritems():
res[key][k] = "\n".join(sorted(v))
return res
@@ -232,36 +257,34 @@ class module(osv.osv):
# installed_version refer the latest version (the one on disk)
# latest_version refer the installed version (the one in database)
# published_version refer the version available on the repository
'installed_version': fields.function(_get_latest_version,
string='Latest Version', type='char'),
'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'),
'latest_version': fields.char('Installed Version', size=64, readonly=True),
'published_version': fields.char('Published Version', size=64, readonly=True),
'url': fields.char('URL', size=128, readonly=True),
'sequence': fields.integer('Sequence'),
'dependencies_id': fields.one2many('ir.module.module.dependency',
'module_id', 'Dependencies', readonly=True),
'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True),
'auto_install': fields.boolean('Automatic Installation',
help='An auto-installable module is automatically installed by the '
'system when all its dependencies are satisfied. '
'If the module has no dependency, it is always installed.'),
help='An auto-installable module is automatically installed by the '
'system when all its dependencies are satisfied. '
'If the module has no dependency, it is always installed.'),
'state': fields.selection([
('uninstallable','Not Installable'),
('uninstalled','Not Installed'),
('installed','Installed'),
('to upgrade','To be upgraded'),
('to remove','To be removed'),
('to install','To be installed')
('uninstallable', 'Not Installable'),
('uninstalled', 'Not Installed'),
('installed', 'Installed'),
('to upgrade', 'To be upgraded'),
('to remove', 'To be removed'),
('to install', 'To be installed')
], string='Status', readonly=True, select=True),
'demo': fields.boolean('Demo Data', readonly=True),
'license': fields.selection([
('GPL-2', 'GPL Version 2'),
('GPL-2 or any later version', 'GPL-2 or later version'),
('GPL-3', 'GPL Version 3'),
('GPL-3 or any later version', 'GPL-3 or later version'),
('AGPL-3', 'Affero GPL-3'),
('Other OSI approved licence', 'Other OSI Approved Licence'),
('Other proprietary', 'Other Proprietary')
('GPL-2', 'GPL Version 2'),
('GPL-2 or any later version', 'GPL-2 or later version'),
('GPL-3', 'GPL Version 3'),
('GPL-3 or any later version', 'GPL-3 or later version'),
('AGPL-3', 'Affero GPL-3'),
('Other OSI approved licence', 'Other OSI Approved Licence'),
('Other proprietary', 'Other Proprietary')
], string='License', readonly=True),
'menus_by_module': fields.function(_get_views, string='Menus', type='text', multi="meta", store=True),
'reports_by_module': fields.function(_get_views, string='Reports', type='text', multi="meta", store=True),
@@ -283,7 +306,7 @@ class module(osv.osv):
return _('The name of the module must be unique !')
_sql_constraints = [
('name_uniq', 'UNIQUE (name)',_name_uniq_msg ),
('name_uniq', 'UNIQUE (name)', _name_uniq_msg),
]
def unlink(self, cr, uid, ids, context=None):
@@ -292,10 +315,9 @@ class module(osv.osv):
if isinstance(ids, (int, long)):
ids = [ids]
mod_names = []
for mod in self.read(cr, uid, ids, ['state','name'], context):
for mod in self.read(cr, uid, ids, ['state', 'name'], context):
if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'):
raise orm.except_orm(_('Error'),
_('You try to remove a module that is installed or will be installed'))
raise orm.except_orm(_('Error'), _('You try to remove a module that is installed or will be installed'))
mod_names.append(mod['name'])
#Removing the entry from ir_model_data
#ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)])
@@ -340,7 +362,7 @@ class module(osv.osv):
raise orm.except_orm(_('Error'), msg % (module_name, e.args[0]))
def state_update(self, cr, uid, ids, newstate, states_to_update, context=None, level=100):
if level<1:
if level < 1:
raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !'))
demo = False
for module in self.browse(cr, uid, ids, context=context):
@@ -348,9 +370,9 @@ class module(osv.osv):
for dep in module.dependencies_id:
if dep.state == 'unknown':
raise orm.except_orm(_('Error'), _("You try to install module '%s' that depends on module '%s'.\nBut the latter module is not available in your system.") % (module.name, dep.name,))
ids2 = self.search(cr, uid, [('name','=',dep.name)])
ids2 = self.search(cr, uid, [('name', '=', dep.name)])
if dep.state != newstate:
mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level-1,) or mdemo
mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level - 1) or mdemo
else:
od = self.browse(cr, uid, ids2)[0]
mdemo = od.demo or mdemo
@@ -359,7 +381,7 @@ class module(osv.osv):
if not module.dependencies_id:
mdemo = module.demo
if module.state in states_to_update:
self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo})
self.write(cr, uid, [module.id], {'state': newstate, 'demo': mdemo})
demo = demo or mdemo
return demo
@@ -403,7 +425,7 @@ class module(osv.osv):
return self._button_immediate_function(cr, uid, ids, self.button_install, context=context)
def button_install_cancel(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
self.write(cr, uid, ids, {'state': 'uninstalled', 'demo': False})
return True
def module_uninstall(self, cr, uid, ids, context=None):
@@ -421,12 +443,13 @@ class module(osv.osv):
return True
def downstream_dependencies(self, cr, uid, ids, known_dep_ids=None,
exclude_states=['uninstalled','uninstallable','to remove'],
exclude_states=['uninstalled', 'uninstallable', 'to remove'],
context=None):
"""Return the ids of all modules that directly or indirectly depend
on the given module `ids`, and that satisfy the `exclude_states`
filter"""
if not ids: return []
if not ids:
return []
known_dep_ids = set(known_dep_ids or [])
cr.execute('''SELECT DISTINCT m.id
FROM
@@ -437,13 +460,13 @@ class module(osv.osv):
d.name IN (SELECT name from ir_module_module where id in %s) AND
m.state NOT IN %s AND
m.id NOT IN %s ''',
(tuple(ids),tuple(exclude_states), tuple(known_dep_ids or ids)))
(tuple(ids), tuple(exclude_states), tuple(known_dep_ids or ids)))
new_dep_ids = set([m[0] for m in cr.fetchall()])
missing_mod_ids = new_dep_ids - known_dep_ids
known_dep_ids |= new_dep_ids
if missing_mod_ids:
known_dep_ids |= set(self.downstream_dependencies(cr, uid, list(missing_mod_ids),
known_dep_ids, exclude_states,context))
known_dep_ids, exclude_states, context))
return list(known_dep_ids)
def _button_immediate_function(self, cr, uid, ids, function, context=None):
@@ -460,9 +483,9 @@ class module(osv.osv):
menu_obj = self.pool.get('ir.ui.menu')
menu_ids = menu_obj.search(cr, uid, [('parent_id', '=', False)], context=context)
return {
'type' : 'ir.actions.client',
'tag' : 'reload',
'params' : {'menu_id' : menu_ids and menu_ids[0] or False}
'type': 'ir.actions.client',
'tag': 'reload',
'params': {'menu_id': menu_ids and menu_ids[0] or False}
}
def button_immediate_uninstall(self, cr, uid, ids, context=None):
@@ -496,20 +519,19 @@ class module(osv.osv):
self.update_list(cr, uid)
i = 0
while i<len(todo):
while i < len(todo):
mod = todo[i]
i += 1
if mod.state not in ('installed','to upgrade'):
raise orm.except_orm(_('Error'),
_("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
if mod.state not in ('installed', 'to upgrade'):
raise orm.except_orm(_('Error'), _("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
self.check_external_dependencies(mod.name, 'to upgrade')
iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context)
for dep in depobj.browse(cr, uid, iids, context=context):
if dep.module_id.state=='installed' and dep.module_id not in todo:
if dep.module_id.state == 'installed' and dep.module_id not in todo:
todo.append(dep.module_id)
ids = map(lambda x: x.id, todo)
self.write(cr, uid, ids, {'state':'to upgrade'}, context=context)
self.write(cr, uid, ids, {'state': 'to upgrade'}, context=context)
to_install = []
for mod in todo:
@@ -517,7 +539,7 @@ class module(osv.osv):
if dep.state == 'unknown':
raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,))
if dep.state == 'uninstalled':
ids2 = self.search(cr, uid, [('name','=',dep.name)])
ids2 = self.search(cr, uid, [('name', '=', dep.name)])
to_install.extend(ids2)
self.button_install(cr, uid, to_install, context=context)
@@ -550,8 +572,9 @@ class module(osv.osv):
# update the list of available packages
def update_list(self, cr, uid, context=None):
res = [0, 0] # [update, add]
res = [0, 0] # [update, add]
default_version = modules.adapt_version('1.0')
known_mods = self.browse(cr, uid, self.search(cr, uid, []))
known_mods_names = dict([(m.name, m) for m in known_mods])
@@ -570,7 +593,7 @@ class module(osv.osv):
updated_values[key] = values[key]
if terp.get('installable', True) and mod.state == 'uninstallable':
updated_values['state'] = 'uninstalled'
if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
if parse_version(terp.get('version', default_version)) > parse_version(mod.latest_version or default_version):
res[0] += 1
if updated_values:
self.write(cr, uid, mod.id, updated_values)
@@ -587,24 +610,32 @@ class module(osv.osv):
self._update_dependencies(cr, uid, mod, terp.get('depends', []))
self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
# Trigger load_addons if new module have been discovered it exists on
# wsgi handlers, so they can react accordingly
if tuple(res) != (0, 0):
for handler in openerp.service.wsgi_server.module_handlers:
if hasattr(handler,'load_addons'):
handler.load_addons()
return res
def download(self, cr, uid, ids, download=True, context=None):
res = []
default_version = modules.adapt_version('1.0')
for mod in self.browse(cr, uid, ids, context=context):
if not mod.url:
continue
match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
version = '0'
version = default_version
if match:
version = match.group(1)
if parse_version(mod.installed_version or '0') >= parse_version(version):
if parse_version(mod.installed_version) >= parse_version(version):
continue
res.append(mod.url)
if not download:
continue
zip_content = urllib.urlopen(mod.url).read()
fname = modules.get_module_path(str(mod.name)+'.zip', downloaded=True)
fname = modules.get_module_path(str(mod.name) + '.zip', downloaded=True)
try:
with open(fname, 'wb') as fp:
fp.write(zip_content)
@@ -614,17 +645,77 @@ class module(osv.osv):
raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
terp = self.get_module_info(mod.name)
self.write(cr, uid, mod.id, self.get_values_from_terp(terp))
cr.execute('DELETE FROM ir_module_module_dependency ' \
'WHERE module_id = %s', (mod.id,))
self._update_dependencies(cr, uid, mod, terp.get('depends',
[]))
self._update_category(cr, uid, mod, terp.get('category',
'Uncategorized'))
cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (mod.id,))
self._update_dependencies(cr, uid, mod, terp.get('depends', []))
self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
# Import module
zimp = zipimport.zipimporter(fname)
zimp.load_module(mod.name)
return res
def install_from_urls(self, cr, uid, urls, context=None):
OPENERP = 'openerp'
tmp = tempfile.mkdtemp()
try:
for module_name, url in urls.items():
if not url:
continue # nothing to download, local version is already the last one
try:
content = urllib2.urlopen(url).read()
except Exception, e:
_logger.exception('ggr')
raise osv.except_osv('grrr', e)
else:
zipfile.ZipFile(StringIO(content)).extractall(tmp)
assert os.path.isdir(os.path.join(tmp, module_name))
for module_name in urls:
if module_name == OPENERP:
continue # special case. handled below
module_path = modules.get_module_path(module_name, downloaded=True, display_warning=False)
bck = backup(module_path, False)
shutil.move(os.path.join(tmp, module_name), module_path)
if bck:
shutil.rmtree(bck)
if urls.get(OPENERP, None):
# special case. it containt the server and the base module.
# extract path is not the same
base_path = os.path.dirname(modules.get_module_path('base'))
# copy all modules in the SERVER/openerp/addons directory to the new "openerp" module (except base itself)
for d in os.listdir(base_path):
if d != 'base' and os.path.isdir(os.path.join(base_path, d)):
destdir = os.path.join(tmp, OPENERP, 'addons', d) # XXX 'openerp' subdirectory ?
shutil.copytree(os.path.join(base_path, d), destdir)
# then replace the server by the new "base" module
server_dir = openerp.tools.config['root_path'] # XXX or dirname()
bck = backup(server_dir)
shutil.move(os.path.join(tmp, OPENERP), server_dir)
#if bck:
# shutil.rmtree(bck)
self.update_list(cr, uid, context=context)
ids = self.search(cr, uid, [('name', 'in', urls.keys())], context=context)
if self.search_count(cr, uid, [('id', 'in', ids), ('state', '=', 'installed')], context=context):
# if any to update
cr.commit()
openerp.service.restart_server()
return {
'type': 'ir.actions.client',
'tag': 'home',
'params': {'wait': True},
}
return self.button_immediate_install(cr, uid, ids, context=context)
finally:
shutil.rmtree(tmp)
def install_by_names(self, cr, uid, names, context=None):
raise NotImplementedError('# TODO')
def _update_dependencies(self, cr, uid, mod_browse, depends=None):
if depends is None:
depends = []
@@ -679,20 +770,20 @@ class module_dependency(osv.osv):
_columns = {
# The dependency name
'name': fields.char('Name', size=128, select=True),
'name': fields.char('Name', size=128, select=True),
# The module that depends on it
'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'),
'state': fields.function(_state, type='selection', selection=[
('uninstallable','Uninstallable'),
('uninstalled','Not Installed'),
('installed','Installed'),
('to upgrade','To be upgraded'),
('to remove','To be removed'),
('to install','To be installed'),
('uninstallable', 'Uninstallable'),
('uninstalled', 'Not Installed'),
('installed', 'Installed'),
('to upgrade', 'To be upgraded'),
('to remove', 'To be removed'),
('to install', 'To be installed'),
('unknown', 'Unknown'),
], string='Status', readonly=True, select=True),
], string='Status', readonly=True, select=True),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+59 -40
View File
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Modules Categories -->
<record id="view_module_category_form" model="ir.ui.view">
<field name="name">ir.module.category.form</field>
<field name="model">ir.module.category</field>
@@ -32,7 +30,6 @@
</record>
<!-- Click on a category -->
<record id="view_module_filter" model="ir.ui.view">
<field name="name">ir.module.module.list.select</field>
<field name="model">ir.module.module</field>
@@ -43,7 +40,7 @@
<filter name="app" icon="terp-check" string="Apps" domain="[('application', '=', 1)]"/>
<filter name="extra" icon="terp-check" string="Extra" domain="[('application', '=', 0)]"/>
<separator/>
<filter icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
<filter name="installed" icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
<filter icon="terp-dialog-close" string="Not Installed" domain="[('state', 'in', ['uninstalled', 'uninstallable', 'to install'])]"/>
<field name="category_id"/>
<group expand="0" string="Group By...">
@@ -53,37 +50,6 @@
</search>
</field>
</record>
<record model="ir.ui.view" id="module_view_kanban">
<field name="name">Modules Kanban</field>
<field name="model">ir.module.module</field>
<field name="arch" type="xml">
<kanban create="false">
<field name="icon"/>
<field name="name"/>
<field name="state"/>
<field name="summary"/>
<templates>
<t t-name="kanban-box">
<div class="oe_module_vignette">
<t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
<img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
<div class="oe_module_desc">
<h4><a type="open"><field name="shortdesc"/></a></h4>
<p class="oe_module_name">
<t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
<i><field name="name" groups="base.group_no_one"/></i>
</p>
<button type="object" name="button_immediate_install" states="uninstalled">Install</button>
<button t-if="installed" disabled="disabled">Installed</button>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="action_module_open_categ" model="ir.actions.act_window">
<field name="name">Modules</field>
<field name="res_model">ir.module.module</field>
@@ -100,7 +66,6 @@
<!-- Modules -->
<record id="module_form" model="ir.ui.view">
<field name="name">ir.module.module.form</field>
<field name="model">ir.module.module</field>
@@ -176,20 +141,74 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="module_view_kanban">
<field name="name">Modules Kanban</field>
<field name="model">ir.module.module</field>
<field name="arch" type="xml">
<kanban create="false">
<field name="icon"/>
<field name="name"/>
<field name="state"/>
<field name="summary"/>
<templates>
<t t-name="kanban-box">
<div class="oe_module_vignette">
<t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
<img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
<div class="oe_module_desc">
<h4><a type="open"><field name="shortdesc"/></a></h4>
<p class="oe_module_name">
<t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
<i><field name="name" groups="base.group_no_one"/></i>
</p>
<button type="object" name="button_immediate_install" states="uninstalled">Install</button>
<button t-if="installed" disabled="disabled">Installed</button>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="open_module_tree" model="ir.actions.act_window">
<field name="name">Install a Module</field>
<!-- uncomment on released
<field name="name">Installed Modules</field>
-->
<field name="name">Modules</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_app':1}</field>
<!-- uncomment on released
<field name="context">{'search_default_installed':1}</field>
-->
<field name="search_view_id" ref="view_module_filter"/>
<field name="help" type="html">
<p><b>No module found!</b></p>
<p>You should try others search criteria.</p>
</field>
</record>
<menuitem id="menu_module_tree" parent="base.menu_management" name="Modules"
sequence="1" action="open_module_tree"/>
<menuitem id="menu_module_tree" parent="menu_management" name="Installed Modules" sequence="10" action="open_module_tree"/>
<!-- Apps modules -->
<record model="ir.actions.client" id="modules_act_cl">
<field name="name">Apps</field>
<field name="tag">apps</field>
</record>
<!-- uncomment on released
<menuitem id="module_mi" parent="base.menu_management" sequence="3" action="modules_act_cl"/>
-->
<menuitem id="module_mi" parent="base.menu_management" sequence="20" action="modules_act_cl"/>
<record model="ir.actions.client" id="modules_updates_act_cl">
<field name="name">Updates</field>
<field name="tag">apps.updates</field>
<field name="params">{}</field>
</record>
<!-- uncomment on released
<menuitem id="menu_module_updates" parent="base.menu_management" sequence="7" action="modules_updates_act_cl"/>
-->
<menuitem id="menu_module_updates" parent="base.menu_management" sequence="30" action="modules_updates_act_cl"/>
</data>
</openerp>
@@ -43,7 +43,7 @@
id="menu_view_base_module_import"
parent="menu_management"
groups="base.group_no_one"
sequence="1"/>
sequence="6"/>
-->
</data>
@@ -18,17 +18,17 @@
</group>
<footer>
<div states="init">
<button name="update_module" string="Update" type="object" class="oe_highlight"/> or
<button name="update_module" string="Update" type="object" class="oe_highlight"/> or
<button special="cancel" string="Cancel" class="oe_link"/>
</div>
<div states="done">
<button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or
<button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or
<button special="cancel" string="Close" class="oe_link"/>
</div>
</footer>
</form>
</field>
</record>
</record>
<record id="action_view_base_module_update" model="ir.actions.act_window">
<field name="name">Module Update</field>
@@ -45,7 +45,7 @@
id="menu_view_base_module_update"
groups="base.group_no_one"
parent="menu_management"
sequence="2"
sequence="40"
icon="STOCK_CONVERT"/>
</data>
@@ -35,7 +35,7 @@
groups="base.group_no_one"
id="menu_view_base_module_upgrade"
parent="menu_management"
sequence="3"/>
sequence="50"/>
<record id="view_base_module_upgrade_install" model="ir.ui.view">
<field name="name">Module Upgrade Install</field>
+18 -10
View File
@@ -466,7 +466,8 @@ class res_config_settings(osv.osv_memory):
groups.append((name, ref(field_group), ref(field.implied_group)))
elif name.startswith('module_') and isinstance(field, fields.boolean):
mod_ids = ir_module.search(cr, uid, [('name', '=', name[7:])])
modules.append((name, ir_module.browse(cr, uid, mod_ids[0], context)))
record = ir_module.browse(cr, uid, mod_ids[0], context) if mod_ids else None
modules.append((name, record))
else:
others.append(name)
@@ -490,7 +491,7 @@ class res_config_settings(osv.osv_memory):
# modules: which modules are installed/to install
for name, module in classified['module']:
res[name] = module.state in ('installed', 'to install', 'to upgrade')
res[name] = module and module.state in ('installed', 'to install', 'to upgrade')
# other fields: call all methods that start with 'get_default_'
for method in dir(self):
@@ -501,9 +502,7 @@ class res_config_settings(osv.osv_memory):
def execute(self, cr, uid, ids, context=None):
ir_values = self.pool.get('ir.values')
ir_model_data = self.pool.get('ir.model.data')
ir_module = self.pool.get('ir.module.module')
res_groups = self.pool.get('res.groups')
classified = self._get_classified_fields(cr, uid, context)
config = self.browse(cr, uid, ids[0], context)
@@ -526,17 +525,26 @@ class res_config_settings(osv.osv_memory):
getattr(self, method)(cr, uid, ids, context)
# module fields: install/uninstall the selected modules
to_install_ids = []
to_install_names = []
to_uninstall_ids = []
lm = len('module_')
for name, module in classified['module']:
if config[name]:
if module.state == 'uninstalled': to_install_ids.append(module.id)
if not module or module.state == 'uninstalled':
to_install_names.append(name[lm:])
else:
if module.state in ('installed','upgrade'): to_uninstall_ids.append(module.id)
if module and module.state in ('installed', 'to upgrade'):
to_uninstall_ids.append(module.id)
if to_install_ids or to_uninstall_ids:
ir_module.button_uninstall(cr, uid, to_uninstall_ids, context=context)
ir_module.button_immediate_install(cr, uid, to_install_ids, context=context)
if to_uninstall_ids:
ir_module.button_immediate_uninstall(cr, uid, to_uninstall_ids, context=context)
if to_install_names:
return {
'type': 'ir.actions.client',
'tag': 'apps',
'params': {'modules': to_install_names},
}
config = self.pool.get('res.config').next(cr, uid, [], context=context) or {}
if config.get('type') not in ('ir.actions.act_window_close',):
+117
View File
@@ -0,0 +1,117 @@
openerp.base = function(instance) {
instance.base.apps_remote = null;
instance.base.apps_client = null;
instance.base.Apps = instance.web.Widget.extend({
template: 'EmptyComponent',
remote_action_id: 'loempia.action_embed',
failback_action_id: 'base.open_module_tree',
init: function(parent, action) {
this._super(parent, action);
var options = action.params || {};
if (options.apps_user) {
sessionStorage.setItem('apps.login', options.apps_user);
}
if (options.apps_access_token) {
sessionStorage.setItem('apps.access_token', options.apps_access_token);
}
this.params = options; // NOTE read by embedded client action
},
get_client: function() {
// return the client via a deferred, resolved or rejected depending if the remote host is available or not.
var check_client_available = function(client) {
var d = $.Deferred();
var i = new Image();
i.onerror = function() {
d.reject(client);
};
i.onload = function() {
client.session.session_bind(client.origin).then(function() {
// check if client can authenticate
client.authenticate().then(
function() { /* done */
d.resolve(client);
}, function() { /* fail */
if (client.login === 'anonymous') {
d.reject(client);
} else {
sessionStorage.removeItem('apps.login');
sessionStorage.removeItem('apps.access_token');
client.bind_crendentials(client.dbname, 'anonymous', 'anonymous');
client.authenticate().then(
function() { /* done */
d.resolve(client);
}, function() { /* fail */
d.reject(client);
});
}
});
});
};
i.src = _.str.sprintf('%s/web/static/src/img/sep-a.gif', client.origin);
return d.promise();
};
if (instance.base.apps_client) {
return check_client_available(instance.base.apps_client);
} else {
var ICP = new instance.web.Model('ir.config_parameter');
return ICP.call('get_param', ['apps.server', 'https://apps.openerp.com/apps']).then(function(u) {
var link = $(_.str.sprintf('<a href="%s"></a>', u))[0];
var host = _.str.sprintf('%s//%s', link.protocol, link.host);
var dbname = link.pathname;
if (dbname[0] === '/') {
dbname = dbname.substr(1);
}
var login = (sessionStorage ? sessionStorage.getItem('apps.login') : null) || 'anonymous';
var passwd = (sessionStorage ? sessionStorage.getItem('apps.access_token') : null) || 'anonymous';
if (_.isNull(instance.base.apps_remote)) {
instance.base.apps_remote = new openerp.init();
}
var client = new instance.base.apps_remote.web.EmbeddedClient(null, host, dbname, login, passwd);
instance.base.apps_client = client;
return check_client_available(client);
});
}
},
destroy: function() {
if (instance.base.apps_client) {
instance.base.apps_client.destroy();
}
return this._super();
},
start: function() {
var self = this;
return self.get_client().
done(function(client) {
client.replace(self.$el).
done(function() {
client.$el.removeClass('openerp');
client.do_action(self.remote_action_id);
});
}).
fail(function(client) {
self.do_warn('Apps Server not reachable.', 'Showing local modules.', true);
self.rpc('/web/action/load', {action_id: self.failback_action_id}).done(function(action) {
self.do_action(action);
instance.webclient.menu.open_action(action.id);
});
});
},
});
instance.base.AppsUpdates = instance.base.Apps.extend({
remote_action_id: 'loempia.action_embed_updates'
});
instance.web.client_actions.add("apps", "instance.base.Apps");
instance.web.client_actions.add("apps.updates", "instance.base.AppsUpdates");
};
+7 -2
View File
@@ -207,10 +207,15 @@ def quit_on_signals():
pass
config = openerp.tools.config
openerp.service.stop_services()
if getattr(openerp, 'phoenix', False):
# like the phoenix, reborn from ashes...
openerp.service._reexec()
return
if config['pidfile']:
os.unlink(config['pidfile'])
openerp.service.stop_services()
sys.exit(0)
def configure_babel_localedata_path():
+3 -2
View File
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -32,7 +32,8 @@ from openerp.modules.module import \
load_information_from_description_file, \
get_module_resource, zip_directory, \
get_module_path, initialize_sys_path, \
load_openerp_module, init_module_models
load_openerp_module, init_module_models, \
adapt_version
from openerp.modules.loading import load_modules
+13 -5
View File
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -329,7 +329,7 @@ def load_information_from_description_file(module):
'license': 'AGPL-3',
'name': False,
'post_load': None,
'version': '0.0.0',
'version': '1.0',
'web': False,
'website': '',
'sequence': 100,
@@ -349,6 +349,7 @@ def load_information_from_description_file(module):
# 'active' has been renamed 'auto_install'
info['auto_install'] = info['active']
info['version'] = adapt_version(info['version'])
return info
#TODO: refactor the logger in this file to follow the logging guidelines
@@ -447,15 +448,22 @@ def get_modules():
def get_modules_with_version():
modules = get_modules()
res = {}
res = dict.fromkeys(modules, adapt_version('1.0'))
for module in modules:
try:
info = load_information_from_description_file(module)
res[module] = "%s.%s" % (release.major_version, info['version'])
except Exception, e:
res[module] = info['version']
except Exception:
continue
return res
def adapt_version(version):
serie = release.major_version
if version == serie or not version.startswith(serie + '.'):
version = '%s.%s' % (serie, version)
return version
def get_test_modules(module, submodule, explode):
"""
Return a list of submodules containing tests.
+2
View File
@@ -50,4 +50,6 @@ author = 'OpenERP S.A.'
author_email = 'info@openerp.com'
license = 'AGPL-3'
nt_service_name = "openerp-server-" + serie
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+38 -2
View File
@@ -21,6 +21,10 @@
##############################################################################
import logging
import os
import signal
import subprocess
import sys
import threading
import time
@@ -33,6 +37,7 @@ import wsgi_server
import openerp.modules
import openerp.netsvc
import openerp.osv
from openerp.release import nt_service_name
import openerp.tools
#.apidoc title: RPC Services
@@ -97,27 +102,58 @@ def stop_services():
_logger.info("Initiating shutdown")
_logger.info("Hit CTRL-C again or send a second signal to force the shutdown.")
logging.shutdown()
# Manually join() all threads before calling sys.exit() to allow a second signal
# to trigger _force_quit() in case some non-daemon threads won't exit cleanly.
# threading.Thread.join() should not mask signals (at least in python 2.5).
me = threading.currentThread()
_logger.debug('current thread: %r', me)
for thread in threading.enumerate():
_logger.debug('process %r (%r)', thread, thread.isDaemon())
if thread != me and not thread.isDaemon() and thread.ident != main_thread_id:
while thread.isAlive():
_logger.debug('join and sleep')
# Need a busyloop here as thread.join() masks signals
# and would prevent the forced shutdown.
thread.join(0.05)
time.sleep(0.05)
_logger.debug('--')
openerp.modules.registry.RegistryManager.delete_all()
logging.shutdown()
def start_services_workers():
import openerp.service.workers
openerp.multi_process = True
openerp.service.workers.Multicorn(openerp.service.wsgi_server.application).run()
def _reexec():
"""reexecute openerp-server process with (nearly) the same arguments"""
if openerp.tools.osutil.is_running_as_nt_service():
subprocess.call('sc stop {0} && sc start {0}'.format(nt_service_name), shell=True)
exe = os.path.basename(sys.executable)
strip_args = ['-d', '-u']
a = sys.argv[:]
args = [x for i, x in enumerate(a) if x not in strip_args and a[max(i - 1, 0)] not in strip_args]
if not args or args[0] != exe:
args.insert(0, exe)
os.execv(sys.executable, args)
def restart_server():
if openerp.multi_process:
raise NotImplementedError("Multicorn is not supported (but gunicorn was)")
pid = openerp.wsgi.core.arbiter_pid
os.kill(pid, signal.SIGHUP)
else:
if os.name == 'nt':
def reborn():
stop_services()
_reexec()
# run in a thread to let the current thread return response to the caller.
threading.Thread(target=reborn).start()
else:
openerp.phoenix = True
os.kill(os.getpid(), signal.SIGINT)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+6 -1
View File
@@ -54,7 +54,12 @@ from openerp import SUPERUSER_ID
_logger = logging.getLogger(__name__)
RPC_VERSION_1 = {'server_version': '6.1', 'protocol_version': 1}
RPC_VERSION_1 = {
'server_version': release.version,
'server_version_info': release.version_info,
'server_serie': release.serie,
'protocol_version': 1,
}
# This should be moved to openerp.modules.db, along side initialize().
def _initialize_db(serv, id, db_name, demo, lang, user_password):
+1
View File
@@ -442,5 +442,6 @@ def stop_service():
"""
if httpd:
httpd.shutdown()
openerp.netsvc.close_socket(httpd.socket)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+59
View File
@@ -26,6 +26,12 @@ Some functions related to the os and os.path module
import os
from os.path import join as opj
if os.name == 'nt':
import ctypes
import win32service as ws
import win32serviceutil as wsu
def listdir(dir, recursive=False):
"""Allow to recursively get the file listing"""
dir = os.path.normpath(dir)
@@ -56,6 +62,59 @@ def walksymlinks(top, topdown=True, onerror=None):
yield dirpath, dirnames, filenames
if os.name != 'nt':
getppid = os.getppid
is_running_as_nt_service = lambda: False
else:
# based on http://mail.python.org/pipermail/python-win32/2007-June/006174.html
_TH32CS_SNAPPROCESS = 0x00000002
class _PROCESSENTRY32(ctypes.Structure):
_fields_ = [("dwSize", ctypes.c_ulong),
("cntUsage", ctypes.c_ulong),
("th32ProcessID", ctypes.c_ulong),
("th32DefaultHeapID", ctypes.c_ulong),
("th32ModuleID", ctypes.c_ulong),
("cntThreads", ctypes.c_ulong),
("th32ParentProcessID", ctypes.c_ulong),
("pcPriClassBase", ctypes.c_ulong),
("dwFlags", ctypes.c_ulong),
("szExeFile", ctypes.c_char * 260)]
def getppid():
CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
Process32First = ctypes.windll.kernel32.Process32First
Process32Next = ctypes.windll.kernel32.Process32Next
CloseHandle = ctypes.windll.kernel32.CloseHandle
hProcessSnap = CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
current_pid = os.getpid()
try:
pe32 = _PROCESSENTRY32()
pe32.dwSize = ctypes.sizeof(_PROCESSENTRY32)
if not Process32First(hProcessSnap, ctypes.byref(pe32)):
raise OSError('Failed getting first process.')
while True:
if pe32.th32ProcessID == current_pid:
return pe32.th32ParentProcessID
if not Process32Next(hProcessSnap, ctypes.byref(pe32)):
return None
finally:
CloseHandle(hProcessSnap)
from contextlib import contextmanager
from openerp.release import nt_service_name
def is_running_as_nt_service():
@contextmanager
def close_srv(srv):
try:
yield srv
finally:
ws.CloseServiceHandle(srv)
with close_srv(ws.OpenSCManager(None, None, ws.SC_MANAGER_ALL_ACCESS)) as hscm:
with close_srv(wsu.SmartOpenService(hscm, nt_service_name, ws.SERVICE_ALL_ACCESS)) as hs:
info = ws.QueryServiceStatusEx(hs)
return info['ProcessId'] == getppid()
if __name__ == '__main__':
from pprint import pprint as pp
+21 -36
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,14 +15,12 @@
# 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/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# Win32 python extensions modules
import win32serviceutil
import win32service
import win32event
import win32api
import win32process
import servicemanager
@@ -30,35 +28,32 @@ import servicemanager
import sys
import subprocess
import os
import thread
try:
import meta
except ImportError:
if hasattr(sys, 'frozen'):
raise
from setup import generate_files
generate_files()
import meta # noqa
class OpenERPServerService(win32serviceutil.ServiceFramework):
# required info
_svc_name_ = "openerp-server-6.1"
_svc_display_name_ = "OpenERP Server 6.1"
# optionnal info
_svc_description_ = "OpenERP Server 6.1 service"
_svc_name_ = meta.nt_service_name
_svc_display_name_ = "%s %s" % (meta.description, meta.serie)
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
# a reference to the server's process
self.terpprocess = None
# info if the service terminates correctly or if the server crashed
self.stopping = False
def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# stop the running TERP Server: say it's a normal exit
# stop the running OpenERP Server: say it's a normal exit
win32api.TerminateProcess(int(self.terpprocess._handle), 0)
servicemanager.LogInfoMsg("OpenERP Server stopped correctly")
# And set my event.
win32event.SetEvent(self.hWaitStop)
def StartTERP(self):
# The server finds now its configuration automatically on Windows
@@ -69,29 +64,19 @@ class OpenERPServerService(win32serviceutil.ServiceFramework):
server_path = os.path.join(server_dir, 'server', 'openerp-server.exe')
self.terpprocess = subprocess.Popen([server_path], cwd=server_dir, creationflags=win32process.CREATE_NO_WINDOW)
def StartControl(self,ws):
# this listens to the Service Manager's events
win32event.WaitForSingleObject(ws, win32event.INFINITE)
self.stopping = True
def SvcDoRun(self):
# Start OpenERP Server itself
self.StartTERP()
# start the loop waiting for the Service Manager's stop signal
thread.start_new_thread(self.StartControl, (self.hWaitStop,))
# Log a info message that the server is running
servicemanager.LogInfoMsg("OpenERP Server up and running")
# verification if the server is really running, else quit with an error
self.terpprocess.wait()
if not self.stopping:
sys.exit("OpenERP Server check: server not running, check the logfile for more info")
# exit with same exit code as OpenERP process
sys.exit(self.terpprocess.wait())
def option_handler(opts):
# configure the service to auto restart on failures...
subprocess.call(['sc', 'failure', meta.nt_service_name, 'reset=', '0', 'actions=', 'restart/0/restart/0/restart/0'])
if __name__=='__main__':
if __name__ == '__main__':
# Do with the service whatever option is passed in the command line
win32serviceutil.HandleCommandLine(OpenERPServerService)
win32serviceutil.HandleCommandLine(OpenERPServerService, customOptionHandler=option_handler)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+41 -10
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# 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/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -30,15 +30,46 @@ def datas():
r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*')))
return r
setup(service=["OpenERPServerService"],
options={"py2exe":{"excludes":["Tkconstants","Tkinter","tcl",
"_imagingtk","PIL._imagingtk",
"ImageTk", "PIL.ImageTk",
"FixTk"],
"skip_archive": 1,
"optimize": 2,}},
meta = {}
execfile(os.path.join(os.path.dirname(__file__), '..', 'openerp', 'release.py'), meta)
def generate_files():
actions = {
'start': ['stop', 'start'],
'stop': ['stop'],
}
files = []
for action, steps in actions.items():
fname = action + '.bat'
files.append(fname)
with open(fname, 'w') as fp:
fp.write('@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.\n')
for step in steps:
fp.write('@net %s %s\n' % (step, meta['nt_service_name']))
files.append('meta.py')
with open('meta.py', 'w') as fp:
for m in 'description serie nt_service_name'.split():
fp.write("%s = %r\n" % (m, meta[m],))
return files
excludes = "Tkconstants Tkinter tcl _imagingtk PIL._imagingtk ImageTk PIL.ImageTk FixTk".split()
setup(service = ["OpenERPServerService"],
version = meta['version'],
license = meta['license'],
url = meta['url'],
author = meta['author'],
author_email = meta['author_email'],
data_files = generate_files(),
options = {"py2exe": {
"excludes": excludes,
"skip_archive": 1,
"optimize": 2,
}},
data_files=datas(),
)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-7
View File
@@ -1,7 +0,0 @@
@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.
@net stop openerp-server-6.1
@net start openerp-server-6.1
cls
-5
View File
@@ -1,5 +0,0 @@
@PATH=%WINDIR%\system32;%WINDIR%;%WINDIR%\System32\Wbem;.
@net stop openerp-server-6.1
cls