Simplify module information with python configuration

review363001
This commit is contained in:
Cédric Krier committed 2012-06-08 19:32:23 +02:00
1 parent 1aae951f92
commit a09d9a54a1
21 files changed
+189 -526

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Replace __tryton__.py by tryton.cfg
* Allow to use Reference field in One2Many & Many2Many
* Remove hexmd5 from ModelView.fields_view_get
* Allow client to manage model access
+4
View File
@@ -10,6 +10,7 @@ recursive-include doc *.po
recursive-include doc *.pot
include etc/*
include trytond/backend/*/init.sql
include trytond/ir/tryton.cfg
include trytond/ir/*.xml
include trytond/ir/locale/*.po
include trytond/ir/module/*.xml
@@ -17,8 +18,11 @@ include trytond/ir/ui/*.xml
include trytond/ir/ui/*.rng
include trytond/ir/ui/*.rnc
include trytond/ir/ui/icons/*.svg
include trytond/res/tryton.cfg
include trytond/res/*.xml
include trytond/res/locale/*.po
include trytond/test/tryton.cfg
include trytond/test/*.xml
include trytond/webdav/tryton.cfg
include trytond/webdav/*.xml
include trytond/webdav/locale/*.po
+25 -56
View File
@@ -15,7 +15,7 @@ A module is a directory in trytond/modules which contains at least two files:
* ``__init__.py``: a Tryton module must be a Python module.
* ``__tryton__.py``: a Python file that describes the Tryton module.
* ``tryton.cfg``: a Configuration file that describes the Tryton module.
``__init__.py`` file
--------------------
@@ -24,69 +24,35 @@ It is the Python ``__init__.py`` to define a module. It must import all the
Python files from the module.
``__tryton__.py`` file
----------------------
``tryton.cfg`` file
-------------------
It is a Python file that must contain only one dictionary with those keywords:
* ``name``: The name of the module.
* ``name_language_code``: The name of the module in the language code.
It is a configuration file using the format of `ConfigParser`_ that must
contain `tryton` section with this following name:
* ``version``: The version number of the module.
* ``author``: The author name of the module.
* ``depends``: A one per line list of modules on which this module depends.
* ``email``: The email address of the author (optional).
* ``extras_depend``: A one per line list of modules on which this module
*may* depend.
* ``website``: The url of the website for the module (optional).
* ``xml``: The one per line list of the XML files of the module. They will
be loaded in the given order at the installation or update of the module.
* ``description``: A long description of the module.
Here is an example::
* ``description_language_code``: The long description in the language code.
* ``depends``: A list of modules on which this module depends.
* ``extras_depend``: A list of modules on which this module *may* depend.
* ``xml``: The list of the XML files of the module. They will be loaded in
the given order at the installation or update of the module.
* ``translation``: The list of csv files that contain the translation. The
name of the files must be the language code.
Here is an example:
.. highlight:: python
::
{
"name" : "Party",
"version" : "0.0.1",
"author" : "B2CK",
'email': 'info@b2ck.com',
'website': 'http://www.tryton.org/',
"category" : "Generic",
"description": "Define parties, addresses and co.",
"depends" : [
"ir",
"res",
"country",
],
"xml" : [
"party.xml",
"category.xml",
"address.xml",
"contact_mechanism.xml",
],
'translation': [
'fr_FR.csv',
'de_DE.csv',
'es_ES.csv',
],
}
[tryton]
version=0.0.1
depends:
ir
res
country
xml:
party.xml
category.xml
address.xml
contact_mechanism.xml
Python Files
============
@@ -194,3 +160,6 @@ Here is the list of the tags:
separated by commas.
* ``active``: A boolean telling if the menu is active or not.
.. _ConfigParser: http://docs.python.org/library/configparser.html
+10 -11
View File
@@ -15,11 +15,10 @@ setup(name=PACKAGE,
version=VERSION,
description='Tryton server',
long_description=read('README'),
author='B2CK',
author_email='info@b2ck.com',
author='Tryton',
url=WEBSITE,
download_url="http://downloads.tryton.org/" + \
VERSION.rsplit('.', 1)[0] + '/',
VERSION.rsplit('.', 1)[0] + '/',
packages=find_packages(exclude=['*.modules.*', 'modules.*', 'modules',
'*.proteus.*', 'proteus.*', 'proteus']),
package_data={
@@ -27,13 +26,13 @@ setup(name=PACKAGE,
'trytond.backend.mysql': ['init.sql'],
'trytond.backend.postgresql': ['init.sql'],
'trytond.backend.sqlite': ['init.sql'],
'trytond.ir': ['*.xml', 'locale/*.po'],
'trytond.ir': ['tryton.cfg', '*.xml', 'locale/*.po'],
'trytond.ir.module': ['*.xml'],
'trytond.ir.ui': ['*.xml', '*.rng', '*.rnc'],
'trytond.res': ['*.xml', 'locale/*.po'],
'trytond.webdav': ['*.xml', 'locale/*.po'],
'trytond.test': ['*.xml'],
},
'trytond.res': ['tryton.cfg', '*.xml', 'locale/*.po'],
'trytond.webdav': ['tryton.cfg', '*.xml', 'locale/*.po'],
'trytond.test': ['tryton.cfg', '*.xml'],
},
scripts=['bin/trytond'],
classifiers=[
'Development Status :: 5 - Production/Stable',
@@ -53,7 +52,7 @@ setup(name=PACKAGE,
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries :: Application Frameworks',
],
],
license=LICENSE,
install_requires=[
'lxml >= 2.0',
@@ -61,7 +60,7 @@ setup(name=PACKAGE,
'Genshi',
'python-dateutil',
'polib',
],
],
extras_require={
'PostgreSQL': ['psycopg2 >= 2.0'],
'MySQL': ['MySQL-python'],
@@ -72,7 +71,7 @@ setup(name=PACKAGE,
'timezone': ['pytz'],
'simplejson': ['simplejson'],
'cdecimal': ['cdecimal'],
},
},
zip_safe=False,
test_suite='trytond.tests',
test_loader='trytond.test_loader:Loader',
+15 -24
View File
@@ -171,38 +171,29 @@ class Database(DatabaseInterface):
@staticmethod
def init(cursor):
from trytond.tools import safe_eval
from trytond.modules import get_module_info
sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
with open(sql_file) as fp:
for line in fp.read().split(';'):
if (len(line) > 0) and (not line.isspace()):
cursor.execute(line)
for i in ('ir', 'res', 'webdav'):
root_path = os.path.join(os.path.dirname(__file__), '..', '..')
tryton_file = os.path.join(root_path, i, '__tryton__.py')
with open(tryton_file) as fp:
info = safe_eval(fp.read())
active = info.get('active', False)
if active:
for module in ('ir', 'res', 'webdav'):
state = 'uninstalled'
if module in ('ir', 'res'):
state = 'to install'
else:
state = 'uninstalled'
cursor.execute('INSERT INTO ir_module_module ' \
'(create_uid, create_date, author, website, name, ' \
'shortdesc, description, state) ' \
'VALUES (%s, now(), %s, %s, %s, %s, %s, %s)',
(0, info.get('author', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), state))
info = get_module_info(module)
cursor.execute('INSERT INTO ir_module_module '
'(create_uid, create_date, name, state) '
'VALUES (%s, now(), %s, %s)',
(0, module, state))
cursor.execute('SELECT LAST_INSERT_ID()')
module_id = cursor.fetchone()[0]
dependencies = info.get('depends', [])
for dependency in dependencies:
cursor.execute('INSERT INTO ir_module_module_dependency ' \
'(create_uid, create_date, module, name) ' \
'VALUES (%s, now(), %s, %s)',
(0, module_id, dependency))
module_id, = cursor.fetchone()
for dependency in info.get('depends', []):
cursor.execute('INSERT INTO ir_module_module_dependency '
'(create_uid, create_date, module, name) '
'VALUES (%s, now(), %s, %s)',
(0, module_id, dependency))
class _Cursor(MySQLdb.cursors.Cursor):
-5
View File
@@ -97,13 +97,8 @@ CREATE TABLE ir_module_module (
create_date TIMESTAMP NOT NULL,
write_date TIMESTAMP NULL,
write_uid BIGINT,
website VARCHAR(255),
name VARCHAR(255) NOT NULL,
author VARCHAR(255),
url VARCHAR(255),
state VARCHAR(255),
shortdesc VARCHAR(255),
description TEXT,
PRIMARY KEY(id),
CONSTRAINT ir_module_module_create_uid_fkey FOREIGN KEY (create_uid) REFERENCES res_user (id) ON DELETE SET NULL,
CONSTRAINT ir_module_module_write_uid_fkey FOREIGN KEY (write_uid) REFERENCES res_user (id) ON DELETE SET NULL
+14 -23
View File
@@ -223,38 +223,29 @@ class Database(DatabaseInterface):
@staticmethod
def init(cursor):
from trytond.tools import safe_eval
from trytond.modules import get_module_info
sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
with open(sql_file) as fp:
for line in fp.read().split(';'):
if (len(line) > 0) and (not line.isspace()):
cursor.execute(line)
for i in ('ir', 'res', 'webdav'):
root_path = os.path.join(os.path.dirname(__file__), '..', '..')
tryton_file = os.path.join(root_path, i, '__tryton__.py')
with open(tryton_file) as fp:
info = safe_eval(fp.read())
active = info.get('active', False)
if active:
for module in ('ir', 'res', 'webdav'):
state = 'uninstalled'
if module in ('ir', 'res'):
state = 'to install'
else:
state = 'uninstalled'
info = get_module_info(module)
cursor.execute('SELECT NEXTVAL(\'ir_module_module_id_seq\')')
module_id = cursor.fetchone()[0]
cursor.execute('INSERT INTO ir_module_module ' \
'(id, create_uid, create_date, author, website, name, ' \
'shortdesc, description, state) ' \
'VALUES (%s, %s, now(), %s, %s, %s, %s, %s, %s)',
(module_id, 0, info.get('author', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), state))
dependencies = info.get('depends', [])
for dependency in dependencies:
cursor.execute('INSERT INTO ir_module_module_dependency ' \
'(create_uid, create_date, module, name) ' \
'VALUES (%s, now(), %s, %s)',
(0, module_id, dependency))
cursor.execute('INSERT INTO ir_module_module '
'(id, create_uid, create_date, name, state) '
'VALUES (%s, %s, now(), %s, %s)',
(module_id, 0, module, state))
for dependency in info.get('depends', []):
cursor.execute('INSERT INTO ir_module_module_dependency '
'(create_uid, create_date, module, name) '
'VALUES (%s, now(), %s, %s)',
(0, module_id, dependency))
class _Cursor(PsycopgCursor):
-5
View File
@@ -117,13 +117,8 @@ CREATE TABLE ir_module_module (
create_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
write_date TIMESTAMP WITHOUT TIME ZONE,
write_uid INTEGER,
website VARCHAR,
name VARCHAR NOT NULL,
author VARCHAR,
url VARCHAR,
state VARCHAR,
shortdesc VARCHAR,
description TEXT,
PRIMARY KEY(id),
FOREIGN KEY (create_uid) REFERENCES res_user ON DELETE SET NULL,
FOREIGN KEY (write_uid) REFERENCES res_user ON DELETE SET NULL
+15 -24
View File
@@ -215,38 +215,29 @@ class Database(DatabaseInterface):
@staticmethod
def init(cursor):
from trytond.tools import safe_eval
from trytond.modules import get_module_info
sql_file = os.path.join(os.path.dirname(__file__), 'init.sql')
with open(sql_file) as fp:
for line in fp.read().split(';'):
if (len(line) > 0) and (not line.isspace()):
cursor.execute(line)
for i in ('ir', 'res', 'webdav'):
root_path = os.path.join(os.path.dirname(__file__), '..', '..')
tryton_file = os.path.join(root_path, i, '__tryton__.py')
with open(tryton_file) as fp:
info = safe_eval(fp.read())
active = info.get('active', False)
if active:
for module in ('ir', 'res', 'webdav'):
state = 'uninstalled'
if module in ('ir', 'res'):
state = 'to install'
else:
state = 'uninstalled'
cursor.execute('INSERT INTO ir_module_module ' \
'(create_uid, create_date, author, website, name, ' \
'shortdesc, description, state) ' \
'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)',
(0, datetime.datetime.now(), info.get('author', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), state))
info = get_module_info(module)
cursor.execute('INSERT INTO ir_module_module '
'(create_uid, create_date, name, state) '
'VALUES (%s, %s, %s, %s)',
(0, datetime.datetime.now(), module, state))
cursor.execute('SELECT last_insert_rowid()')
module_id = cursor.fetchone()[0]
dependencies = info.get('depends', [])
for dependency in dependencies:
cursor.execute('INSERT INTO ir_module_module_dependency ' \
'(create_uid, create_date, module, name) ' \
'VALUES (%s, %s, %s, %s) ',
(0, datetime.datetime.now(), module_id, dependency))
module_id, = cursor.fetchone()
for dependency in info.get('depends', []):
cursor.execute('INSERT INTO ir_module_module_dependency '
'(create_uid, create_date, module, name) '
'VALUES (%s, %s, %s, %s) ',
(0, datetime.datetime.now(), module_id, dependency))
class _Cursor(sqlite.Cursor):
-5
View File
@@ -83,13 +83,8 @@ CREATE TABLE ir_module_module (
create_date TIMESTAMP,
write_date TIMESTAMP,
write_uid INTEGER,
website VARCHAR,
name VARCHAR,
author VARCHAR,
url VARCHAR,
state VARCHAR,
shortdesc VARCHAR,
description TEXT
);
CREATE TABLE ir_module_module_dependency (
-75
View File
@@ -1,75 +0,0 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
{
'name': 'IR',
'name_bg_BG': 'Вътрешна администрация',
'name_ca_ES': 'Administració interna',
'name_de_DE': 'Interne Administration',
'name_es_AR': 'Administración interna',
'name_es_ES': 'Administración interna',
'name_fr_FR': 'Administration Interne',
'name_nl_NL': 'Interne administratie',
'name_ru_RU': 'Внутреннее управление',
'description': '''Basic module handling internal tasks of the application.
Provides concepts and administration of models, actions, sequences, localizations, cron jobs etc.
''',
'description_bg_BG': '''Общ модул за вътрешните задачи на приложението
- Предлага предсатва и адмнинистрация на модули, десйтвия, последователности, преводи, планировщици и тн.
''',
'description_ca_ES': '''Mòdul bàsic que gestiona les tasques internes de l'aplicació.
Proporciona els conceptes i administració de models, accions, seqüències, localització, tasques planificades, etc.
''',
'description_de_DE': '''Basismodul für interne Aufgaben der Anwendung
- Stellt Konzept und Administration für Modelle, Aktionen, Sequenzen, Lokalisierungen, Zeitplaner etc. zur Verfügung
''',
'description_es_AR': '''Módulo básico que gestiona las tareas internas de la aplicación.
- Provee los conceptos y administración de modelos, acciones, secuencias, localización, tareas programadas, etc...
''',
'description_es_ES': '''Módulo básico que gestiona las tareas internas de la aplicación.
Proporciona los conceptos y administración de modelos, acciones, secuencias, localización, tareas planificadas, etc.
''',
'description_fr_FR': '''Module de base gérant les tâches internes de l'application.
Fournit les concepts et l'administration des modèles, actions, séquences, localizations, planificateur de tâches etc.
''',
'description_nl_NL': '''Basismodule voor interne taken binnen het programma.
- Instellen en beheren van modellen, acties, reeksen, lokalisaties, herhalende taken enz.
''',
'description_ru_RU': '''Базовый модуль обработки внутренних задач приложения.
Обеспечивает концепций и моделей, администрация, действия, последовательность, локализация, Cron Jobs т.д.
''',
'active': True,
'xml': [
'ir.xml',
'ui/ui.xml',
'ui/icon.xml',
'ui/menu.xml',
'ui/view.xml',
'action.xml',
'model.xml',
'sequence.xml',
'attachment.xml',
'cron.xml',
'lang.xml',
'translation.xml',
'export.xml',
'rule.xml',
'property.xml',
'module/module.xml',
'trigger.xml',
],
'translation': [
'locale/cs_CZ.po',
'locale/bg_BG.po',
'locale/ca_ES.po',
'locale/de_DE.po',
'locale/es_AR.po',
'locale/es_CO.po',
'locale/es_ES.po',
'locale/fr_FR.po',
'locale/nl_NL.po',
'locale/ru_RU.po',
],
}
+28 -114
View File
@@ -1,9 +1,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import os
from trytond.model import ModelView, ModelSQL, fields
import trytond.tools as tools
from trytond.modules import create_graph, get_module_list
from trytond.modules import create_graph, get_module_list, get_module_info
from trytond.wizard import Wizard, StateView, Button, StateTransition, \
StateAction
from trytond.backend import TableHandler
@@ -17,10 +15,6 @@ class Module(ModelSQL, ModelView):
_name = "ir.module.module"
_description = __doc__
name = fields.Char("Name", readonly=True, required=True)
shortdesc = fields.Char('Short description', readonly=True, translate=True)
description = fields.Text("Description", readonly=True, translate=True)
author = fields.Char("Author", readonly=True)
website = fields.Char("Website", readonly=True)
version = fields.Function(fields.Char('Version'), 'get_version')
dependencies = fields.One2Many('ir.module.module.dependency',
'module', 'Dependencies', readonly=True)
@@ -77,26 +71,10 @@ class Module(ModelSQL, ModelView):
def default_state(self):
return 'uninstalled'
@staticmethod
def get_module_info(name):
"Return the content of the __tryton__.py"
try:
if name in ['ir', 'res', 'webdav']:
file_p = tools.file_open(os.path.join(name, '__tryton__.py'))
else:
file_p = tools.file_open(os.path.join(name, '__tryton__.py'))
with file_p:
data = file_p.read()
info = tools.safe_eval(data)
except Exception:
return {}
return info
def get_version(self, ids, name):
res = {}
for module in self.browse(ids):
res[module.id] = Module.get_module_info(
module.name).get('version', '')
res[module.id] = get_module_info(module.name).get('version', '')
return res
def get_parents(self, ids, name):
@@ -263,102 +241,38 @@ class Module(ModelSQL, ModelView):
# update the list of available packages
def update_list(self):
pool = Pool()
lang_obj = pool.get('ir.lang')
res = 0
with Transaction().set_context(language=False):
lang_ids = lang_obj.search([
('translatable', '=', True),
])
lang_codes = [x.code for x in lang_obj.browse(lang_ids)]
count = 0
module_names = get_module_list()
module_names = get_module_list()
module_ids = self.search([])
modules = self.browse(module_ids)
name2module = dict((m.name, m) for m in modules)
module_ids = self.search([])
modules = self.browse(module_ids)
name2module = {}
for module in modules:
name2module.setdefault(module.name, {})
name2module[module.name]['en_US'] = module
for code in lang_codes:
with Transaction().set_context(language=code):
modules = self.browse(module_ids)
for module in modules:
name2module[module.name][code] = module
# iterate through installed modules and mark them as being so
for name in module_names:
if name in name2module:
module = name2module[name]
tryton = get_module_info(name)
self._update_dependencies(module, tryton.get('depends', []))
continue
# iterate through installed modules and mark them as being so
for name in module_names:
mod_name = name
if mod_name in name2module.keys():
mod = name2module[mod_name]['en_US']
tryton = Module.get_module_info(mod_name)
if mod.description != tryton.get('description',
'').decode('utf-8', 'ignore') \
or mod.shortdesc != tryton.get('name',
'').decode('utf-8', 'ignore') \
or mod.author != tryton.get('author',
'').decode('utf-8', 'ignore') \
or mod.website != tryton.get('website',
'').decode('utf-8', 'ignore'):
self.write(mod.id, {
'description': tryton.get('description', ''),
'shortdesc': tryton.get('name', ''),
'author': tryton.get('author', ''),
'website': tryton.get('website', ''),
})
for code in lang_codes:
mod2 = name2module[mod_name][code]
if mod2.description != \
tryton.get('description_' + code,
tryton.get('description', '')
).decode('utf-8', 'ignore') \
or mod2.shortdesc != \
tryton.get('name_' + code,
tryton.get('name', '')
).decode('utf-8', 'ignore'):
with Transaction().set_context(language=code):
self.write(mod.id, {
'description': tryton.get(
'description_' + code, ''),
'shortdesc': tryton.get(
'name_' + code, ''),
})
self._update_dependencies(mod, tryton.get('depends', []))
continue
tryton = Module.get_module_info(mod_name)
if not tryton:
continue
new_id = self.create({
'name': mod_name,
tryton = get_module_info(name)
if not tryton:
continue
module_id = self.create({
'name': name,
'state': 'uninstalled',
'description': tryton.get('description', ''),
'shortdesc': tryton.get('name', ''),
'author': tryton.get('author', 'Unknown'),
'website': tryton.get('website', ''),
})
for code in lang_codes:
with Transaction().set_context(language=code):
self.write(new_id, {
'description': tryton.get(
'description_' + code, ''),
'shortdesc': tryton.get('name_' + code, ''),
})
res += 1
name2module.setdefault(mod_name, {})
name2module[mod_name]['en_US'] = self.browse(new_id)
self._update_dependencies(name2module[mod_name]['en_US'],
tryton.get('depends', []))
return res
})
count += 1
module = self.browse(module_id)
self._update_dependencies(module, tryton.get('depends', []))
return count
def _update_dependencies(self, module, depends=None):
pool = Pool()
dependency_obj = pool.get('ir.module.module.dependency')
dependency_obj.delete([x.id for x in module.dependencies
if x.name not in depends])
if x.name not in depends])
if depends is None:
depends = []
# Restart Browse Cache for deleted dependencies
@@ -367,9 +281,9 @@ class Module(ModelSQL, ModelView):
for depend in depends:
if depend not in dependency_names:
dependency_obj.create({
'module': module.id,
'name': depend,
})
'module': module.id,
'name': depend,
})
Module()
+5 -23
View File
@@ -12,23 +12,9 @@ this repository contains the full copyright notices and license terms. -->
<form string="Module" on_write="on_write">
<label name="name"/>
<field name="name"/>
<label name="shortdesc"/>
<field name="shortdesc"/>
<notebook colspan="4">
<page string="Module" id="module">
<separator name="description" colspan="4"/>
<field name="description" colspan="4"/>
<label name="version"/>
<field name="version"/>
<label name="author"/>
<field name="author"/>
<label name="website"/>
<field name="website" widget="url"/>
</page>
<page string="Dependencies" col="1" id="dependencies">
<field name="dependencies"/>
</page>
</notebook>
<label name="version"/>
<field name="version"/>
<field name="dependencies" colspan="4"/>
<label name="state"/>
<field name="state" readonly="1"/>
<group col="2" colspan="2" id="button">
@@ -56,13 +42,9 @@ this repository contains the full copyright notices and license terms. -->
<![CDATA[
<tree string="Modules" on_write="on_write"
colors="If(In(Eval('state', ''), ['to upgrade', 'to install']), 'blue', If(Equal(Eval('state', ''), 'uninstalled'), 'grey', 'black'))">
<field name="name"/>
<field name="shortdesc"/>
<field name="author"/>
<field name="name" expand="1"/>
<field name="version"/>
<field name="website"/>
<field name="state"/>
<field name="description" tree_invisible="1"/>
<button string="Mark for Upgrade" name="upgrade"
type="object"/>
<button string="Mark for Installation" name="install"
@@ -121,7 +103,7 @@ this repository contains the full copyright notices and license terms. -->
<![CDATA[
<tree string="Dependencies">
<field name="module"/>
<field name="name"/>
<field name="name" expand="1"/>
<field name="state"/>
</tree>
]]>
+19
View File
@@ -0,0 +1,19 @@
[tryton]
xml:
ir.xml
ui/ui.xml
ui/icon.xml
ui/menu.xml
ui/view.xml
action.xml
model.xml
sequence.xml
attachment.xml
cron.xml
lang.xml
translation.xml
export.xml
rule.xml
property.xml
module/module.xml
trigger.xml
+29 -29
View File
@@ -8,6 +8,9 @@ import contextlib
from functools import reduce
import imp
import operator
import ConfigParser
from glob import iglob
import trytond.tools as tools
from trytond.config import CONFIG
from trytond.transaction import Transaction
@@ -125,35 +128,32 @@ class Node(Singleton):
return res
def get_module_info(name):
"Return the content of the tryton.cfg"
config = ConfigParser.ConfigParser()
with tools.file_open(os.path.join(name, 'tryton.cfg')) as fp:
config.readfp(fp)
directory = os.path.dirname(fp.name)
info = dict(config.items('tryton'))
info['directory'] = directory
for key in ('depends', 'extras_depend', 'xml'):
if key in info:
info[key] = info[key].strip().splitlines()
return info
def create_graph(module_list):
graph = Graph()
packages = []
for module in module_list:
tryton_file = OPJ(MODULES_PATH, module, '__tryton__.py')
mod_path = OPJ(MODULES_PATH, module)
if module in ('ir', 'res', 'webdav', 'test'):
root_path = os.path.abspath(os.path.dirname(
os.path.dirname(__file__)))
tryton_file = OPJ(root_path, module, '__tryton__.py')
mod_path = OPJ(root_path, module)
elif module in EGG_MODULES:
ep = EGG_MODULES[module]
tryton_file = OPJ(ep.dist.location, 'trytond', 'modules', module,
'__tryton__.py')
mod_path = OPJ(ep.dist.location, 'trytond', 'modules', module)
if not os.path.isfile(tryton_file) or not os.path.isdir(mod_path):
# When testing modules from setuptools location is the module
# directory
tryton_file = OPJ(ep.dist.location, '__tryton__.py')
mod_path = os.path.dirname(ep.dist.location)
if os.path.isfile(tryton_file):
with tools.file_open(tryton_file, subdir='') as fp:
info = tools.safe_eval(fp.read())
packages.append((module, info.get('depends', []),
info.get('extras_depend', []), info))
elif module != 'all':
raise Exception('Module %s not found' % module)
try:
info = get_module_info(module)
except IOError:
if module != 'all':
raise Exception('Module %s not found' % module)
packages.append((module, info.get('depends', []),
info.get('extras_depend', []), info))
current, later = set([x[0] for x in packages]), set()
all_packages = set(current)
@@ -242,16 +242,16 @@ def load_module_graph(graph, pool, lang=None):
modules_todo.append((module, list(tryton_parser.to_delete)))
for filename in package.info.get('translation', []):
for filename in iglob('%s/%s/*.po'
% (package.info['directory'], 'locale')):
filename = filename.replace('/', os.sep)
lang2 = os.path.splitext(os.path.basename(filename))[0]
if lang2 not in lang:
continue
logger.info('%s:loading %s' % (module, filename))
with tools.file_open(OPJ(module, filename)) as trans_file:
po_path = trans_file.name
logger.info('%s:loading %s' % (module,
filename[len(package.info['directory']) + 1:]))
translation_obj = pool.get('ir.translation')
translation_obj.translation_import(lang2, module, po_path)
translation_obj.translation_import(lang2, module, filename)
cursor.execute("UPDATE ir_module_module SET state = 'installed' " \
"WHERE name = %s", (package.name,))
-64
View File
@@ -1,64 +0,0 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
{
'name': 'Res',
'name_bg_BG': 'Ресурс',
'name_ca_ES': 'Recursos interns',
'name_de_DE': 'Benutzerverwaltung',
'name_es_AR': 'Gestión de usuarios',
'name_es_ES': 'Recursos internos',
'name_fr_FR': 'Ressource',
'name_nl_NL': 'Interne handelingen',
'name_ru_RU': 'Базовые ресурсы сервера',
'description': '''Basic module handling internal tasks of the application.
Provides concepts and administration of users and internal communication.
''',
'description_bg_BG': '''Основен модул управляващ вътрешните задачи на приложението
- Предоставя идеи и администрация на потребители и вътрешна комуникация
''',
'description_ca_ES': '''Mòdul bàsic que gestiona tasques internes de l'aplicació.
Proporciona els conceptes i administració d'usuaris i comunicació interna.
''',
'description_de_DE': '''Basismodul für interne Aufgaben der Anwendung
- Stellt Konzept und Administration für die Benutzerverwaltung und interne Kommunikation zur Verfügung
''',
'description_es_AR': '''Módulo básico que gestiona tareas internas de la aplicación.
- Provee los conceptos y administración de usuarios y comunicación interna.
''',
'description_es_ES': '''Módulo básico que gestiona tareas internas de la aplicación.
Proporciona los conceptos y administración de usuarios y comunicación interna.
''',
'description_fr_FR': '''Module de base gérant les tâches internes de l'application.
Fournit les concepts et l'administration des utilisateurs et de la communication interne.
''',
'description_nl_NL': '''Basis module voor de afhandeling van interne taken.
Regelt instellingen en beheer van gebruikers en interne communicatie.
''',
'description_ru_RU': '''Базовый модуль обработки внутренних задач приложения.
Обеспечивает концепции и администрирование пользователей и внутренней связи.
''',
'active': True,
'depends': ['ir'],
'xml': [
'res.xml',
'group.xml',
'user.xml',
'request.xml',
'ir.xml',
],
'translation': [
'locale/cs_CZ.po',
'locale/bg_BG.po',
'locale/ca_ES.po',
'locale/fr_FR.po',
'locale/de_DE.po',
'locale/es_AR.po',
'locale/es_ES.po',
'locale/es_CO.po',
'locale/nl_NL.po',
'locale/ru_RU.po',
],
}
+9
View File
@@ -0,0 +1,9 @@
[tryton]
depends:
ir
xml:
res.xml
group.xml
user.xml
request.xml
ir.xml
-17
View File
@@ -1,17 +0,0 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
{
'name': 'Test',
'description': '''A module for unittest.
''',
'active': True,
'depends': ['ir', 'res'],
'xml': [
'import_data.xml',
'sequence.xml',
'workflow.xml',
'wizard.xml',
],
'translation': [
],
}
+9
View File
@@ -0,0 +1,9 @@
[tryton]
depends:
ir
res
xml:
import_data.xml
sequence.xml
workflow.xml
wizard.xml
-51
View File
@@ -1,51 +0,0 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
{
'name': 'WebDAV',
'name_bg_BG': 'WebDAV',
'name_ca_ES': 'WebDAV',
'name_de_DE': 'WebDAV',
'name_es_AR': 'WebDAV',
'name_es_ES': 'WebDAV',
'name_fr_FR': 'WebDAV',
'name_nl_NL': 'WebDAV',
'name_ru_RU': 'WebDAV',
'description': '''Basic module providing concept and administration of integrated WebDAV features.
''',
'description_bg_BG': '''Общ модул предоставящ представа и администрация на интегрирани WebDAV услуги.
''',
'description_ca_ES': '''Mòdul bàsic que proporciona el concepte i l'administració de serveis WebDAV integrats.
''',
'description_de_DE': '''Basismodul für Konzept und Administration der integrierten WebDAV-Komponente
''',
'description_es_AR': '''Módulo básico que provee el concepto y la administración de servicios WebDAV integrados.
''',
'description_es_ES': '''Módulo básico que proporciona el concepto y la administración de servicios WebDAV integrados.
''',
'description_fr_FR': '''Module de base fournissant les concepts et l'administration des fonctionnalités integrées de WebDAV.
''',
'description_nl_NL': '''Basismodule voor het instellen en beheren van de geïntegreerde WebDAV functionaliteit
''',
'description_ru_RU': '''Базовый модуль обеспечения и управления встроенными функциями WebDAV.
''',
'active': True,
'depends': [
'ir',
'res',
],
'xml': [
'webdav.xml',
],
'translation': [
'locale/cs_CZ.po',
'locale/bg_BG.po',
'locale/ca_ES.po',
'locale/fr_FR.po',
'locale/de_DE.po',
'locale/es_AR.po',
'locale/es_ES.po',
'locale/es_CO.po',
'locale/nl_NL.po',
'locale/ru_RU.po',
],
}
+6
View File
@@ -0,0 +1,6 @@
[tryton]
depends:
ir
res
xml:
webdav.xml