~therp-nl/anybox.recipe.openerp/jbaudoux-relative_paths_resolve_conflict

« back to all changes in this revision

Viewing changes to anybox/recipe/openerp/runtime/upgrade.py

[MRG] Update with target branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Uniform encapsulation of buildout-local upgrade script.
 
2
 
 
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
 
5
taking logic.
 
6
"""
 
7
import os
 
8
import sys
 
9
import imp
 
10
import logging
 
11
from argparse import ArgumentParser
 
12
from argparse import ArgumentDefaultsHelpFormatter
 
13
from argparse import SUPPRESS
 
14
from datetime import datetime
 
15
from math import ceil
 
16
 
 
17
from .session import Session
 
18
 
 
19
DEFAULT_LOG_FILE = 'upgrade.log'
 
20
 
 
21
 
 
22
def upgrade(upgrade_script, upgrade_callable, conf, buildout_dir):
 
23
    """Run the upgrade from a source file.
 
24
 
 
25
    All arguments are set in the standalone script produced by buildout through
 
26
    entry point options.
 
27
 
 
28
    * ``upgrade_script``: absolute path to the upgrade script python source.
 
29
    * ``upgrade_callable``: name of the callable in source file actually
 
30
      running the script.
 
31
 
 
32
      It must accept the two following positional arguments, in that order:
 
33
 
 
34
        - a :class:`.Session` instance (as in standard "OpenERP scripts")
 
35
        - a logger (standard object from the :mod:`logging` module)
 
36
 
 
37
      and may return a non zero status code to indicate an error.
 
38
      Both ``None`` and 0 are interpreted as success.
 
39
 
 
40
    * ``conf``: path to the OpenERP configuration file (managed by the recipe)
 
41
    * ``buildout_dir``: directory of the buildout
 
42
    """
 
43
 
 
44
    parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter,
 
45
                            epilog="")
 
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 "
 
57
                        "logged ")
 
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")
 
68
 
 
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
 
74
 
 
75
    try:
 
76
        log_file = open(log_path, 'a')
 
77
    except IOError:
 
78
        sys.stderr.write("Cannot open %r for write" % log_path + os.linesep)
 
79
        sys.exit(-1)
 
80
 
 
81
    session = Session(conf, buildout_dir)
 
82
 
 
83
    from openerp.tools import config
 
84
    config['logfile'] = log_path
 
85
    config['log-level'] = log_level
 
86
 
 
87
    start_time = datetime.utcnow()
 
88
    if not quiet:
 
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()))
 
92
        print('')
 
93
 
 
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"))
 
99
 
 
100
    if not arguments.quiet:
 
101
        logger.addHandler(console_handler)
 
102
 
 
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
 
108
 
 
109
    if session.is_initialization:
 
110
        logger.info("Database %r base initialization done. Proceeding further",
 
111
                    db_name)
 
112
    else:
 
113
        logger.info("Database %r loaded. Actual upgrade begins.", db_name)
 
114
 
 
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)
 
122
    else:
 
123
        logger.info("Read package version: %s from %s", pkg_version,
 
124
                    session.version_file_path)
 
125
 
 
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.")
 
133
    else:
 
134
        logger.info("Database latest upgrade version : %s", db_version)
 
135
 
 
136
    upgrade_module = imp.load_source('anybox.recipe.openerp.upgrade_openerp',
 
137
                                     upgrade_script)
 
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
 
143
        session.cr.commit()
 
144
 
 
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())
 
148
        ))
 
149
    else:
 
150
        logger.error("Please check logs at %s" % log_path)
 
151
 
 
152
    log_file.close()
 
153
    sys.exit(statuscode)