1
"""Uniform encapsulation of buildout-local upgrade script.
3
The idea is to provide a common set of options, so that upgrade scripts all
4
have the same interface, and project maintainers can focus on the decision
11
from argparse import ArgumentParser
12
from argparse import ArgumentDefaultsHelpFormatter
13
from argparse import SUPPRESS
14
from datetime import datetime
17
from .session import Session
19
DEFAULT_LOG_FILE = 'upgrade.log'
22
def upgrade(upgrade_script, upgrade_callable, conf, buildout_dir):
23
"""Run the upgrade from a source file.
25
All arguments are set in the standalone script produced by buildout through
28
* ``upgrade_script``: absolute path to the upgrade script python source.
29
* ``upgrade_callable``: name of the callable in source file actually
32
It must accept the two following positional arguments, in that order:
34
- a :class:`.Session` instance (as in standard "OpenERP scripts")
35
- a logger (standard object from the :mod:`logging` module)
37
and may return a non zero status code to indicate an error.
38
Both ``None`` and 0 are interpreted as success.
40
* ``conf``: path to the OpenERP configuration file (managed by the recipe)
41
* ``buildout_dir``: directory of the buildout
44
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter,
46
parser.add_argument('--log-file', default=DEFAULT_LOG_FILE,
47
help="File to log sub-operations to, relative to the "
48
"current working directory, supports homedir "
49
"expansion ('~' on POSIX systems).")
50
parser.add_argument('--log-level', default='info',
51
help="Main OpenERP logging level. Does not affect the "
52
"logging from the main upgrade script itself.")
53
parser.add_argument('--console-log-level', default='info',
54
help="Level for the upgrade process console "
55
"logging. This is for the main upgrade script itself "
56
"meaning that usually only major steps should be "
58
parser.add_argument('-q', '--quiet', action='store_true',
59
help="Suppress console output from the main upgrade "
60
"script (lower level stages can still write)")
61
parser.add_argument('-d', '--db-name', default=SUPPRESS,
62
help="Database name. If ommitted, the general default "
63
"values from OpenERP config file or libpq will apply.")
64
parser.add_argument('--init-load-demo-data', action='store_true',
65
help="Demo data will be loaded with module "
66
"installations if and only if "
67
"this modifier is specified")
69
arguments = parser.parse_args() # 'args' would shadow the one of pdb
70
log_path = os.path.abspath(os.path.expanduser(arguments.log_file))
71
log_level = arguments.log_level
72
console_level = arguments.console_log_level.upper()
73
quiet = arguments.quiet
76
log_file = open(log_path, 'a')
78
sys.stderr.write("Cannot open %r for write" % log_path + os.linesep)
81
session = Session(conf, buildout_dir)
83
from openerp.tools import config
84
config['logfile'] = log_path
85
config['log-level'] = log_level
87
start_time = datetime.utcnow()
89
print("Starting upgrade, logging details to %s at level %s, "
90
"and major steps to console at level %s" % (
91
log_path, log_level.upper(), console_level.upper()))
94
logger = logging.getLogger('openerp.upgrade')
95
console_handler = logging.StreamHandler()
96
console_handler.setLevel(getattr(logging, console_level))
97
console_handler.setFormatter(logging.Formatter(
98
"%(asctime)s %(levelname)s %(message)s"))
100
if not arguments.quiet:
101
logger.addHandler(console_handler)
103
db_name = getattr(arguments, 'db_name', None)
104
logger.info("Opening database %r", db_name)
105
session.open(db=db_name, with_demo=bool(arguments.init_load_demo_data))
106
# actual value after all defaultings have been done
107
db_name = session.cr.dbname
109
if session.is_initialization:
110
logger.info("Database %r base initialization done. Proceeding further",
113
logger.info("Database %r loaded. Actual upgrade begins.", db_name)
115
pkg_version = session.package_version
116
if pkg_version is None:
117
logger.warn("Expected package version file %r does not exist. "
118
"version won't be set in database at the end of upgrade. "
119
"Consider including such a version file in your project "
120
"*before* version dependent logic is actually needed.",
121
session.version_file_path)
123
logger.info("Read package version: %s from %s", pkg_version,
124
session.version_file_path)
126
db_version = session.db_version
127
if db_version is None:
128
if not session.is_initialization:
129
logger.warn("No version currently set in database (the present "
130
"upgrade script has never been run). Consider setting "
131
"database version even for fresh instances, to "
132
"eliminate any guesswork in the upgrade scripts.")
134
logger.info("Database latest upgrade version : %s", db_version)
136
upgrade_module = imp.load_source('anybox.recipe.openerp.upgrade_openerp',
138
statuscode = getattr(upgrade_module, upgrade_callable)(session, logger)
139
if statuscode is None or statuscode == 0:
140
if pkg_version is not None:
141
logger.info("setting version %s in database" % pkg_version)
142
session.db_version = pkg_version
145
logger.info("%s successful. Total time: %d seconds." % (
146
"Initialization" if session.is_initialization else "Upgrade",
147
ceil((datetime.utcnow() - start_time).total_seconds())
150
logger.error("Please check logs at %s" % log_path)