Refactore configuration to allow easy extention
issue3627 review7401002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Refactor configuration file and command line
|
||||
* Use the context of the relation field for instanciation
|
||||
* Use a configuration field for logging
|
||||
* Add translated descriptor for Selection field
|
||||
|
||||
@@ -8,7 +8,6 @@ include doc/*
|
||||
recursive-include doc *.rst
|
||||
recursive-include doc *.po
|
||||
recursive-include doc *.pot
|
||||
include etc/*
|
||||
include trytond/backend/*/init.sql
|
||||
include trytond/ir/tryton.cfg
|
||||
include trytond/ir/*.xml
|
||||
|
||||
+15
-48
@@ -21,72 +21,39 @@ def parse_commandline():
|
||||
|
||||
parser.add_argument('--version', action='version',
|
||||
version='%(prog)s ' + VERSION)
|
||||
parser.add_argument("-c", "--config", dest="config",
|
||||
parser.add_argument("-c", "--config", dest="configfile",
|
||||
help="specify config file")
|
||||
parser.add_argument('--debug', dest='debug_mode', action='store_true',
|
||||
help='enable debug mode (start post-mortem debugger if exceptions'
|
||||
' occur)')
|
||||
parser.add_argument('--debug', dest='debug', action='store_true',
|
||||
help='enable debug mode')
|
||||
parser.add_argument("-v", "--verbose", action="store_true",
|
||||
dest="verbose", help="enable verbose mode")
|
||||
|
||||
parser.add_argument("-d", "--database", dest="db_name",
|
||||
help="specify the database name")
|
||||
parser.add_argument("-i", "--init", dest="init",
|
||||
parser.add_argument("-d", "--database", dest="database_names", nargs='+',
|
||||
default=[], help="specify the database name")
|
||||
parser.add_argument("-i", "--init", dest="init", nargs='+', default=[],
|
||||
help="init a module (use \"all\" for all modules)")
|
||||
parser.add_argument("-u", "--update", dest="update",
|
||||
parser.add_argument("-u", "--update", dest="update", nargs='+', default=[],
|
||||
help="update a module (use \"all\" for all modules)")
|
||||
|
||||
parser.add_argument("--pidfile", dest="pidfile",
|
||||
help="file where the server pid will be stored")
|
||||
parser.add_argument("--logconf", dest="logconf",
|
||||
help="logging configuration file (ConfigParser format)")
|
||||
parser.add_argument("--disable-cron", dest="cron",
|
||||
action="store_false", help="disable cron")
|
||||
parser.add_argument("--cron", dest="cron", action="store_true",
|
||||
help="enable cron")
|
||||
|
||||
parser.epilog = ('The first time a database is initialized with "-i" admin'
|
||||
' password is read from file defined by TRYTONPASSFILE '
|
||||
'environment variable or interactively ask user. '
|
||||
'environment variable or interactively ask user.\n'
|
||||
'The config file can be specified in the TRYTOND_CONFIG '
|
||||
'environment variable.\n'
|
||||
'The database URI can be specified in the TRYTOND_DATABASE_URI '
|
||||
'environment variable.')
|
||||
|
||||
opt = parser.parse_args()
|
||||
|
||||
if opt.config:
|
||||
options['configfile'] = opt.config
|
||||
else:
|
||||
# No config file speficified, it will be guessed
|
||||
options['configfile'] = None
|
||||
|
||||
for arg in (
|
||||
'verbose',
|
||||
'debug_mode',
|
||||
'pidfile',
|
||||
'logconf',
|
||||
'cron',
|
||||
):
|
||||
if getattr(opt, arg) is not None:
|
||||
options[arg] = getattr(opt, arg)
|
||||
|
||||
db_name = []
|
||||
if opt.db_name:
|
||||
for i in opt.db_name.split(','):
|
||||
db_name.append(i)
|
||||
options['db_name'] = db_name
|
||||
|
||||
init = {}
|
||||
if opt.init:
|
||||
for i in opt.init.split(','):
|
||||
if i != 'test':
|
||||
init[i] = 1
|
||||
options['init'] = init
|
||||
|
||||
update = {}
|
||||
if opt.update:
|
||||
for i in opt.update.split(','):
|
||||
if i != 'test':
|
||||
update[i] = 1
|
||||
options['update'] = update
|
||||
options = parser.parse_args()
|
||||
|
||||
if not options.database_names and bool(options.init or options.update):
|
||||
parser.error('Missing database option')
|
||||
return options
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ First steps
|
||||
|
||||
* **Installation:**
|
||||
:ref:`Installation <topics-install>`
|
||||
:ref:`Configuration <topics-configuration>`
|
||||
|
||||
The model layer
|
||||
===============
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
.. _topics-configuration:
|
||||
|
||||
=============================
|
||||
Configuration file for Tryton
|
||||
=============================
|
||||
|
||||
The configuration file control some aspects of the behavior of Tryton.
|
||||
The file uses a simple ini-file format. It consists of sections, led by a
|
||||
`[section]` header and followed by `name = value` entries:
|
||||
|
||||
[database]
|
||||
uri = postgresql://user:password@localhost/
|
||||
path = /var/lib/trytond
|
||||
|
||||
For more information see ConfigParser_.
|
||||
|
||||
.. _ConfigParser: http://docs.python.org/2/library/configparser.html
|
||||
|
||||
Sections
|
||||
========
|
||||
|
||||
This section describes the different main sections that may appear in a Tryton
|
||||
configuration file, the purpose of each section, its possible keys, and their
|
||||
possible values.
|
||||
Some modules could request the usage of other sections for which the guideline
|
||||
asks them to be named like their module.
|
||||
|
||||
jsonrpc
|
||||
-------
|
||||
|
||||
Defines the behavior of the JSON-RPC_ network interface.
|
||||
|
||||
listen
|
||||
~~~~~~
|
||||
|
||||
Defines a comma separated list of couple of host (or IP address) and port numer
|
||||
separeted by a colon to listen on.
|
||||
The default value is `localhost:8000`.
|
||||
|
||||
hostname
|
||||
~~~~~~~~
|
||||
|
||||
Defines the hostname for this network interface.
|
||||
|
||||
data
|
||||
~~~~
|
||||
|
||||
Defines the root path to retrieve data for `GET` request.
|
||||
|
||||
xmlrpc
|
||||
------
|
||||
|
||||
Defines the behavior of the XML-RPC_ network interface.
|
||||
|
||||
listen
|
||||
~~~~~~
|
||||
|
||||
Same as for `jsonrpc` except it have no default value.
|
||||
|
||||
webdav
|
||||
------
|
||||
|
||||
Define the behavior of the WebDAV_ network interface.
|
||||
|
||||
listen
|
||||
~~~~~~
|
||||
|
||||
Same as for `jsonrpc` except it have no default value.
|
||||
|
||||
database
|
||||
--------
|
||||
|
||||
Defines how database is managed.
|
||||
|
||||
uri
|
||||
~~~
|
||||
|
||||
Contains the URI to connect to the SQL database. The URI follows the RFC-3986_.
|
||||
The typical form is:
|
||||
|
||||
database://username:password@host:port/
|
||||
|
||||
The default available databases are:
|
||||
|
||||
PostgreSQL
|
||||
**********
|
||||
|
||||
`pyscopg2` supports two type of connections:
|
||||
|
||||
- TCP/IP connection: `postgresql://user:password@localhost:5432/`
|
||||
- Unix domain connection: `postgresql://username:password@/`
|
||||
|
||||
SQLite
|
||||
******
|
||||
|
||||
The only possible URI is: `sqlite://`
|
||||
|
||||
MySQL
|
||||
*****
|
||||
|
||||
Same as for PostgreSQL.
|
||||
|
||||
path
|
||||
~~~~
|
||||
|
||||
The directory where Tryton should store files and so the user running `trytond`
|
||||
must have write access on this directory.
|
||||
The default value is `/var/lib/trytond/`.
|
||||
|
||||
list
|
||||
~~~~
|
||||
|
||||
A boolean value (default: `True`) to list available databases.
|
||||
|
||||
retry
|
||||
~~~~~
|
||||
|
||||
The number of retries when a database operation error occurs during a request.
|
||||
|
||||
language
|
||||
~~~~~~~~
|
||||
|
||||
The main language (default: `en_US`) of the database that will be stored in the
|
||||
main table for translatable fields.
|
||||
|
||||
ssl
|
||||
---
|
||||
|
||||
Activates the SSL_ on all network protocol.
|
||||
|
||||
privatekey
|
||||
~~~~~~~~~~
|
||||
|
||||
The path to the private key.
|
||||
|
||||
certificate
|
||||
~~~~~~~~~~~
|
||||
|
||||
The path to the certificate.
|
||||
|
||||
email
|
||||
-----
|
||||
|
||||
uri
|
||||
~~~
|
||||
|
||||
The SMTP-URL_ to connect to the SMTP server which is extended to support SSL_
|
||||
and STARTTLS_.
|
||||
The available protocols are:
|
||||
|
||||
- `smtp`: simple SMTP
|
||||
- `smtp+tls`: SMTP with STARTTLS
|
||||
- `smtps`: SMTP with SSL
|
||||
|
||||
The default value is: `smtp://localhost:25`
|
||||
|
||||
from
|
||||
~~~~
|
||||
|
||||
Defines the default `From` address when Tryton send emails.
|
||||
|
||||
session
|
||||
-------
|
||||
|
||||
timeout
|
||||
~~~~~~~
|
||||
|
||||
The time in second before a session expires.
|
||||
|
||||
super_pwd
|
||||
~~~~~~~~~
|
||||
|
||||
Theserver password uses to authenticate database management from the client.
|
||||
It is encrypted using using the Unix `crypt(3)` routine.
|
||||
Such password can be generated using this command line::
|
||||
|
||||
python -c 'import getpass,crypt,random,string; print crypt.crypt(getpass.getpass(), "".join(random.sample(string.ascii_letters + string.digits, 8)))'
|
||||
|
||||
report
|
||||
------
|
||||
|
||||
unoconv
|
||||
~~~~~~~
|
||||
|
||||
The parameters for `unoconv`.
|
||||
|
||||
.. _JSON-RPC: http://en.wikipedia.org/wiki/JSON-RPC
|
||||
.. _XML-RPC: http://en.wikipedia.org/wiki/XML-RPC
|
||||
.. _WebDAV: http://en.wikipedia.org/wiki/WebDAV
|
||||
.. _RFC-3986: http://tools.ietf.org/html/rfc3986
|
||||
.. _SMTP-URL: http://tools.ietf.org/html/draft-earhart-url-smtp-00
|
||||
.. _SSL: http://en.wikipedia.org/wiki/Secure_Sockets_Layer
|
||||
.. _STARTTLS: http://en.wikipedia.org/wiki/STARTTLS
|
||||
@@ -10,6 +10,7 @@ Introduction to all the key parts of trytond:
|
||||
:maxdepth: 1
|
||||
|
||||
install
|
||||
configuration
|
||||
logs
|
||||
models/index
|
||||
models/fields_default_value
|
||||
|
||||
@@ -1,88 +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.
|
||||
[options]
|
||||
|
||||
# Activate the json-rpc protocol
|
||||
jsonrpc = localhost:8000
|
||||
#ssl_jsonrpc = False
|
||||
|
||||
# This is the hostname used when generating tryton URI
|
||||
#hostname_jsonrpc =
|
||||
|
||||
# Configure the path of json-rpc data
|
||||
#jsondata_path = /var/www/localhost/tryton
|
||||
|
||||
# Activate the xml-rpc protocol
|
||||
#xmlrpc = *:8069
|
||||
#ssl_xmlrpc = False
|
||||
|
||||
# Activate the webdav protocol
|
||||
#webdav = *:8080
|
||||
#ssl_webdav = False
|
||||
|
||||
# This is the hostname used when generating WebDAV URI
|
||||
#hostname_webdav =
|
||||
|
||||
# Configure the database type
|
||||
# allowed values are postgresql, sqlite, mysql
|
||||
#db_type = postgresql
|
||||
|
||||
# Configure the database connection
|
||||
## Note: Only databases owned by db_user will be displayed in the connection dialog
|
||||
## of the Tryton client. db_user must have create permission for new databases
|
||||
## to be able to use automatic database creation with the Tryton client.
|
||||
#db_host = False
|
||||
#db_port = False
|
||||
#db_user = False
|
||||
#db_password = False
|
||||
#db_minconn = 1
|
||||
#db_maxconn = 64
|
||||
|
||||
# Configure the postgresql path for the executable
|
||||
#pg_path = None
|
||||
|
||||
# Configure the Tryton server password
|
||||
#admin_passwd = admin
|
||||
|
||||
# Configure the path of the files for the pid and the logs
|
||||
#pidfile = False
|
||||
#logconf = False
|
||||
|
||||
#privatekey = server.pem
|
||||
#certificate = server.pem
|
||||
|
||||
# Configure the SMTP connection
|
||||
#smtp_server = localhost
|
||||
#smtp_port = 25
|
||||
#smtp_ssl = False
|
||||
#smtp_tls = False
|
||||
#smtp_password = False
|
||||
#smtp_user = False
|
||||
#smtp_default_from_email = False
|
||||
|
||||
# Configure the path to store attachments and sqlite database
|
||||
#data_path = /var/lib/trytond
|
||||
|
||||
# Allow to run more than one instance of trytond
|
||||
#multi_server = False
|
||||
|
||||
# Configure the session timeout (inactivity of the client in sec)
|
||||
#session_timeout = 600
|
||||
|
||||
# Enable auto-reload of modules if changed
|
||||
#auto_reload = True
|
||||
|
||||
# Prevent database listing
|
||||
#prevent_dblist = False
|
||||
|
||||
# Enable cron
|
||||
# cron = True
|
||||
|
||||
# unoconv connection
|
||||
#unoconv = pipe,name=trytond;urp;StarOffice.ComponentContext
|
||||
|
||||
# Number of retries on database operational error
|
||||
# retry = 5
|
||||
|
||||
# Default language code
|
||||
# language = en_US
|
||||
@@ -1,15 +1,20 @@
|
||||
#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 sys
|
||||
import urlparse
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
|
||||
__all__ = ['get']
|
||||
__all__ = ['name', 'get']
|
||||
|
||||
|
||||
def get(name):
|
||||
db_type = CONFIG['db_type']
|
||||
def name():
|
||||
return urlparse.urlparse(config.get('database', 'uri', '')).scheme
|
||||
|
||||
|
||||
def get(prop):
|
||||
db_type = name()
|
||||
modname = 'trytond.backend.%s' % db_type
|
||||
__import__(modname)
|
||||
module = sys.modules[modname]
|
||||
return getattr(module, name)
|
||||
return getattr(module, prop)
|
||||
|
||||
@@ -1,7 +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.
|
||||
from trytond.backend.database import DatabaseInterface, CursorInterface
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config, parse_uri
|
||||
import MySQLdb
|
||||
import MySQLdb.cursors
|
||||
import MySQLdb.converters
|
||||
@@ -91,14 +91,16 @@ class Database(DatabaseInterface):
|
||||
'charset': 'utf8',
|
||||
'conv': conv,
|
||||
}
|
||||
if CONFIG['db_host']:
|
||||
args['host'] = CONFIG['db_host']
|
||||
if CONFIG['db_port']:
|
||||
args['port'] = int(CONFIG['db_port'])
|
||||
if CONFIG['db_user']:
|
||||
args['user'] = CONFIG['db_user']
|
||||
if CONFIG['db_password']:
|
||||
args['passwd'] = CONFIG['db_password']
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
assert uri.scheme == 'mysql'
|
||||
if uri.hostname:
|
||||
args['host'] = uri.hostname
|
||||
if uri.port:
|
||||
args['port'] = uri.port
|
||||
if uri.username:
|
||||
args['user'] = uri.username
|
||||
if uri.password:
|
||||
args['passwd'] = uri.password
|
||||
conn = MySQLdb.connect(**args)
|
||||
cursor = Cursor(conn, self.database_name)
|
||||
cursor.execute('SET time_zone = `UTC`')
|
||||
@@ -120,20 +122,21 @@ class Database(DatabaseInterface):
|
||||
|
||||
@staticmethod
|
||||
def dump(database_name):
|
||||
from trytond.tools import exec_pg_command_pipe
|
||||
from trytond.tools import exec_command_pipe
|
||||
|
||||
cmd = ['mysqldump', '--no-create-db']
|
||||
if CONFIG['db_user']:
|
||||
cmd.append('--user=' + CONFIG['db_user'])
|
||||
if CONFIG['db_host']:
|
||||
cmd.append('--host=' + CONFIG['db_host'])
|
||||
if CONFIG['db_port']:
|
||||
cmd.append('--port=' + CONFIG['db_port'])
|
||||
if CONFIG['db_password']:
|
||||
cmd.append('--password=' + CONFIG['db_password'])
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
if uri.username:
|
||||
cmd.append('--user=' + uri.username)
|
||||
if uri.hostname:
|
||||
cmd.append('--host=' + uri.hostname)
|
||||
if uri.port:
|
||||
cmd.append('--port=' + uri.port)
|
||||
if uri.password:
|
||||
cmd.append('--password=' + uri.password)
|
||||
cmd.append(database_name)
|
||||
|
||||
pipe = exec_pg_command_pipe(*tuple(cmd))
|
||||
pipe = exec_command_pipe(*tuple(cmd))
|
||||
pipe.stdin.close()
|
||||
data = pipe.stdout.read()
|
||||
res = pipe.wait()
|
||||
@@ -143,7 +146,7 @@ class Database(DatabaseInterface):
|
||||
|
||||
@staticmethod
|
||||
def restore(database_name, data):
|
||||
from trytond.tools import exec_pg_command_pipe
|
||||
from trytond.tools import exec_command_pipe
|
||||
|
||||
database = Database().connect()
|
||||
cursor = database.cursor(autocommit=True)
|
||||
@@ -152,14 +155,15 @@ class Database(DatabaseInterface):
|
||||
cursor.close()
|
||||
|
||||
cmd = ['mysql']
|
||||
if CONFIG['db_user']:
|
||||
cmd.append('--user=' + CONFIG['db_user'])
|
||||
if CONFIG['db_host']:
|
||||
cmd.append('--host=' + CONFIG['db_host'])
|
||||
if CONFIG['db_port']:
|
||||
cmd.append('--port=' + CONFIG['db_port'])
|
||||
if CONFIG['db_password']:
|
||||
cmd.append('--password=' + CONFIG['db_password'])
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
if uri.username:
|
||||
cmd.append('--user=' + uri.username)
|
||||
if uri.hostname:
|
||||
cmd.append('--host=' + uri.hostname)
|
||||
if uri.port:
|
||||
cmd.append('--port=' + uri.port)
|
||||
if uri.password:
|
||||
cmd.append('--password=' + uri.password)
|
||||
cmd.append(database_name)
|
||||
|
||||
fd, file_name = tempfile.mkstemp()
|
||||
@@ -171,7 +175,7 @@ class Database(DatabaseInterface):
|
||||
|
||||
args2 = tuple(cmd)
|
||||
|
||||
pipe = exec_pg_command_pipe(*args2)
|
||||
pipe = exec_command_pipe(*args2)
|
||||
pipe.stdin.close()
|
||||
res = pipe.wait()
|
||||
os.remove(file_name)
|
||||
@@ -192,7 +196,7 @@ class Database(DatabaseInterface):
|
||||
@staticmethod
|
||||
def list(cursor):
|
||||
now = time.time()
|
||||
timeout = int(CONFIG['session_timeout'])
|
||||
timeout = config.getint('session', 'timeout')
|
||||
res = Database._list_cache
|
||||
if res and abs(Database._list_cache_timestamp - now) < timeout:
|
||||
return res
|
||||
|
||||
@@ -1,7 +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.
|
||||
from trytond.backend.database import DatabaseInterface, CursorInterface
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config, parse_uri
|
||||
from psycopg2.pool import ThreadedConnectionPool
|
||||
from psycopg2.extensions import cursor as PsycopgCursor
|
||||
from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
|
||||
@@ -54,14 +54,15 @@ class Database(DatabaseInterface):
|
||||
return self
|
||||
logger = logging.getLogger('database')
|
||||
logger.info('connect to "%s"' % self.database_name)
|
||||
host = CONFIG['db_host'] and "host=%s" % CONFIG['db_host'] or ''
|
||||
port = CONFIG['db_port'] and "port=%s" % CONFIG['db_port'] or ''
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
assert uri.scheme == 'postgresql'
|
||||
host = uri.hostname and "host=%s" % uri.hostname or ''
|
||||
port = uri.port and "port=%s" % uri.port or ''
|
||||
name = "dbname=%s" % self.database_name
|
||||
user = CONFIG['db_user'] and "user=%s" % CONFIG['db_user'] or ''
|
||||
password = (CONFIG['db_password']
|
||||
and "password=%s" % CONFIG['db_password'] or '')
|
||||
minconn = int(CONFIG['db_minconn']) or 1
|
||||
maxconn = int(CONFIG['db_maxconn']) or 64
|
||||
user = uri.username and "user=%s" % uri.username or ''
|
||||
password = uri.password and "password=%s" % uri.password or ''
|
||||
minconn = config.getint('database', 'minconn', 1)
|
||||
maxconn = config.getint('database', 'maxconn', 64)
|
||||
dsn = '%s %s %s %s %s' % (host, port, name, user, password)
|
||||
self._connpool = ThreadedConnectionPool(minconn, maxconn, dsn)
|
||||
return self
|
||||
@@ -106,18 +107,25 @@ class Database(DatabaseInterface):
|
||||
|
||||
@staticmethod
|
||||
def dump(database_name):
|
||||
from trytond.tools import exec_pg_command_pipe
|
||||
from trytond.tools import exec_command_pipe
|
||||
|
||||
cmd = ['pg_dump', '--format=c', '--no-owner']
|
||||
if CONFIG['db_user']:
|
||||
cmd.append('--username=' + CONFIG['db_user'])
|
||||
if CONFIG['db_host']:
|
||||
cmd.append('--host=' + CONFIG['db_host'])
|
||||
if CONFIG['db_port']:
|
||||
cmd.append('--port=' + CONFIG['db_port'])
|
||||
env = {}
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
if uri.username:
|
||||
cmd.append('--username=' + uri.username)
|
||||
if uri.hostname:
|
||||
cmd.append('--host=' + uri.hostname)
|
||||
if uri.port:
|
||||
cmd.append('--port=' + uri.port)
|
||||
if uri.password:
|
||||
# if db_password is set in configuration we should pass
|
||||
# an environment variable PGPASSWORD to our subprocess
|
||||
# see libpg documentation
|
||||
env['PGPASSWORD'] = uri.password
|
||||
cmd.append(database_name)
|
||||
|
||||
pipe = exec_pg_command_pipe(*tuple(cmd))
|
||||
pipe = exec_command_pipe(*tuple(cmd), env=env)
|
||||
pipe.stdin.close()
|
||||
data = pipe.stdout.read()
|
||||
res = pipe.wait()
|
||||
@@ -127,7 +135,7 @@ class Database(DatabaseInterface):
|
||||
|
||||
@staticmethod
|
||||
def restore(database_name, data):
|
||||
from trytond.tools import exec_pg_command_pipe
|
||||
from trytond.tools import exec_command_pipe
|
||||
|
||||
database = Database().connect()
|
||||
cursor = database.cursor(autocommit=True)
|
||||
@@ -136,12 +144,16 @@ class Database(DatabaseInterface):
|
||||
cursor.close()
|
||||
|
||||
cmd = ['pg_restore', '--no-owner']
|
||||
if CONFIG['db_user']:
|
||||
cmd.append('--username=' + CONFIG['db_user'])
|
||||
if CONFIG['db_host']:
|
||||
cmd.append('--host=' + CONFIG['db_host'])
|
||||
if CONFIG['db_port']:
|
||||
cmd.append('--port=' + CONFIG['db_port'])
|
||||
env = {}
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
if uri.username:
|
||||
cmd.append('--username=' + uri.username)
|
||||
if uri.hostname:
|
||||
cmd.append('--host=' + uri.hostname)
|
||||
if uri.port:
|
||||
cmd.append('--port=' + uri.port)
|
||||
if uri.password:
|
||||
env['PGPASSWORD'] = uri.password
|
||||
cmd.append('--dbname=' + database_name)
|
||||
args2 = tuple(cmd)
|
||||
|
||||
@@ -153,7 +165,7 @@ class Database(DatabaseInterface):
|
||||
args2.append(' ' + tmpfile)
|
||||
args2 = tuple(args2)
|
||||
|
||||
pipe = exec_pg_command_pipe(*args2)
|
||||
pipe = exec_command_pipe(*args2, env=env)
|
||||
if not os.name == "nt":
|
||||
pipe.stdin.write(data)
|
||||
pipe.stdin.close()
|
||||
@@ -175,23 +187,14 @@ class Database(DatabaseInterface):
|
||||
@staticmethod
|
||||
def list(cursor):
|
||||
now = time.time()
|
||||
timeout = int(CONFIG['session_timeout'])
|
||||
timeout = config.getint('session', 'timeout')
|
||||
res = Database._list_cache
|
||||
if res and abs(Database._list_cache_timestamp - now) < timeout:
|
||||
return res
|
||||
db_user = CONFIG['db_user']
|
||||
uri = parse_uri(config.get('database', 'uri'))
|
||||
db_user = uri.username
|
||||
if not db_user and os.name == 'posix':
|
||||
db_user = pwd.getpwuid(os.getuid())[0]
|
||||
if not db_user:
|
||||
cursor.execute("SELECT usename "
|
||||
"FROM pg_user "
|
||||
"WHERE usesysid = ("
|
||||
"SELECT datdba "
|
||||
"FROM pg_database "
|
||||
"WHERE datname = %s)",
|
||||
(CONFIG["db_name"],))
|
||||
res = cursor.fetchone()
|
||||
db_user = res and res[0]
|
||||
if db_user:
|
||||
cursor.execute("SELECT datname "
|
||||
"FROM pg_database "
|
||||
|
||||
@@ -1,7 +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.
|
||||
from trytond.backend.database import DatabaseInterface, CursorInterface
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
import os
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
@@ -174,7 +174,7 @@ class Database(DatabaseInterface):
|
||||
path = ':memory:'
|
||||
else:
|
||||
db_filename = self.database_name + '.sqlite'
|
||||
path = os.path.join(CONFIG['data_path'], db_filename)
|
||||
path = os.path.join(config.get('database', 'path'), db_filename)
|
||||
if not os.path.isfile(path):
|
||||
raise IOError('Database "%s" doesn\'t exist!' % db_filename)
|
||||
if self._conn is not None:
|
||||
@@ -216,7 +216,7 @@ class Database(DatabaseInterface):
|
||||
else:
|
||||
if os.sep in database_name:
|
||||
return
|
||||
path = os.path.join(CONFIG['data_path'],
|
||||
path = os.path.join(config.get('database', 'path'),
|
||||
database_name + '.sqlite')
|
||||
with sqlite.connect(path) as conn:
|
||||
cursor = conn.cursor()
|
||||
@@ -229,7 +229,7 @@ class Database(DatabaseInterface):
|
||||
return
|
||||
if os.sep in database_name:
|
||||
return
|
||||
os.remove(os.path.join(CONFIG['data_path'],
|
||||
os.remove(os.path.join(config.get('database', 'path'),
|
||||
database_name + '.sqlite'))
|
||||
|
||||
@staticmethod
|
||||
@@ -238,7 +238,7 @@ class Database(DatabaseInterface):
|
||||
raise Exception('Unable to dump memory database!')
|
||||
if os.sep in database_name:
|
||||
raise Exception('Wrong database name!')
|
||||
path = os.path.join(CONFIG['data_path'],
|
||||
path = os.path.join(config.get('database', 'path'),
|
||||
database_name + '.sqlite')
|
||||
with open(path, 'rb') as file_p:
|
||||
data = file_p.read()
|
||||
@@ -250,7 +250,7 @@ class Database(DatabaseInterface):
|
||||
raise Exception('Unable to restore memory database!')
|
||||
if os.sep in database_name:
|
||||
raise Exception('Wrong database name!')
|
||||
path = os.path.join(CONFIG['data_path'],
|
||||
path = os.path.join(config.get('database', 'path'),
|
||||
database_name + '.sqlite')
|
||||
if os.path.isfile(path):
|
||||
raise Exception('Database already exists!')
|
||||
@@ -262,7 +262,7 @@ class Database(DatabaseInterface):
|
||||
res = []
|
||||
listdir = [':memory:']
|
||||
try:
|
||||
listdir += os.listdir(CONFIG['data_path'])
|
||||
listdir += os.listdir(config.get('database', 'path'))
|
||||
except OSError:
|
||||
pass
|
||||
for db_file in listdir:
|
||||
|
||||
+17
-28
@@ -1,12 +1,12 @@
|
||||
#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 datetime
|
||||
from threading import Lock
|
||||
from collections import OrderedDict
|
||||
|
||||
from sql import Table
|
||||
from sql.functions import Now
|
||||
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.config import CONFIG
|
||||
from trytond import backend
|
||||
|
||||
__all__ = ['Cache', 'LRUDict']
|
||||
|
||||
@@ -74,18 +74,13 @@ class Cache(object):
|
||||
|
||||
@staticmethod
|
||||
def clean(dbname):
|
||||
if not CONFIG['multi_server']:
|
||||
return
|
||||
database = backend.get('Database')(dbname).connect()
|
||||
cursor = database.cursor()
|
||||
try:
|
||||
cursor.execute('SELECT "timestamp", "name" FROM ir_cache')
|
||||
with Transaction().new_cursor():
|
||||
cursor = Transaction().cursor
|
||||
table = Table('ir_cache')
|
||||
cursor.execute(*table.select(table.timestamp, table.name))
|
||||
timestamps = {}
|
||||
for timestamp, name in cursor.fetchall():
|
||||
timestamps[name] = timestamp
|
||||
finally:
|
||||
cursor.commit()
|
||||
cursor.close()
|
||||
for inst in Cache._cache_instance:
|
||||
if inst._name in timestamps:
|
||||
with inst._lock:
|
||||
@@ -96,36 +91,30 @@ class Cache(object):
|
||||
|
||||
@staticmethod
|
||||
def reset(dbname, name):
|
||||
if not CONFIG['multi_server']:
|
||||
return
|
||||
with Cache._resets_lock:
|
||||
Cache._resets.setdefault(dbname, set())
|
||||
Cache._resets[dbname].add(name)
|
||||
|
||||
@staticmethod
|
||||
def resets(dbname):
|
||||
if not CONFIG['multi_server']:
|
||||
return
|
||||
database = backend.get('Database')(dbname).connect()
|
||||
cursor = database.cursor()
|
||||
try:
|
||||
with Transaction().new_cursor():
|
||||
cursor = Transaction().cursor
|
||||
table = Table('ir_cache')
|
||||
with Cache._resets_lock:
|
||||
Cache._resets.setdefault(dbname, set())
|
||||
for name in Cache._resets[dbname]:
|
||||
cursor.execute('SELECT name FROM ir_cache WHERE name = %s',
|
||||
(name,))
|
||||
cursor.execute(*table.select(table.name,
|
||||
where=table.name == name))
|
||||
if cursor.fetchone():
|
||||
# It would be better to insert only
|
||||
cursor.execute('UPDATE ir_cache SET "timestamp" = %s '
|
||||
'WHERE name = %s', (datetime.datetime.now(), name))
|
||||
cursor.execute(*table.update([table.timestamp],
|
||||
[Now()], where=table.name == name))
|
||||
else:
|
||||
cursor.execute('INSERT INTO ir_cache '
|
||||
'("timestamp", "name") '
|
||||
'VALUES (%s, %s)', (datetime.datetime.now(), name))
|
||||
cursor.execute(*table.insert(
|
||||
[table.timestamp, table.name],
|
||||
[[Now(), name]]))
|
||||
Cache._resets[dbname].clear()
|
||||
finally:
|
||||
cursor.commit()
|
||||
cursor.close()
|
||||
|
||||
|
||||
class LRUDict(OrderedDict):
|
||||
|
||||
+65
-114
@@ -1,18 +1,11 @@
|
||||
#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 sys
|
||||
try:
|
||||
import cdecimal
|
||||
# Use cdecimal globally
|
||||
if 'decimal' not in sys.modules:
|
||||
sys.modules['decimal'] = cdecimal
|
||||
except ImportError:
|
||||
import decimal
|
||||
sys.modules['cdecimal'] = decimal
|
||||
import os
|
||||
import ConfigParser
|
||||
import getpass
|
||||
import socket
|
||||
import urlparse
|
||||
|
||||
__all__ = ['config', 'get_hostname', 'get_port', 'split_netloc',
|
||||
'parse_listen', 'parse_uri']
|
||||
|
||||
|
||||
def get_hostname(netloc):
|
||||
@@ -24,119 +17,77 @@ def get_hostname(netloc):
|
||||
return netloc
|
||||
|
||||
|
||||
def get_port(netloc, protocol):
|
||||
def get_port(netloc):
|
||||
netloc = netloc.split(']')[-1]
|
||||
if ':' in netloc:
|
||||
return int(netloc.split(':')[1])
|
||||
else:
|
||||
return {
|
||||
'jsonrpc': 8000,
|
||||
'xmlrpc': 8069,
|
||||
'webdav': 8080,
|
||||
}.get(protocol)
|
||||
return int(netloc.split(':')[1])
|
||||
|
||||
|
||||
class ConfigManager(object):
|
||||
def __init__(self, fname=None):
|
||||
self.options = {
|
||||
'jsonrpc': [('localhost', 8000)],
|
||||
'ssl_jsonrpc': False,
|
||||
'hostname_jsonrpc': None,
|
||||
'xmlrpc': [],
|
||||
'ssl_xmlrpc': False,
|
||||
'jsondata_path': '/var/www/localhost/tryton',
|
||||
'webdav': [],
|
||||
'ssl_webdav': False,
|
||||
'hostname_webdav': None,
|
||||
'db_type': 'postgresql',
|
||||
'db_host': False,
|
||||
'db_port': False,
|
||||
'db_name': False,
|
||||
'db_user': False,
|
||||
'db_password': False,
|
||||
'db_minconn': 1,
|
||||
'db_maxconn': 64,
|
||||
'pg_path': None,
|
||||
'admin_passwd': 'admin',
|
||||
'verbose': False,
|
||||
'debug_mode': False,
|
||||
'pidfile': None,
|
||||
'logconf': None,
|
||||
'privatekey': '/etc/ssl/trytond/server.key',
|
||||
'certificate': '/etc/ssl/trytond/server.pem',
|
||||
'smtp_server': 'localhost',
|
||||
'smtp_port': 25,
|
||||
'smtp_ssl': False,
|
||||
'smtp_tls': False,
|
||||
'smtp_user': False,
|
||||
'smtp_password': False,
|
||||
'smtp_default_from_email': '%s@%s' % (
|
||||
getpass.getuser(), socket.getfqdn()),
|
||||
'data_path': '/var/lib/trytond',
|
||||
'multi_server': False,
|
||||
'session_timeout': 600,
|
||||
'auto_reload': True,
|
||||
'prevent_dblist': False,
|
||||
'init': {},
|
||||
'update': {},
|
||||
'cron': True,
|
||||
'unoconv': 'pipe,name=trytond;urp;StarOffice.ComponentContext',
|
||||
'retry': 5,
|
||||
'language': 'en_US',
|
||||
}
|
||||
self.configfile = None
|
||||
def split_netloc(netloc):
|
||||
return get_hostname(netloc).replace('*', ''), get_port(netloc)
|
||||
|
||||
def update_cmdline(self, cmdline_options):
|
||||
self.options.update(cmdline_options)
|
||||
|
||||
# Verify that logging configuration is defined in an external file,
|
||||
# if not the output will go to stdout
|
||||
if self.options['logconf'] in ('None', 'False'):
|
||||
self.options['logconf'] = False
|
||||
# the same for the pidfile
|
||||
if self.options['pidfile'] in ('None', 'False'):
|
||||
self.options['pidfile'] = False
|
||||
if self.options['data_path'] in ('None', 'False'):
|
||||
self.options['data_path'] = False
|
||||
def parse_listen(value):
|
||||
for netloc in value.split(','):
|
||||
yield split_netloc(netloc)
|
||||
|
||||
def update_etc(self, configfile=None):
|
||||
if configfile is None:
|
||||
configfile = os.environ.get('TRYTOND_CONFIG')
|
||||
if not configfile:
|
||||
prefixdir = os.path.abspath(os.path.normpath(os.path.join(
|
||||
os.path.dirname(sys.prefix), '..')))
|
||||
configfile = os.path.join(prefixdir, 'etc', 'trytond.conf')
|
||||
if not os.path.isfile(configfile):
|
||||
configdir = os.path.abspath(os.path.normpath(os.path.join(
|
||||
os.path.dirname(__file__), '..')))
|
||||
configfile = os.path.join(configdir, 'etc', 'trytond.conf')
|
||||
if not os.path.isfile(configfile):
|
||||
configfile = None
|
||||
|
||||
self.configfile = configfile
|
||||
if not self.configfile:
|
||||
def parse_uri(uri):
|
||||
return urlparse.urlparse(uri)
|
||||
|
||||
|
||||
class TrytonConfigParser(ConfigParser.RawConfigParser):
|
||||
|
||||
def __init__(self):
|
||||
ConfigParser.RawConfigParser.__init__(self)
|
||||
self.add_section('jsonrpc')
|
||||
self.set('jsonrpc', 'listen', 'localhost:8000')
|
||||
self.set('jsonrpc', 'data', '/var/www/localhost/tryton')
|
||||
self.add_section('xmlrpc')
|
||||
self.add_section('webdav')
|
||||
self.add_section('database')
|
||||
self.set('database', 'uri',
|
||||
os.environ.get('TRYTOND_DATABASE_URI', 'sqlite://'))
|
||||
self.set('database', 'path', '/var/lib/trytond')
|
||||
self.set('database', 'list', 'True')
|
||||
self.set('database', 'retry', 5)
|
||||
self.set('database', 'language', 'en_US')
|
||||
self.add_section('ssl')
|
||||
self.add_section('email')
|
||||
self.set('email', 'uri', 'smtp://localhost:25')
|
||||
self.add_section('session')
|
||||
self.set('session', 'timeout', 600)
|
||||
self.add_section('report')
|
||||
self.set('report', 'unoconv',
|
||||
'pipe,name=trytond;urp;StarOffice.ComponentContext')
|
||||
|
||||
def update_etc(self, configfile=os.environ.get('TRYTOND_CONFIG')):
|
||||
if not configfile:
|
||||
return
|
||||
self.read(configfile)
|
||||
|
||||
parser = ConfigParser.ConfigParser()
|
||||
with open(self.configfile) as fp:
|
||||
parser.readfp(fp)
|
||||
for (name, value) in parser.items('options'):
|
||||
if value == 'True' or value == 'true':
|
||||
value = True
|
||||
if value == 'False' or value == 'false':
|
||||
value = False
|
||||
if name in ('xmlrpc', 'jsonrpc', 'webdav') and value:
|
||||
value = [(get_hostname(netloc).replace('*', ''),
|
||||
get_port(netloc, name)) for netloc in value.split(',')]
|
||||
self.options[name] = value
|
||||
def get(self, section, option, default=None):
|
||||
try:
|
||||
return ConfigParser.RawConfigParser.get(self, section, option)
|
||||
except ConfigParser.NoOptionError:
|
||||
return default
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self.options.get(key, default)
|
||||
def getint(self, section, option, default=None):
|
||||
try:
|
||||
return ConfigParser.RawConfigParser.getint(self, section, option)
|
||||
except (ConfigParser.NoOptionError, TypeError):
|
||||
return default
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.options[key] = value
|
||||
def getfloat(self, section, option, default=None):
|
||||
try:
|
||||
return ConfigParser.RawConfigParser.getfloat(self, section, option)
|
||||
except (ConfigParser.NoOptionError, TypeError):
|
||||
return default
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.options[key]
|
||||
def getboolean(self, section, option, default=None):
|
||||
try:
|
||||
return ConfigParser.RawConfigParser.getboolean(
|
||||
self, section, option)
|
||||
except ConfigParser.NoOptionError:
|
||||
return default
|
||||
|
||||
CONFIG = ConfigManager()
|
||||
config = TrytonConfigParser()
|
||||
|
||||
@@ -5,7 +5,7 @@ import hashlib
|
||||
from sql.operators import Concat
|
||||
|
||||
from ..model import ModelView, ModelSQL, fields
|
||||
from ..config import CONFIG
|
||||
from ..config import config
|
||||
from .. import backend
|
||||
from ..transaction import Transaction
|
||||
from ..pyson import Eval
|
||||
@@ -117,7 +117,7 @@ class Attachment(ModelSQL, ModelView):
|
||||
filename = self.digest
|
||||
if self.collision:
|
||||
filename = filename + '-' + str(self.collision)
|
||||
filename = os.path.join(CONFIG['data_path'], db_name,
|
||||
filename = os.path.join(config.get('database', 'path'), db_name,
|
||||
filename[0:2], filename[2:4], filename)
|
||||
if name == 'data_size' or format_ == 'size':
|
||||
try:
|
||||
@@ -140,7 +140,7 @@ class Attachment(ModelSQL, ModelView):
|
||||
cursor = Transaction().cursor
|
||||
table = cls.__table__()
|
||||
db_name = cursor.dbname
|
||||
directory = os.path.join(CONFIG['data_path'], db_name)
|
||||
directory = os.path.join(config.get('database', 'path'), db_name)
|
||||
if not os.path.isdir(directory):
|
||||
os.makedirs(directory, 0770)
|
||||
digest = hashlib.md5(value).hexdigest()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from ..model import ModelSQL, ModelSingleton, fields
|
||||
from ..cache import Cache
|
||||
from ..config import CONFIG
|
||||
from ..config import config
|
||||
|
||||
__all__ = ['Configuration']
|
||||
|
||||
@@ -15,7 +15,7 @@ class Configuration(ModelSingleton, ModelSQL):
|
||||
|
||||
@staticmethod
|
||||
def default_language():
|
||||
return CONFIG['language']
|
||||
return config.get('database', 'language')
|
||||
|
||||
@classmethod
|
||||
def get_language(cls):
|
||||
@@ -25,6 +25,6 @@ class Configuration(ModelSingleton, ModelSQL):
|
||||
config = cls(1)
|
||||
language = config.language
|
||||
if not language:
|
||||
language = CONFIG['language']
|
||||
language = config.get('database', 'language')
|
||||
cls._get_language_cache.set(None, language)
|
||||
return language
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ from ..tools import safe_eval, get_smtp_server
|
||||
from ..transaction import Transaction
|
||||
from ..pool import Pool
|
||||
from .. import backend
|
||||
from ..config import CONFIG
|
||||
from ..config import config
|
||||
|
||||
__all__ = [
|
||||
'Cron',
|
||||
@@ -132,7 +132,7 @@ class Cron(ModelSQL, ModelView):
|
||||
(cron.name, cron.__url__, tb_s),
|
||||
raise_exception=False)
|
||||
|
||||
from_addr = CONFIG['smtp_default_from_email']
|
||||
from_addr = config.get('email', 'from')
|
||||
to_addr = cron.request_user.email
|
||||
|
||||
msg = MIMEText(body, _charset='utf-8')
|
||||
|
||||
@@ -509,13 +509,14 @@ class ModuleInstallUpgrade(Wizard):
|
||||
modules = Module.search([
|
||||
('state', 'in', ['to upgrade', 'to remove', 'to install']),
|
||||
])
|
||||
update = [m.name for m in modules]
|
||||
langs = Lang.search([
|
||||
('translatable', '=', True),
|
||||
])
|
||||
lang = [x.code for x in langs]
|
||||
transaction.cursor.commit()
|
||||
if modules:
|
||||
pool.init(update=True, lang=lang)
|
||||
if update:
|
||||
pool.init(update=update, lang=lang)
|
||||
return 'done'
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@ from ..tools import datetime_strftime
|
||||
from ..pyson import Eval, And
|
||||
from ..transaction import Transaction
|
||||
from ..pool import Pool
|
||||
from ..config import CONFIG
|
||||
from .. import backend
|
||||
|
||||
__all__ = [
|
||||
'SequenceType', 'Sequence', 'SequenceStrict',
|
||||
]
|
||||
|
||||
sql_sequence = CONFIG.options['db_type'] == 'postgresql'
|
||||
sql_sequence = backend.name() == 'postgresql'
|
||||
|
||||
|
||||
class SequenceType(ModelSQL, ModelView):
|
||||
|
||||
@@ -8,7 +8,7 @@ import uuid
|
||||
import datetime
|
||||
|
||||
from trytond.model import ModelSQL, fields
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from .. import backend
|
||||
from ..transaction import Transaction
|
||||
|
||||
@@ -45,7 +45,8 @@ class Session(ModelSQL):
|
||||
def check(cls, user, key):
|
||||
"Check user key and delete old one"
|
||||
now = datetime.datetime.now()
|
||||
timeout = datetime.timedelta(seconds=int(CONFIG['session_timeout']))
|
||||
timeout = datetime.timedelta(
|
||||
seconds=config.getint('session', 'timeout'))
|
||||
sessions = cls.search([
|
||||
('create_uid', '=', user),
|
||||
])
|
||||
|
||||
@@ -4,7 +4,7 @@ from sql import Query, Expression
|
||||
|
||||
from .field import Field, SQLType
|
||||
from ...transaction import Transaction
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
|
||||
|
||||
class Binary(Field):
|
||||
@@ -59,14 +59,14 @@ class Binary(Field):
|
||||
def sql_format(value):
|
||||
if isinstance(value, (Query, Expression)):
|
||||
return value
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql' and value is not None:
|
||||
import psycopg2
|
||||
return psycopg2.Binary(value)
|
||||
return value
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql':
|
||||
return SQLType('BYTEA', 'BYTEA')
|
||||
elif db_type == 'mysql':
|
||||
|
||||
@@ -4,7 +4,7 @@ import warnings
|
||||
|
||||
from sql import Query, Expression
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import Field, FieldTranslate, size_validate, SQLType
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class Char(FieldTranslate):
|
||||
return value
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if self.size and db_type != 'sqlite':
|
||||
return SQLType('VARCHAR', 'VARCHAR(%s)' % self.size)
|
||||
elif db_type == 'mysql':
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import datetime
|
||||
from sql import Query, Expression
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import Field, SQLType
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class DateTime(Field):
|
||||
return value.replace(microsecond=0)
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'sqlite':
|
||||
return SQLType('TIMESTAMP', 'TIMESTAMP')
|
||||
elif db_type == 'mysql':
|
||||
@@ -106,7 +106,7 @@ class Timestamp(Field):
|
||||
return value
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'sqlite':
|
||||
return SQLType('TIMESTAMP', 'TIMESTAMP')
|
||||
elif db_type == 'mysql':
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from sql import Query, Expression
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import Field, SQLType
|
||||
from ...pyson import PYSON
|
||||
|
||||
@@ -59,7 +59,7 @@ class Float(Field):
|
||||
return float(value)
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql':
|
||||
return SQLType('FLOAT8', 'FLOAT8')
|
||||
elif db_type == 'mysql':
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from sql import Query, Expression
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import Field, SQLType
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class Integer(Field):
|
||||
_type = 'integer'
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql':
|
||||
return SQLType('INT4', 'INT4')
|
||||
elif db_type == 'mysql':
|
||||
@@ -22,7 +22,7 @@ class Integer(Field):
|
||||
return SQLType('INTEGER', 'INTEGER')
|
||||
|
||||
def sql_format(self, value):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if (db_type == 'sqlite'
|
||||
and value is not None
|
||||
and not isinstance(value, (Query, Expression))):
|
||||
@@ -37,7 +37,7 @@ class BigInteger(Integer):
|
||||
_type = 'biginteger'
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql':
|
||||
return SQLType('INT8', 'INT8')
|
||||
return super(BigInteger, self).sql_type()
|
||||
|
||||
@@ -6,7 +6,7 @@ from sql.operators import Or
|
||||
|
||||
from .field import Field, SQLType
|
||||
from ...pool import Pool
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from ...tools import reduce_ids
|
||||
from ...transaction import Transaction
|
||||
|
||||
@@ -86,7 +86,7 @@ class Many2One(Field):
|
||||
return int(value)
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'postgresql':
|
||||
return SQLType('INT4', 'INT4')
|
||||
elif db_type == 'mysql':
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from decimal import Decimal
|
||||
from sql import Query, Expression, Cast, Literal, Select, CombiningQuery
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import SQLType
|
||||
from .float import Float
|
||||
|
||||
@@ -26,14 +26,14 @@ class Numeric(Float):
|
||||
return value
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'mysql':
|
||||
return SQLType('DECIMAL', 'DECIMAL(65, 30)')
|
||||
return SQLType('NUMERIC', 'NUMERIC')
|
||||
|
||||
def sql_column(self, table):
|
||||
column = super(Numeric, self).sql_column(table)
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'sqlite':
|
||||
# Must be casted as Decimal is stored as bytes
|
||||
column = Cast(column, self.sql_type().base)
|
||||
@@ -41,7 +41,7 @@ class Numeric(Float):
|
||||
|
||||
def _domain_value(self, operator, value):
|
||||
value = super(Numeric, self)._domain_value(operator, value)
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'sqlite':
|
||||
if isinstance(value, (Select, CombiningQuery)):
|
||||
return value
|
||||
|
||||
@@ -8,7 +8,7 @@ from .field import Field, SQLType
|
||||
from .char import Char
|
||||
from ...transaction import Transaction
|
||||
from ...pool import Pool
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
|
||||
|
||||
class Reference(Field):
|
||||
@@ -109,7 +109,7 @@ class Reference(Field):
|
||||
return Char.sql_format(value)
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'mysql':
|
||||
return SQLType('CHAR', 'VARCHAR(255)')
|
||||
return SQLType('VARCHAR', 'VARCHAR')
|
||||
|
||||
@@ -4,7 +4,7 @@ import warnings
|
||||
|
||||
from sql.conditionals import Case
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import Field, SQLType
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class Selection(Field):
|
||||
__init__.__doc__ += Field.__init__.__doc__
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'mysql':
|
||||
return SQLType('CHAR', 'VARCHAR(255)')
|
||||
return SQLType('VARCHAR', 'VARCHAR')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import hashlib
|
||||
from sql import Query, Expression
|
||||
|
||||
from ...config import CONFIG
|
||||
from ... import backend
|
||||
from .field import SQLType
|
||||
from .char import Char
|
||||
|
||||
@@ -22,7 +22,7 @@ class Sha(Char):
|
||||
return super(Sha, self).sql_format(value)
|
||||
|
||||
def sql_type(self):
|
||||
db_type = CONFIG['db_type']
|
||||
db_type = backend.name()
|
||||
if db_type == 'mysql':
|
||||
return SQLType('CHAR', 'VARCHAR(40)')
|
||||
return SQLType('VARCHAR', 'VARCHAR(40)')
|
||||
|
||||
@@ -24,7 +24,7 @@ from trytond.const import OPERATORS, RECORD_CACHE_SIZE, BROWSE_FIELD_TRESHOLD
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
from trytond.cache import LRUDict, freeze
|
||||
from trytond.config import CONFIG
|
||||
from trytond import backend
|
||||
from trytond.rpc import RPC
|
||||
from .modelview import ModelView
|
||||
|
||||
@@ -1018,7 +1018,7 @@ class ModelStorage(Model):
|
||||
if (value.quantize(Decimal(str(10.0 ** -digits[1])))
|
||||
!= value):
|
||||
raise_user_error(value)
|
||||
elif CONFIG.options['db_type'] != 'mysql':
|
||||
elif backend.name() != 'mysql':
|
||||
if not (round(value, digits[1]) == float(value)):
|
||||
raise_user_error(value)
|
||||
# validate digits
|
||||
|
||||
+17
-23
@@ -14,7 +14,7 @@ from sql import Table
|
||||
from sql.functions import Now
|
||||
|
||||
import trytond.tools as tools
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.cache import Cache
|
||||
import trytond.convert as convert
|
||||
@@ -135,11 +135,11 @@ class Node(Singleton):
|
||||
|
||||
def get_module_info(name):
|
||||
"Return the content of the tryton.cfg"
|
||||
config = ConfigParser.ConfigParser()
|
||||
module_config = ConfigParser.ConfigParser()
|
||||
with tools.file_open(os.path.join(name, 'tryton.cfg')) as fp:
|
||||
config.readfp(fp)
|
||||
module_config.readfp(fp)
|
||||
directory = os.path.dirname(fp.name)
|
||||
info = dict(config.items('tryton'))
|
||||
info = dict(module_config.items('tryton'))
|
||||
info['directory'] = directory
|
||||
for key in ('depends', 'extras_depend', 'xml'):
|
||||
if key in info:
|
||||
@@ -193,18 +193,17 @@ def create_graph(module_list):
|
||||
return graph, packages, later
|
||||
|
||||
|
||||
def is_module_to_install(module):
|
||||
for kind in ('init', 'update'):
|
||||
if 'all' in CONFIG[kind] and module != 'tests':
|
||||
return True
|
||||
elif module in CONFIG[kind]:
|
||||
return True
|
||||
def is_module_to_install(module, update):
|
||||
if 'all' in update and module != 'tests':
|
||||
return True
|
||||
elif module in update:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def load_module_graph(graph, pool, lang=None):
|
||||
def load_module_graph(graph, pool, update=None, lang=None):
|
||||
if lang is None:
|
||||
lang = [CONFIG['language']]
|
||||
lang = [config.get('database', 'language')]
|
||||
modules_todo = []
|
||||
models_to_update_history = set()
|
||||
logger = logging.getLogger('modules')
|
||||
@@ -222,7 +221,7 @@ def load_module_graph(graph, pool, lang=None):
|
||||
logger.info(module)
|
||||
classes = pool.setup(module)
|
||||
package_state = module2state.get(module, 'uninstalled')
|
||||
if (is_module_to_install(module)
|
||||
if (is_module_to_install(module, update)
|
||||
or package_state in ('to install', 'to upgrade')):
|
||||
if package_state not in ('to install', 'to upgrade'):
|
||||
if package_state == 'installed':
|
||||
@@ -362,7 +361,7 @@ def register_classes():
|
||||
MODULES.append(module)
|
||||
|
||||
|
||||
def load_modules(database_name, pool, update=False, lang=None):
|
||||
def load_modules(database_name, pool, update=None, lang=None):
|
||||
res = True
|
||||
|
||||
def _load_modules():
|
||||
@@ -372,7 +371,7 @@ def load_modules(database_name, pool, update=False, lang=None):
|
||||
# Migration from 2.2: workflow module removed
|
||||
cursor.execute(*ir_module.delete(
|
||||
where=(ir_module.name == 'workflow')))
|
||||
if 'all' in CONFIG['init']:
|
||||
if 'all' in update:
|
||||
cursor.execute(*ir_module.select(ir_module.name,
|
||||
where=(ir_module.name != 'tests')))
|
||||
else:
|
||||
@@ -385,16 +384,11 @@ def load_modules(database_name, pool, update=False, lang=None):
|
||||
'to remove'))))
|
||||
module_list = [name for (name,) in cursor.fetchall()]
|
||||
if update:
|
||||
for module in CONFIG['init'].keys():
|
||||
if CONFIG['init'][module]:
|
||||
module_list.append(module)
|
||||
for module in CONFIG['update'].keys():
|
||||
if CONFIG['update'][module]:
|
||||
module_list.append(module)
|
||||
module_list += update
|
||||
graph = create_graph(module_list)[0]
|
||||
|
||||
try:
|
||||
load_module_graph(graph, pool, lang)
|
||||
load_module_graph(graph, pool, update, lang)
|
||||
except Exception:
|
||||
cursor.rollback()
|
||||
raise
|
||||
@@ -423,6 +417,7 @@ def load_modules(database_name, pool, update=False, lang=None):
|
||||
Module = pool.get('ir.module.module')
|
||||
Module.update_list()
|
||||
cursor.commit()
|
||||
Cache.resets(database_name)
|
||||
|
||||
if not Transaction().cursor:
|
||||
with Transaction().start(database_name, 0):
|
||||
@@ -433,5 +428,4 @@ def load_modules(database_name, pool, update=False, lang=None):
|
||||
Transaction().reset_context():
|
||||
_load_modules()
|
||||
|
||||
Cache.resets(database_name)
|
||||
return res
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ class Pool(object):
|
||||
'''
|
||||
return self._locks[self.database_name]
|
||||
|
||||
def init(self, update=False, lang=None):
|
||||
def init(self, update=None, lang=None):
|
||||
'''
|
||||
Init pool
|
||||
Set update to proceed to update
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#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 traceback
|
||||
import logging
|
||||
import time
|
||||
import sys
|
||||
import pydoc
|
||||
|
||||
from sql import Table, Flavor
|
||||
from sql import Table
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond import security
|
||||
from trytond import backend
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.version import VERSION
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.cache import Cache
|
||||
@@ -20,6 +19,7 @@ from trytond.exceptions import UserError, UserWarning, NotLogged, \
|
||||
ConcurrencyException
|
||||
from trytond.rpc import RPC
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ir_configuration = Table('ir_configuration')
|
||||
ir_lang = Table('ir_lang')
|
||||
@@ -40,12 +40,13 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
except Exception:
|
||||
return False
|
||||
res = security.login(database_name, user, session)
|
||||
Cache.clean(database_name)
|
||||
with Transaction().start(database_name, 0):
|
||||
Cache.clean(database_name)
|
||||
Cache.resets(database_name)
|
||||
logger = logging.getLogger('dispatcher')
|
||||
msg = res and 'successful login' or 'bad login or password'
|
||||
logger.info('%s \'%s\' from %s:%d using %s on database \'%s\''
|
||||
% (msg, user, host, port, protocol, database_name))
|
||||
Cache.resets(database_name)
|
||||
return res or False
|
||||
elif method == 'logout':
|
||||
name = security.logout(database_name, user, session)
|
||||
@@ -81,7 +82,7 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
except Exception:
|
||||
return False
|
||||
elif method == 'list':
|
||||
if CONFIG['prevent_dblist']:
|
||||
if config.get('database', 'list'):
|
||||
raise Exception('AccessDenied')
|
||||
with Transaction().start(None, 0, close=True) as transaction:
|
||||
return transaction.database.list(transaction.cursor)
|
||||
@@ -121,7 +122,7 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
obj = pool.get(object_name, type=object_type)
|
||||
return pydoc.getdoc(getattr(obj, method))
|
||||
|
||||
for count in range(int(CONFIG['retry']), -1, -1):
|
||||
for count in range(config.getint('database', 'retry'), -1, -1):
|
||||
try:
|
||||
user = security.check(database_name, user, session)
|
||||
except DatabaseOperationalError:
|
||||
@@ -130,7 +131,6 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
raise
|
||||
break
|
||||
|
||||
Cache.clean(database_name)
|
||||
database_list = Pool.database_list()
|
||||
pool = Pool(database_name)
|
||||
if not database_name in database_list:
|
||||
@@ -147,9 +147,13 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
raise UserError('Calling method %s on %s %s is not allowed!'
|
||||
% (method, object_type, object_name))
|
||||
|
||||
for count in range(int(CONFIG['retry']), -1, -1):
|
||||
exception_message = ('Exception calling %s.%s.%s from %s@%s:%d/%s' %
|
||||
(object_type, object_name, method, user, host, port, database_name))
|
||||
|
||||
for count in range(config.getint('database', 'retry'), -1, -1):
|
||||
with Transaction().start(database_name, user,
|
||||
readonly=rpc.readonly) as transaction:
|
||||
Cache.clean(database_name)
|
||||
try:
|
||||
c_args, c_kwargs, transaction.context, transaction.timestamp \
|
||||
= rpc.convert(obj, *args, **kwargs)
|
||||
@@ -166,23 +170,20 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
for i in inst]
|
||||
if not rpc.readonly:
|
||||
transaction.cursor.commit()
|
||||
except DatabaseOperationalError, exception:
|
||||
except DatabaseOperationalError:
|
||||
transaction.cursor.rollback()
|
||||
if count and not rpc.readonly:
|
||||
continue
|
||||
raise
|
||||
except Exception, exception:
|
||||
if CONFIG['verbose'] and not isinstance(exception, (
|
||||
NotLogged, ConcurrencyException, UserError,
|
||||
UserWarning)):
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
logger = logging.getLogger('dispatcher')
|
||||
logger.error('Exception calling method %s on '
|
||||
'%s %s from %s@%s:%d/%s:\n'
|
||||
% (method, object_type, object_name, user, host, port,
|
||||
database_name) + tb_s)
|
||||
except (NotLogged, ConcurrencyException, UserError, UserWarning):
|
||||
logger.debug(exception_message, exc_info=sys.exc_info())
|
||||
transaction.cursor.rollback()
|
||||
raise
|
||||
except Exception:
|
||||
logger.error(exception_message, exc_info=sys.exc_info())
|
||||
transaction.cursor.rollback()
|
||||
raise
|
||||
Cache.resets(database_name)
|
||||
with Transaction().start(database_name, 0) as transaction:
|
||||
pool = Pool(database_name)
|
||||
Session = pool.get('ir.session')
|
||||
@@ -193,7 +194,6 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
|
||||
transaction.cursor.rollback()
|
||||
else:
|
||||
transaction.cursor.commit()
|
||||
Cache.resets(database_name)
|
||||
return result
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ def create(database_name, password, lang, admin_password):
|
||||
transaction.cursor.commit()
|
||||
|
||||
pool = Pool(database_name)
|
||||
pool.init(update=True, lang=[lang])
|
||||
pool.init(update=['res', 'ir'], lang=[lang])
|
||||
with Transaction().start(database_name, 0) as transaction:
|
||||
User = pool.get('res.user')
|
||||
Lang = pool.get('ir.lang')
|
||||
@@ -246,9 +246,8 @@ def create(database_name, password, lang, admin_password):
|
||||
transaction.cursor.commit()
|
||||
res = True
|
||||
except Exception:
|
||||
logger.error('CREATE DB: %s failed' % (database_name,))
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
logger.error('Exception in call: \n' + tb_s)
|
||||
logger.error('CREATE DB: %s failed' % database_name,
|
||||
exc_info=sys.exc_info())
|
||||
raise
|
||||
else:
|
||||
logger.info('CREATE DB: %s' % (database_name,))
|
||||
@@ -270,9 +269,8 @@ def drop(database_name, password):
|
||||
Database.drop(cursor, database_name)
|
||||
cursor.commit()
|
||||
except Exception:
|
||||
logger.error('DROP DB: %s failed' % (database_name,))
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
logger.error('Exception in call: \n' + tb_s)
|
||||
logger.error('DROP DB: %s failed' % database_name,
|
||||
exc_info=sys.exc_info())
|
||||
raise
|
||||
else:
|
||||
logger.info('DROP DB: %s' % (database_name))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.protocols.sslsocket import SSLSocket
|
||||
from trytond.protocols.dispatcher import dispatch
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.protocols.common import daemon, RegisterHandlerMixin
|
||||
from trytond.exceptions import UserError, UserWarning, NotLogged, \
|
||||
ConcurrencyException
|
||||
@@ -157,10 +157,6 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
for path in sys.path:
|
||||
tb_s = tb_s.replace(path, '')
|
||||
if CONFIG['debug_mode']:
|
||||
import pdb
|
||||
traceb = sys.exc_info()[2]
|
||||
pdb.post_mortem(traceb)
|
||||
# report exception back to server
|
||||
response['error'] = (str(sys.exc_value), tb_s)
|
||||
|
||||
@@ -229,7 +225,7 @@ class SimpleJSONRPCRequestHandler(RegisterHandlerMixin,
|
||||
path = posixpath.normpath(urllib.unquote(path))
|
||||
words = path.split('/')
|
||||
words = filter(None, words)
|
||||
path = CONFIG['jsondata_path']
|
||||
path = config.get('jsonrpc', 'data')
|
||||
for word in words:
|
||||
drive, word = os.path.splitdrive(word)
|
||||
head, word = os.path.split(word)
|
||||
@@ -247,7 +243,8 @@ class SimpleJSONRPCRequestHandler(RegisterHandlerMixin,
|
||||
|
||||
def send_tryton_url(self, path):
|
||||
self.send_response(300)
|
||||
hostname = CONFIG['hostname'] or unicode(socket.getfqdn(), 'utf8')
|
||||
hostname = (config.get('jsonrpc', 'hostname')
|
||||
or unicode(socket.getfqdn(), 'utf8'))
|
||||
hostname = '.'.join(encodings.idna.ToASCII(part) for part in
|
||||
hostname.split('.'))
|
||||
values = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
|
||||
|
||||
def SSLSocket(socket):
|
||||
@@ -8,6 +8,6 @@ def SSLSocket(socket):
|
||||
import ssl
|
||||
return ssl.wrap_socket(socket,
|
||||
server_side=True,
|
||||
certfile=CONFIG['certificate'],
|
||||
keyfile=CONFIG['privatekey'],
|
||||
certfile=config.get('ssl', 'certificate'),
|
||||
keyfile=config.get('ssl', 'privatekey'),
|
||||
ssl_version=ssl.PROTOCOL_SSLv23)
|
||||
|
||||
@@ -7,7 +7,6 @@ import urlparse
|
||||
import time
|
||||
import urllib
|
||||
import sys
|
||||
import traceback
|
||||
import logging
|
||||
from threading import local
|
||||
import xml.dom.minidom
|
||||
@@ -21,7 +20,6 @@ from pywebdav.lib.davcmd import copyone, copytree, moveone, movetree, \
|
||||
delone, deltree
|
||||
from trytond.protocols.sslsocket import SSLSocket
|
||||
from trytond.protocols.common import daemon
|
||||
from trytond.config import CONFIG
|
||||
from trytond.security import login
|
||||
from trytond.version import PACKAGE, VERSION, WEBSITE
|
||||
from trytond.tools.misc import LocalDict
|
||||
@@ -36,6 +34,8 @@ domimpl = xml.dom.minidom.getDOMImplementation()
|
||||
DAV_VERSION_1['version'] += ',access-control'
|
||||
DAV_VERSION_2['version'] += ',access-control'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Local int for multi-thread
|
||||
class LocalInt(local):
|
||||
@@ -131,12 +131,12 @@ class TrytonDAVInterface(iface.dav_interface):
|
||||
self.verbose = False
|
||||
|
||||
def _log_exception(self, exception):
|
||||
if CONFIG['verbose'] and not isinstance(exception, (
|
||||
NotLogged, ConcurrencyException, UserError, UserWarning,
|
||||
DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden)):
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
logger = logging.getLogger('webdav')
|
||||
logger.error('Exception:\n' + tb_s)
|
||||
if isinstance(exception, (NotLogged, ConcurrencyException, UserError,
|
||||
UserWarning, DAV_Error, DAV_NotFound, DAV_Secret,
|
||||
DAV_Forbidden)):
|
||||
logger.debug('Exception', exc_info=sys.exc_info())
|
||||
else:
|
||||
logger.error('Exception', exc_info=sys.exc_info())
|
||||
|
||||
@staticmethod
|
||||
def get_dburi(uri):
|
||||
|
||||
+11
-15
@@ -2,7 +2,6 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.protocols.sslsocket import SSLSocket
|
||||
from trytond.protocols.dispatcher import dispatch
|
||||
from trytond.config import CONFIG
|
||||
from trytond.protocols.common import daemon, RegisterHandlerMixin
|
||||
from trytond.exceptions import UserError, UserWarning, NotLogged, \
|
||||
ConcurrencyException
|
||||
@@ -10,16 +9,18 @@ from trytond import security
|
||||
import SimpleXMLRPCServer
|
||||
import SocketServer
|
||||
import xmlrpclib
|
||||
import traceback
|
||||
import socket
|
||||
import sys
|
||||
import base64
|
||||
import datetime
|
||||
from types import DictType
|
||||
import logging
|
||||
|
||||
# convert decimal to float before marshalling:
|
||||
from decimal import Decimal
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def dump_decimal(self, value, write):
|
||||
value = {'__class__': 'Decimal',
|
||||
@@ -133,6 +134,7 @@ class GenericXMLRPCRequestHandler:
|
||||
database_name = self.path[1:]
|
||||
user = self.tryton['user']
|
||||
session = self.tryton['session']
|
||||
exception_message = 'Exception calling %s%s' % (method, params)
|
||||
try:
|
||||
try:
|
||||
method_list = method.split('.')
|
||||
@@ -150,21 +152,15 @@ class GenericXMLRPCRequestHandler:
|
||||
return dispatch(host, port, 'XML-RPC', database_name, user,
|
||||
session, object_type, object_name, method, *params)
|
||||
except (NotLogged, ConcurrencyException), exception:
|
||||
raise xmlrpclib.Fault(exception.code,
|
||||
'\n'.join(exception.args))
|
||||
logger.debug(exception_message, exc_info=sys.exc_info())
|
||||
raise xmlrpclib.Fault(exception.code, str(exception))
|
||||
except (UserError, UserWarning), exception:
|
||||
logger.debug(exception_message, exc_info=sys.exc_info())
|
||||
error, description = exception.args
|
||||
raise xmlrpclib.Fault(exception.code,
|
||||
'\n'.join((error,) + description))
|
||||
except Exception:
|
||||
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
|
||||
for path in sys.path:
|
||||
tb_s = tb_s.replace(path, '')
|
||||
if CONFIG['debug_mode']:
|
||||
import pdb
|
||||
traceb = sys.exc_info()[2]
|
||||
pdb.post_mortem(traceb)
|
||||
raise xmlrpclib.Fault(255, str(sys.exc_value) + '\n' + tb_s)
|
||||
raise xmlrpclib.Fault(exception.code, str(exception))
|
||||
except Exception, exception:
|
||||
logger.error(exception_message, exc_info=sys.exc_info())
|
||||
raise xmlrpclib.Fault(255, str(exception))
|
||||
finally:
|
||||
security.logout(database_name, user, session)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ except ImportError:
|
||||
Manifest, MANIFEST = None, None
|
||||
from genshi.filters import Translator
|
||||
import lxml.etree
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.pool import Pool, PoolBase
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.url import URLMixin
|
||||
@@ -295,7 +295,7 @@ class Report(URLMixin, PoolBase):
|
||||
oext = FORMAT2EXT.get(output_format, output_format)
|
||||
with os.fdopen(fd, 'wb+') as fp:
|
||||
fp.write(data)
|
||||
cmd = ['unoconv', '--connection=%s' % CONFIG['unoconv'],
|
||||
cmd = ['unoconv', '--connection=%s' % config.get('report', 'unoconv'),
|
||||
'-f', oext, '--stdout', path]
|
||||
try:
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
|
||||
+4
-3
@@ -26,7 +26,7 @@ from .. import backend
|
||||
from ..transaction import Transaction
|
||||
from ..cache import Cache
|
||||
from ..pool import Pool
|
||||
from ..config import CONFIG
|
||||
from ..config import config
|
||||
from ..pyson import PYSONEncoder
|
||||
from ..rpc import RPC
|
||||
|
||||
@@ -197,7 +197,8 @@ class User(ModelSQL, ModelView):
|
||||
def get_sessions(users, name):
|
||||
Session = Pool().get('ir.session')
|
||||
now = datetime.datetime.now()
|
||||
timeout = datetime.timedelta(seconds=int(CONFIG['session_timeout']))
|
||||
timeout = datetime.timedelta(
|
||||
seconds=config.getint('session', 'timeout'))
|
||||
result = dict((u.id, 0) for u in users)
|
||||
for sub_ids in grouped_slice(users):
|
||||
with Transaction().set_user(0):
|
||||
@@ -553,7 +554,7 @@ class LoginAttempt(ModelSQL):
|
||||
@staticmethod
|
||||
def delay():
|
||||
return (datetime.datetime.now()
|
||||
- datetime.timedelta(seconds=int(CONFIG['session_timeout'])))
|
||||
- datetime.timedelta(seconds=config.getint('session', 'timeout')))
|
||||
|
||||
@classmethod
|
||||
def add(cls, login):
|
||||
|
||||
+10
-4
@@ -1,7 +1,13 @@
|
||||
#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
|
||||
try:
|
||||
import crypt
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.exceptions import NotLogged
|
||||
|
||||
@@ -48,10 +54,10 @@ def logout(dbname, user, session):
|
||||
|
||||
|
||||
def check_super(passwd):
|
||||
if passwd == CONFIG['admin_passwd']:
|
||||
cryptedpasswd = config.get('session', 'super_pwd')
|
||||
if cryptedpasswd and crypt.crypt(passwd, cryptedpasswd) == cryptedpasswd:
|
||||
return True
|
||||
else:
|
||||
raise Exception('AccessDenied')
|
||||
raise Exception('AccessDenied')
|
||||
|
||||
|
||||
def check(dbname, user, session):
|
||||
|
||||
+35
-44
@@ -13,7 +13,7 @@ import time
|
||||
from getpass import getpass
|
||||
import threading
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config, parse_listen
|
||||
from trytond import backend
|
||||
from trytond.pool import Pool
|
||||
from trytond.monitor import monitor
|
||||
@@ -24,13 +24,12 @@ class TrytonServer(object):
|
||||
|
||||
def __init__(self, options):
|
||||
|
||||
CONFIG.update_etc(options['configfile'])
|
||||
CONFIG.update_cmdline(options)
|
||||
config.update_etc(options.configfile)
|
||||
|
||||
if CONFIG['logconf']:
|
||||
logging.config.fileConfig(CONFIG['logconf'])
|
||||
if options.logconf:
|
||||
logging.config.fileConfig(options.logconf)
|
||||
logging.getLogger('server').info('using %s as logging '
|
||||
'configuration file', CONFIG['logconf'])
|
||||
'configuration file', options.logconf)
|
||||
else:
|
||||
logformat = '[%(asctime)s] %(levelname)s:%(name)s:%(message)s'
|
||||
datefmt = '%a %b %d %H:%M:%S %Y'
|
||||
@@ -39,19 +38,20 @@ class TrytonServer(object):
|
||||
|
||||
self.logger = logging.getLogger('server')
|
||||
|
||||
if CONFIG.configfile:
|
||||
if options.configfile:
|
||||
self.logger.info('using %s as configuration file'
|
||||
% CONFIG.configfile)
|
||||
% options.configfile)
|
||||
else:
|
||||
self.logger.info('using default configuration')
|
||||
self.logger.info('initialising distributed objects services')
|
||||
self.xmlrpcd = []
|
||||
self.jsonrpcd = []
|
||||
self.webdavd = []
|
||||
self.options = options
|
||||
|
||||
def run(self):
|
||||
"Run the server and never return"
|
||||
update = bool(CONFIG['init'] or CONFIG['update'])
|
||||
update = self.options.init + self.options.update
|
||||
init = {}
|
||||
|
||||
signal.signal(signal.SIGINT, lambda *a: self.stop())
|
||||
@@ -61,22 +61,18 @@ class TrytonServer(object):
|
||||
if hasattr(signal, 'SIGUSR1'):
|
||||
signal.signal(signal.SIGUSR1, lambda *a: self.restart())
|
||||
|
||||
if CONFIG['pidfile']:
|
||||
with open(CONFIG['pidfile'], 'w') as fd_pid:
|
||||
if self.options.pidfile:
|
||||
with open(self.options.pidfile, 'w') as fd_pid:
|
||||
fd_pid.write("%d" % (os.getpid()))
|
||||
|
||||
if not CONFIG["db_name"] \
|
||||
and bool(CONFIG['init'] or CONFIG['update']):
|
||||
raise Exception('Missing database option!')
|
||||
|
||||
if not update:
|
||||
self.start_servers()
|
||||
|
||||
for db_name in CONFIG["db_name"]:
|
||||
for db_name in self.options.database_names:
|
||||
init[db_name] = False
|
||||
with Transaction().start(db_name, 0) as transaction:
|
||||
cursor = transaction.cursor
|
||||
if CONFIG['init']:
|
||||
if self.options.init:
|
||||
if not cursor.test():
|
||||
self.logger.info("init db")
|
||||
backend.get('Database').init(cursor)
|
||||
@@ -85,7 +81,7 @@ class TrytonServer(object):
|
||||
elif not cursor.test():
|
||||
raise Exception("'%s' is not a Tryton database!" % db_name)
|
||||
|
||||
for db_name in CONFIG["db_name"]:
|
||||
for db_name in self.options.database_names:
|
||||
if update:
|
||||
with Transaction().start(db_name, 0) as transaction:
|
||||
cursor = transaction.cursor
|
||||
@@ -99,10 +95,7 @@ class TrytonServer(object):
|
||||
lang = None
|
||||
Pool(db_name).init(update=update, lang=lang)
|
||||
|
||||
for kind in ('init', 'update'):
|
||||
CONFIG[kind] = {}
|
||||
|
||||
for db_name in CONFIG['db_name']:
|
||||
for db_name in self.options.database_names:
|
||||
if init[db_name]:
|
||||
# try to read password from environment variable
|
||||
# TRYTONPASSFILE, empty TRYTONPASSFILE ignored
|
||||
@@ -145,7 +138,7 @@ class TrytonServer(object):
|
||||
|
||||
threads = {}
|
||||
while True:
|
||||
if CONFIG['cron']:
|
||||
if self.options.cron:
|
||||
for dbname in Pool.database_list():
|
||||
thread = threads.get(dbname)
|
||||
if thread and thread.is_alive():
|
||||
@@ -164,7 +157,7 @@ class TrytonServer(object):
|
||||
args=(dbname,), kwargs={})
|
||||
thread.start()
|
||||
threads[dbname] = thread
|
||||
if CONFIG['auto_reload']:
|
||||
if self.options.debug:
|
||||
for _ in range(60):
|
||||
if monitor():
|
||||
self.restart()
|
||||
@@ -173,33 +166,31 @@ class TrytonServer(object):
|
||||
time.sleep(60)
|
||||
|
||||
def start_servers(self):
|
||||
ssl = config.get('ssl', 'privatekey')
|
||||
# Launch Server
|
||||
if CONFIG['jsonrpc']:
|
||||
if config.get('jsonrpc', 'listen'):
|
||||
from trytond.protocols.jsonrpc import JSONRPCDaemon
|
||||
for hostname, port in CONFIG['jsonrpc']:
|
||||
self.jsonrpcd.append(JSONRPCDaemon(hostname, port,
|
||||
CONFIG['ssl_jsonrpc']))
|
||||
for hostname, port in parse_listen(
|
||||
config.get('jsonrpc', 'listen')):
|
||||
self.jsonrpcd.append(JSONRPCDaemon(hostname, port, ssl))
|
||||
self.logger.info("starting JSON-RPC%s protocol on %s:%d" %
|
||||
(CONFIG['ssl_jsonrpc'] and ' SSL' or '', hostname or '*',
|
||||
port))
|
||||
(ssl and ' SSL' or '', hostname or '*', port))
|
||||
|
||||
if CONFIG['xmlrpc']:
|
||||
if config.get('xmlrpc', 'listen'):
|
||||
from trytond.protocols.xmlrpc import XMLRPCDaemon
|
||||
for hostname, port in CONFIG['xmlrpc']:
|
||||
self.xmlrpcd.append(XMLRPCDaemon(hostname, port,
|
||||
CONFIG['ssl_xmlrpc']))
|
||||
for hostname, port in parse_listen(
|
||||
config.get('xmlrpc', 'listen')):
|
||||
self.xmlrpcd.append(XMLRPCDaemon(hostname, port, ssl))
|
||||
self.logger.info("starting XML-RPC%s protocol on %s:%d" %
|
||||
(CONFIG['ssl_xmlrpc'] and ' SSL' or '', hostname or '*',
|
||||
port))
|
||||
(ssl and ' SSL' or '', hostname or '*', port))
|
||||
|
||||
if CONFIG['webdav']:
|
||||
if config.get('webdav', 'listen'):
|
||||
from trytond.protocols.webdav import WebDAVServerThread
|
||||
for hostname, port in CONFIG['webdav']:
|
||||
self.webdavd.append(WebDAVServerThread(hostname, port,
|
||||
CONFIG['ssl_webdav']))
|
||||
for hostname, port in parse_listen(
|
||||
config.get('webdav', 'listen')):
|
||||
self.webdavd.append(WebDAVServerThread(hostname, port, ssl))
|
||||
self.logger.info("starting WebDAV%s protocol on %s:%d" %
|
||||
(CONFIG['ssl_webdav'] and ' SSL' or '', hostname or '*',
|
||||
port))
|
||||
(ssl and ' SSL' or '', hostname or '*', port))
|
||||
|
||||
for servers in (self.xmlrpcd, self.jsonrpcd, self.webdavd):
|
||||
for server in servers:
|
||||
@@ -211,8 +202,8 @@ class TrytonServer(object):
|
||||
server.stop()
|
||||
server.join()
|
||||
if exit:
|
||||
if CONFIG['pidfile']:
|
||||
os.unlink(CONFIG['pidfile'])
|
||||
if self.options.pidfile:
|
||||
os.unlink(self.options.pidfile)
|
||||
logging.getLogger('server').info('stopped')
|
||||
logging.shutdown()
|
||||
sys.exit(0)
|
||||
|
||||
@@ -8,7 +8,8 @@ import time
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond import backend
|
||||
|
||||
if __name__ != '__main__':
|
||||
raise ImportError('%s can not be imported' % __name__)
|
||||
@@ -22,18 +23,17 @@ parser.add_argument("-m", "--modules", action="store_true", dest="modules",
|
||||
parser.add_argument("-v", action="count", default=0, dest="verbosity",
|
||||
help="Increase verbosity")
|
||||
parser.add_argument('tests', metavar='test', nargs='*')
|
||||
parser.epilog = ('The database name can be specified in the DB_NAME '
|
||||
'environment variable.')
|
||||
opt = parser.parse_args()
|
||||
|
||||
CONFIG['db_type'] = 'sqlite'
|
||||
CONFIG.update_etc(opt.config)
|
||||
if not CONFIG['admin_passwd']:
|
||||
CONFIG['admin_passwd'] = 'admin'
|
||||
config.update_etc(opt.config)
|
||||
|
||||
if CONFIG['db_type'] == 'sqlite':
|
||||
if backend.name() == 'sqlite':
|
||||
database_name = ':memory:'
|
||||
else:
|
||||
database_name = 'test_' + str(int(time.time()))
|
||||
os.environ['DB_NAME'] = database_name
|
||||
os.environ.setdefault('DB_NAME', database_name)
|
||||
|
||||
from trytond.tests.test_tryton import all_suite, modules_suite
|
||||
if not opt.modules:
|
||||
|
||||
@@ -7,7 +7,7 @@ from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
|
||||
install_module
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.config import CONFIG
|
||||
from trytond import backend
|
||||
|
||||
|
||||
class HistoryTestCase(unittest.TestCase):
|
||||
@@ -76,7 +76,7 @@ class HistoryTestCase(unittest.TestCase):
|
||||
with Transaction().set_context(_datetime=datetime.datetime.min):
|
||||
self.assertRaises(UserError, History.read, [history_id])
|
||||
|
||||
@unittest.skipIf(CONFIG['db_type'] in ('sqlite', 'mysql'),
|
||||
@unittest.skipIf(backend.name() in ('sqlite', 'mysql'),
|
||||
'now() is not the start of the transaction')
|
||||
def test0020read_same_timestamp(self):
|
||||
'Test read history with same timestamp'
|
||||
@@ -184,7 +184,7 @@ class HistoryTestCase(unittest.TestCase):
|
||||
History.restore_history([history_id], datetime.datetime.min)
|
||||
self.assertRaises(UserError, History.read, [history_id])
|
||||
|
||||
@unittest.skipIf(CONFIG['db_type'] in ('sqlite', 'mysql'),
|
||||
@unittest.skipIf(backend.name() in ('sqlite', 'mysql'),
|
||||
'now() is not the start of the transaction')
|
||||
def test0045restore_history_same_timestamp(self):
|
||||
'Test restore history with same timestamp'
|
||||
@@ -287,7 +287,7 @@ class HistoryTestCase(unittest.TestCase):
|
||||
records = History.search([], order=order)
|
||||
self.assertEqual(records, instances)
|
||||
|
||||
@unittest.skipIf(CONFIG['db_type'] in ('sqlite', 'mysql'),
|
||||
@unittest.skipIf(backend.name() in ('sqlite', 'mysql'),
|
||||
'now() is not the start of the transaction')
|
||||
def test0060_ordered_search_same_timestamp(self):
|
||||
'Test ordered search with same timestamp'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import unittest
|
||||
import time
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond import backend
|
||||
from trytond.exceptions import UserError, ConcurrencyException
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
|
||||
@@ -20,7 +20,7 @@ class ModelSQLTestCase(unittest.TestCase):
|
||||
self.modelsql = POOL.get('test.modelsql')
|
||||
self.modelsql_timestamp = POOL.get('test.modelsql.timestamp')
|
||||
|
||||
@unittest.skipIf(CONFIG['db_type'] == 'sqlite',
|
||||
@unittest.skipIf(backend.name == 'sqlite',
|
||||
'SQLite not concerned because tryton don\'t set "NOT NULL"'
|
||||
'constraint: "ALTER TABLE" don\'t support NOT NULL constraint'
|
||||
'without default value')
|
||||
@@ -55,7 +55,7 @@ class ModelSQLTestCase(unittest.TestCase):
|
||||
timestamp = self.modelsql_timestamp.read([record.id],
|
||||
['_timestamp'])[0]['_timestamp']
|
||||
|
||||
if CONFIG['db_type'] in ('sqlite', 'mysql'):
|
||||
if backend.name() in ('sqlite', 'mysql'):
|
||||
# timestamp precision of sqlite is the second
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@@ -7,16 +7,17 @@ import unittest
|
||||
import doctest
|
||||
from lxml import etree
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond.pool import Pool
|
||||
from trytond import backend
|
||||
from trytond.protocols.dispatcher import create
|
||||
from trytond.protocols.dispatcher import create, drop
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pyson import PYSONEncoder, Eval
|
||||
from trytond.exceptions import UserError
|
||||
from trytond import security
|
||||
|
||||
__all__ = ['POOL', 'DB_NAME', 'USER', 'USER_PASSWORD', 'CONTEXT',
|
||||
'install_module', 'test_view', 'test_depends', 'doctest_dropdb',
|
||||
'install_module', 'test_view', 'test_depends',
|
||||
'doctest_setup', 'doctest_teardown',
|
||||
'suite', 'all_suite', 'modules_suite']
|
||||
|
||||
Pool.start()
|
||||
@@ -27,6 +28,7 @@ DB_NAME = os.environ['DB_NAME']
|
||||
DB = backend.get('Database')(DB_NAME)
|
||||
Pool.test = True
|
||||
POOL = Pool(DB_NAME)
|
||||
security.check_super = lambda *a, **k: True
|
||||
|
||||
|
||||
class ModelViewTestCase(unittest.TestCase):
|
||||
@@ -72,13 +74,7 @@ def install_module(name):
|
||||
'''
|
||||
Install module for the tested database
|
||||
'''
|
||||
Database = backend.get('Database')
|
||||
database = Database().connect()
|
||||
cursor = database.cursor()
|
||||
databases = database.list(cursor)
|
||||
cursor.close()
|
||||
if DB_NAME not in databases:
|
||||
create(DB_NAME, CONFIG['admin_passwd'], 'en_US', USER_PASSWORD)
|
||||
create_db()
|
||||
with Transaction().start(DB_NAME, USER,
|
||||
context=CONTEXT) as transaction:
|
||||
Module = POOL.get('ir.module.module')
|
||||
@@ -177,16 +173,32 @@ def test_depends():
|
||||
list(depends - set(model._fields)), mname, fname))
|
||||
|
||||
|
||||
def doctest_dropdb(test):
|
||||
'''Remove SQLite memory database'''
|
||||
from trytond.backend.sqlite.database import Database as SQLiteDatabase
|
||||
database = SQLiteDatabase().connect()
|
||||
cursor = database.cursor(autocommit=True)
|
||||
try:
|
||||
SQLiteDatabase.drop(cursor, ':memory:')
|
||||
cursor.commit()
|
||||
finally:
|
||||
cursor.close()
|
||||
def db_exist():
|
||||
Database = backend.get('Database')
|
||||
database = Database().connect()
|
||||
cursor = database.cursor()
|
||||
databases = database.list(cursor)
|
||||
cursor.close()
|
||||
return DB_NAME in databases
|
||||
|
||||
|
||||
def create_db():
|
||||
if not db_exist():
|
||||
create(DB_NAME, None, 'en_US', USER_PASSWORD)
|
||||
|
||||
|
||||
def drop_db():
|
||||
if db_exist():
|
||||
drop(DB_NAME, None)
|
||||
|
||||
|
||||
def drop_create():
|
||||
if db_exist:
|
||||
drop_db()
|
||||
create_db()
|
||||
|
||||
doctest_setup = lambda test: drop_create()
|
||||
doctest_teardown = lambda test: drop_db()
|
||||
|
||||
|
||||
def suite():
|
||||
|
||||
+15
-45
@@ -15,8 +15,9 @@ from array import array
|
||||
from itertools import islice
|
||||
from sql import Literal
|
||||
from sql.operators import Or
|
||||
from trytond.config import CONFIG
|
||||
|
||||
from trytond.const import OPERATORS
|
||||
from trytond.config import config, parse_uri
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
@@ -34,42 +35,7 @@ def find_in_path(name):
|
||||
return name
|
||||
|
||||
|
||||
def find_pg_tool(name):
|
||||
if CONFIG['pg_path'] and CONFIG['pg_path'] != 'None':
|
||||
return os.path.join(CONFIG['pg_path'], name)
|
||||
else:
|
||||
return find_in_path(name)
|
||||
|
||||
|
||||
def exec_pg_command(name, *args):
|
||||
prog = find_pg_tool(name)
|
||||
if not prog:
|
||||
raise Exception('Couldn\'t find %s' % name)
|
||||
args2 = (os.path.basename(prog),) + args
|
||||
return os.spawnv(os.P_WAIT, prog, args2)
|
||||
|
||||
|
||||
def exec_pg_command_pipe(name, *args):
|
||||
prog = find_pg_tool(name)
|
||||
if not prog:
|
||||
raise Exception('Couldn\'t find %s' % name)
|
||||
if os.name == "nt":
|
||||
cmd = '"' + prog + '" ' + ' '.join(args)
|
||||
else:
|
||||
cmd = prog + ' ' + ' '.join(args)
|
||||
|
||||
# if db_password is set in configuration we should pass
|
||||
# an environment variable PGPASSWORD to our subprocess
|
||||
# see libpg documentation
|
||||
child_env = dict(os.environ)
|
||||
if CONFIG['db_password']:
|
||||
child_env['PGPASSWORD'] = CONFIG['db_password']
|
||||
pipe = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, env=child_env)
|
||||
return pipe
|
||||
|
||||
|
||||
def exec_command_pipe(name, *args):
|
||||
def exec_command_pipe(name, *args, **kwargs):
|
||||
prog = find_in_path(name)
|
||||
if not prog:
|
||||
raise Exception('Couldn\'t find %s' % name)
|
||||
@@ -77,7 +43,11 @@ def exec_command_pipe(name, *args):
|
||||
cmd = '"' + prog + '" ' + ' '.join(args)
|
||||
else:
|
||||
cmd = prog + ' ' + ' '.join(args)
|
||||
return os.popen2(cmd, 'b')
|
||||
child_env = dict(os.environ)
|
||||
if kwargs.get('env'):
|
||||
child_env.update(kwargs['env'])
|
||||
return subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, env=child_env)
|
||||
|
||||
|
||||
def file_open(name, mode="r", subdir='modules'):
|
||||
@@ -134,17 +104,17 @@ def get_smtp_server():
|
||||
:return: A SMTP instance. The quit() method must be call when all
|
||||
the calls to sendmail() have been made.
|
||||
"""
|
||||
if CONFIG['smtp_ssl']:
|
||||
smtp_server = smtplib.SMTP_SSL(CONFIG['smtp_server'],
|
||||
CONFIG['smtp_port'])
|
||||
uri = parse_uri(config.get('email', 'uri'))
|
||||
if uri.scheme.startswith('smtps'):
|
||||
smtp_server = smtplib.SMTP_SSL(uri.hostname, uri.port)
|
||||
else:
|
||||
smtp_server = smtplib.SMTP(CONFIG['smtp_server'], CONFIG['smtp_port'])
|
||||
smtp_server = smtplib.SMTP(uri.hostname, uri.port)
|
||||
|
||||
if CONFIG['smtp_tls']:
|
||||
if 'tls' in uri.scheme:
|
||||
smtp_server.starttls()
|
||||
|
||||
if CONFIG['smtp_user'] and CONFIG['smtp_password']:
|
||||
smtp_server.login(CONFIG['smtp_user'], CONFIG['smtp_password'])
|
||||
if uri.username and uri.password:
|
||||
smtp_server.login(uri.username, uri.password)
|
||||
|
||||
return smtp_server
|
||||
|
||||
|
||||
+2
-2
@@ -5,12 +5,12 @@ import encodings.idna
|
||||
import urllib
|
||||
import socket
|
||||
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['URLMixin']
|
||||
|
||||
HOSTNAME = (CONFIG['hostname_jsonrpc']
|
||||
HOSTNAME = (config.get('jsonrpc', 'hostname')
|
||||
or unicode(socket.getfqdn(), 'utf8'))
|
||||
HOSTNAME = '.'.join(encodings.idna.ToASCII(part) if part else ''
|
||||
for part in HOSTNAME.split('.'))
|
||||
|
||||
@@ -16,7 +16,7 @@ from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.tools import reduce_ids, safe_eval
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
from trytond.config import CONFIG
|
||||
from trytond.config import config
|
||||
from trytond.pyson import Eval
|
||||
from trytond.tools import grouped_slice
|
||||
|
||||
@@ -26,11 +26,11 @@ __all__ = [
|
||||
|
||||
|
||||
def get_webdav_url():
|
||||
if CONFIG['ssl_webdav']:
|
||||
if config.get('ssl', 'privatekey'):
|
||||
protocol = 'https'
|
||||
else:
|
||||
protocol = 'http'
|
||||
hostname = (CONFIG['hostname_webdav']
|
||||
hostname = (config.get('webdav', 'hostname')
|
||||
or unicode(socket.getfqdn(), 'utf8'))
|
||||
hostname = '.'.join(encodings.idna.ToASCII(part) for part in
|
||||
hostname.split('.'))
|
||||
|
||||
Reference in New Issue
Block a user