def _check_xml(self, cr, uid, ids, context=None): if context is None: context = {} context = dict(context, check_view_ids=ids) # Sanity checks: the view should not break anything upon rendering! # Any exception raised below will cause a transaction rollback. for view in self.browse(cr, uid, ids, context): view_def = self.read_combined(cr, uid, view.id, None, context=context) view_arch_utf8 = view_def['arch'] if view.type != 'qweb': view_doc = etree.fromstring(view_arch_utf8) # verify that all fields used are valid, etc. self.postprocess_and_fields(cr, uid, view.model, view_doc, view.id, context=context) # RNG-based validation is not possible anymore with 7.0 forms view_docs = [view_doc] if view_docs[0].tag == 'data': # A <data> element is a wrapper for multiple root nodes view_docs = view_docs[0] validator = self._relaxng() for view_arch in view_docs: version = view_arch.get('version', '7.0') if parse_version(version) < parse_version('7.0') and validator and not validator.validate(view_arch): for error in validator.error_log: _logger.error(tools.ustr(error)) return False if not valid_view(view_arch): return False return True
def download(self, cr, uid, ids, download=True, context=None): res = [] default_version = modules.adapt_version('1.0') for mod in self.browse(cr, uid, ids, context=context): if not mod.url: continue match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I) version = default_version if match: version = match.group(1) if parse_version(mod.installed_version) >= parse_version(version): continue res.append(mod.url) if not download: continue zip_content = urllib.urlopen(mod.url).read() fname = modules.get_module_path(str(mod.name) + '.zip', downloaded=True) try: with open(fname, 'wb') as fp: fp.write(zip_content) except Exception: _logger.exception('Error when trying to create module ' 'file %s', fname) raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,)) terp = self.get_module_info(mod.name) self.write(cr, uid, mod.id, self.get_values_from_terp(terp)) cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (mod.id,)) self._update_dependencies(cr, uid, mod, terp.get('depends', [])) self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized')) # Import module zimp = zipimport.zipimporter(fname) zimp.load_module(mod.name) return res
def update_list(self, cr, uid, context=None): res = [0, 0] # [update, add] default_version = modules.adapt_version("1.0") known_mods = self.browse(cr, uid, self.search(cr, uid, [])) known_mods_names = dict([(m.name, m) for m in known_mods]) # iterate through detected modules and update/create them in db for mod_name in modules.get_modules(): mod = known_mods_names.get(mod_name) terp = self.get_module_info(mod_name) values = self.get_values_from_terp(terp) if mod: updated_values = {} for key in values: old = getattr(mod, key) updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key] if (old or updated) and updated != old: updated_values[key] = values[key] if terp.get("installable", True) and mod.state == "uninstallable": updated_values["state"] = "uninstalled" if parse_version(terp.get("version", default_version)) > parse_version( mod.latest_version or default_version ): res[0] += 1 if updated_values: self.write(cr, uid, mod.id, updated_values) else: mod_path = modules.get_module_path(mod_name) if not mod_path: continue if not terp or not terp.get("installable", True): continue id = self.create(cr, uid, dict(name=mod_name, state="uninstalled", **values)) mod = self.browse(cr, uid, id) res[1] += 1 self._update_dependencies(cr, uid, mod, terp.get("depends", [])) self._update_category(cr, uid, mod, terp.get("category", "Uncategorized")) # Trigger load_addons if new module have been discovered it exists on # wsgi handlers, so they can react accordingly if tuple(res) != (0, 0): for handler in openerp.service.wsgi_server.module_handlers: if hasattr(handler, "load_addons"): handler.load_addons() return res
def parse(self, incoming): if isinstance(incoming, OpenERPVersion): self.vstring = incoming.vstring self.components = incoming.components else: self.vstring = incoming self.components = parse_version(incoming)
def _get_migration_versions(pkg): def __get_dir(tree): return [d for d in tree if tree[d] is not None] versions = list(set( __get_dir(self.migrations[pkg.name]['module']) + __get_dir(self.migrations[pkg.name]['maintenance']) )) versions.sort(key=lambda k: parse_version(convert_version(k))) return versions
def update_list(self, cr, uid, context=None): res = [0, 0] # [update, add] default_version = modules.adapt_version("1.0") known_mods = self.browse(cr, uid, self.search(cr, uid, [])) known_mods_names = dict([(m.name, m) for m in known_mods]) # iterate through detected modules and update/create them in db for mod_name in modules.get_modules(): mod = known_mods_names.get(mod_name) terp = self.get_module_info(mod_name) values = self.get_values_from_terp(terp) if mod: updated_values = {} for key in values: old = getattr(mod, key) updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key] if (old or updated) and updated != old: updated_values[key] = values[key] if terp.get("installable", True) and mod.state == "uninstallable": updated_values["state"] = "uninstalled" if parse_version(terp.get("version", default_version)) > parse_version( mod.latest_version or default_version ): res[0] += 1 if updated_values: self.write(cr, uid, mod.id, updated_values) else: mod_path = modules.get_module_path(mod_name) if not mod_path: continue if not terp or not terp.get("installable", True): continue id = self.create(cr, uid, dict(name=mod_name, state="uninstalled", **values)) mod = self.browse(cr, uid, id) res[1] += 1 self._update_dependencies(cr, uid, mod, terp.get("depends", [])) self._update_category(cr, uid, mod, terp.get("category", "Uncategorized")) return res
def patch(): """ Monkey patch Odoo to discover addons from the odoo_addons namespace """ version = openerp.cli.server.__version__ if parse_version(version) < parse_version('8.0'): raise RuntimeError("Unsupported Odoo version %s" % version) # monkey-patch sys path for autodiscovery of addons initialize_sys_path_orig = openerp.modules.module.initialize_sys_path def initialize_sys_path_odoo_addons(): initialize_sys_path_orig() ad_paths = openerp.modules.module.ad_paths try: # explicit workaround for https://github.com/pypa/pip/issues/3 and # https://github.com/pypa/setuptools/issues/250 (it sort of works # without this but I'm not sure why, so better be safe) pkg_resources.declare_namespace('odoo_addons') for ad in __import__('odoo_addons').__path__: ad = os.path.abspath(ad) if ad not in ad_paths: ad_paths.append(ad) except ImportError: # odoo_addons is not provided by any distribution pass openerp.modules.module.initialize_sys_path = initialize_sys_path_odoo_addons # monkey-patch long_polling_spawn to launch the autodiscover version def long_polling_spawn(self): nargs = stripped_sys_argv() cmd = nargs[0] cmd = os.path.join(os.path.dirname(cmd), "openerp-gevent-autodiscover") nargs[0] = cmd popen = subprocess.Popen([sys.executable] + nargs) self.long_polling_pid = popen.pid openerp.service.server.PreforkServer.long_polling_spawn = long_polling_spawn
def update_list(self, cr, uid, context=None): res = [0, 0] # [update, add] known_mods = self.browse(cr, uid, self.search(cr, uid, [])) known_mods_names = dict([(m.name, m) for m in known_mods]) # iterate through detected modules and update/create them in db for mod_name in modules.get_modules(): mod = known_mods_names.get(mod_name) terp = self.get_module_info(mod_name) values = self.get_values_from_terp(terp) if mod: updated_values = {} for key in values: old = getattr(mod, key) updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key] if not old == updated: updated_values[key] = values[key] if terp.get('installable', True) and mod.state == 'uninstallable': updated_values['state'] = 'uninstalled' if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''): res[0] += 1 if updated_values: self.write(cr, uid, mod.id, updated_values) else: mod_path = modules.get_module_path(mod_name) if not mod_path: continue if not terp or not terp.get('installable', True): continue id = self.create(cr, uid, dict(name=mod_name, state='uninstalled', **values)) mod = self.browse(cr, uid, id) res[1] += 1 self._update_dependencies(cr, uid, mod, terp.get('depends', [])) self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized')) return res
def migrate_module(self, pkg, stage): assert stage in ('pre', 'post') stageformat = { 'pre': '[>%s]', 'post': '[%s>]', } if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'): return def convert_version(version): if version.startswith(release.major_version) and version != release.major_version: return version # the version number already containt the server version return "%s.%s" % (release.major_version, version) def _get_migration_versions(pkg): def __get_dir(tree): return [d for d in tree if tree[d] is not None] versions = list(set( __get_dir(self.migrations[pkg.name]['module']) + __get_dir(self.migrations[pkg.name]['maintenance']) )) versions.sort(key=lambda k: parse_version(convert_version(k))) return versions def _get_migration_files(pkg, version, stage): """ return a list of tuple (module, file) """ m = self.migrations[pkg.name] lst = [] mapping = { 'module': opj(pkg.name, 'migrations'), 'maintenance': opj('base', 'maintenance', 'migrations', pkg.name), } for x in mapping.keys(): if version in m[x]: for f in m[x][version]: if m[x][version][f] is not None: continue if not f.startswith(stage + '-'): continue lst.append(opj(mapping[x], version, f)) lst.sort() return lst def mergedict(a, b): a = a.copy() a.update(b) return a from openerp.tools.parse_version import parse_version parsed_installed_version = parse_version(pkg.installed_version or '') current_version = parse_version(convert_version(pkg.data['version'])) versions = _get_migration_versions(pkg) for version in versions: if parsed_installed_version < parse_version(convert_version(version)) <= current_version: strfmt = {'addon': pkg.name, 'stage': stage, 'version': stageformat[stage] % version, } for pyfile in _get_migration_files(pkg, version, stage): name, ext = os.path.splitext(os.path.basename(pyfile)) if ext.lower() != '.py': continue mod = fp = fp2 = None try: fp = tools.file_open(pyfile) # imp.load_source need a real file object, so we create # one from the file-like object we get from file_open fp2 = os.tmpfile() fp2.write(fp.read()) fp2.seek(0) try: mod = imp.load_source(name, pyfile, fp2) _logger.info('module %(addon)s: Running migration %(version)s %(name)s' % mergedict({'name': mod.__name__}, strfmt)) migrate = mod.migrate except ImportError: _logger.exception('module %(addon)s: Unable to load %(stage)s-migration file %(file)s' % mergedict({'file': pyfile}, strfmt)) raise except AttributeError: _logger.error('module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function' % strfmt) else: migrate(self.cr, pkg.installed_version) finally: if fp: fp.close() if fp2: fp2.close() if mod: del mod
def migrate_module(self, pkg, stage): assert stage in ("pre", "post") stageformat = {"pre": "[>%s]", "post": "[%s>]"} if not (hasattr(pkg, "update") or pkg.state == "to upgrade"): return def convert_version(version): if version.startswith(release.major_version) and version != release.major_version: return version # the version number already containt the server version return "%s.%s" % (release.major_version, version) def _get_migration_versions(pkg): def __get_dir(tree): return [d for d in tree if tree[d] is not None] versions = list( set( __get_dir(self.migrations[pkg.name]["module"]) + __get_dir(self.migrations[pkg.name]["maintenance"]) ) ) versions.sort(key=lambda k: parse_version(convert_version(k))) return versions def _get_migration_files(pkg, version, stage): """ return a list of tuple (module, file) """ m = self.migrations[pkg.name] lst = [] mapping = { "module": opj(pkg.name, "migrations"), "maintenance": opj("base", "maintenance", "migrations", pkg.name), } for x in mapping.keys(): if version in m[x]: for f in m[x][version]: if m[x][version][f] is not None: continue if not f.startswith(stage + "-"): continue lst.append(opj(mapping[x], version, f)) lst.sort() return lst def mergedict(a, b): a = a.copy() a.update(b) return a from openerp.tools.parse_version import parse_version parsed_installed_version = parse_version(pkg.installed_version or "") current_version = parse_version(convert_version(pkg.data["version"])) versions = _get_migration_versions(pkg) for version in versions: if parsed_installed_version < parse_version(convert_version(version)) <= current_version: strfmt = {"addon": pkg.name, "stage": stage, "version": stageformat[stage] % version} for pyfile in _get_migration_files(pkg, version, stage): name, ext = os.path.splitext(os.path.basename(pyfile)) if ext.lower() != ".py": continue mod = fp = fp2 = None try: fp = tools.file_open(pyfile) # imp.load_source need a real file object, so we create # one from the file-like object we get from file_open fp2 = os.tmpfile() fp2.write(fp.read()) fp2.seek(0) try: mod = imp.load_source(name, pyfile, fp2) logger.notifyChannel( "migration", netsvc.LOG_INFO, "module %(addon)s: Running migration %(version)s %(name)s" % mergedict({"name": mod.__name__}, strfmt), ) mod.migrate(self.cr, pkg.installed_version) except ImportError: logger.notifyChannel( "migration", netsvc.LOG_ERROR, "module %(addon)s: Unable to load %(stage)s-migration file %(file)s" % mergedict({"file": pyfile}, strfmt), ) raise except AttributeError: logger.notifyChannel( "migration", netsvc.LOG_ERROR, 'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function' % strfmt, ) except: raise finally: if fp: fp.close() if fp2: fp2.close() if mod: del mod
def migrate_module(self, pkg, stage): assert stage in ('pre', 'post') stageformat = { 'pre': '[>%s]', 'post': '[%s>]', } if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade') or pkg.state == 'to install': return def convert_version(version): if version.count('.') >= 2: return version # the version number already containt the server version return "%s.%s" % (release.major_version, version) def _get_migration_versions(pkg): def __get_dir(tree): return [d for d in tree if tree[d] is not None] versions = list( set( __get_dir(self.migrations[pkg.name]['module']) + __get_dir(self.migrations[pkg.name]['maintenance']))) versions.sort(key=lambda k: parse_version(convert_version(k))) return versions def _get_migration_files(pkg, version, stage): """ return a list of tuple (module, file) """ m = self.migrations[pkg.name] lst = [] mapping = { 'module': opj(pkg.name, 'migrations'), 'maintenance': opj('base', 'maintenance', 'migrations', pkg.name), } for x in list(mapping.keys()): if version in m[x]: for f in m[x][version]: if m[x][version][f] is not None: continue if not f.startswith(stage + '-'): continue lst.append(opj(mapping[x], version, f)) lst.sort() return lst parsed_installed_version = parse_version(pkg.installed_version or '') current_version = parse_version(convert_version(pkg.data['version'])) versions = _get_migration_versions(pkg) for version in versions: if parsed_installed_version < parse_version( convert_version(version)) <= current_version: strfmt = { 'addon': pkg.name, 'stage': stage, 'version': stageformat[stage] % version, } for pyfile in _get_migration_files(pkg, version, stage): name, ext = os.path.splitext(os.path.basename(pyfile)) if ext.lower() != '.py': continue mod = fp = fp2 = None try: fp, fname = tools.file_open(pyfile, pathinfo=True) if not isinstance(fp, file): # imp.load_source need a real file object, so we create # one from the file-like object we get from file_open fp2 = os.tmpfile() fp2.write(fp.read()) fp2.seek(0) try: mod = imp.load_source(name, fname, fp2 or fp) _logger.info( 'module %(addon)s: Running migration %(version)s %(name)s' % dict(strfmt, name=mod.__name__)) migrate = mod.migrate except ImportError: _logger.exception( 'module %(addon)s: Unable to load %(stage)s-migration file %(file)s' % dict(strfmt, file=pyfile)) raise except AttributeError: _logger.error( 'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function' % strfmt) else: migrate(self.cr, pkg.installed_version) finally: if fp: fp.close() if fp2: fp2.close() if mod: del mod
def migrate_module(self, pkg, stage): assert stage in ('pre', 'post') stageformat = { 'pre': '[>%s]', 'post': '[%s>]', } # In openupgrade, remove 'or pkg.installed_version is None' # We want to always pass in pre and post migration files and use a new # argument in the migrate decorator (explained in the docstring) # to decide if we want to do something if a new module is installed # during the migration. if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'): return def convert_version(version): if version.count('.') >= 2: return version # the version number already containt the server version return "%s.%s" % (release.major_version, version) def _get_migration_versions(pkg): def __get_dir(tree): return [d for d in tree if tree[d] is not None] versions = list( set( __get_dir(self.migrations[pkg.name]['module']) + __get_dir(self.migrations[pkg.name]['maintenance']))) versions.sort(key=lambda k: parse_version(convert_version(k))) return versions def _get_migration_files(pkg, version, stage): """ return a list of tuple (module, file) """ m = self.migrations[pkg.name] lst = [] mapping = { 'module': opj(pkg.name, 'migrations'), 'maintenance': opj('base', 'maintenance', 'migrations', pkg.name), } for x in mapping.keys(): if version in m[x]: for f in m[x][version]: if m[x][version][f] is not None: continue if not f.startswith(stage + '-'): continue lst.append(opj(mapping[x], version, f)) lst.sort() return lst def mergedict(a, b): a = a.copy() a.update(b) return a parsed_installed_version = parse_version(pkg.installed_version or '') current_version = parse_version(convert_version(pkg.data['version'])) versions = _get_migration_versions(pkg) for version in versions: if parsed_installed_version < parse_version( convert_version(version)) <= current_version: strfmt = { 'addon': pkg.name, 'stage': stage, 'version': stageformat[stage] % version, } for pyfile in _get_migration_files(pkg, version, stage): name, ext = os.path.splitext(os.path.basename(pyfile)) if ext.lower() != '.py': continue mod = fp = fp2 = None try: fp = tools.file_open(pyfile) # imp.load_source need a real file object, so we create # one from the file-like object we get from file_open fp2 = os.tmpfile() fp2.write(fp.read()) fp2.seek(0) try: mod = imp.load_source(name, pyfile, fp2) _logger.info( 'module %(addon)s: Running migration %(version)s %(name)s', mergedict({'name': mod.__name__}, strfmt)) except ImportError: _logger.exception( 'module %(addon)s: Unable to load %(stage)s-migration file %(file)s', mergedict({'file': pyfile}, strfmt)) raise _logger.info( 'module %(addon)s: Running migration %(version)s %(name)s', mergedict({'name': mod.__name__}, strfmt)) if hasattr(mod, 'migrate'): mod.migrate(self.cr, pkg.installed_version) else: _logger.error( 'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function', strfmt) finally: if fp: fp.close() if fp2: fp2.close() if mod: del mod