#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function import ast import os import sys from argparse import ArgumentParser from subprocess import check_call from doodbalib import ( CORE, ENTERPRISE, MANIFESTS, PRIVATE, SRC_DIR, AddonsConfigError, addons_config, logger, ) # Exit codes EXIT_NO_ADDONS = 0x4 # Define CLI options parser = ArgumentParser(description="Install addons in current environment") parser.add_argument( "action", choices=("init", "update", "list"), help="What to do with the matched addons.", ) parser.add_argument( "-c", "--core", action="store_true", help="Use all Odoo core addons" ) parser.add_argument( "-d", "--dependencies", action="store_true", help="Use only dependencies of selected addons", ) parser.add_argument("-e", "--extra", action="store_true", help="Use all extra addons") parser.add_argument( "-f", "--fullpath", action="store_true", help="Print addon's full path, only useful with list mode", ) parser.add_argument( "-i", "--installable", action="store_true", help="Include only installable addons" ) parser.add_argument( "-n", "--enterprise", action="store_true", help="Use all enterprise addons" ) parser.add_argument( "-p", "--private", action="store_true", help="Use all private addons" ) parser.add_argument( "-s", "--separator", type=str, default=",", help="String that separates addons only useful with list mode", ) parser.add_argument( "-t", "--test", action="store_true", help="Run unit tests for these addons, usually combined with update", ) parser.add_argument( "-x", "--explicit", action="store_true", help="Fail if any addon is explicitly declared but not found", ) parser.add_argument( "-w", "--with", action="append", dest="with_", default=[], help="Addons to include always.", ) parser.add_argument( "-W", "--without", action="append", default=[], help="Addons to exclude always." ) # Generate the matching addons set args = parser.parse_args() dependencies = {"base"} addons = set(args.with_) without = set(args.without) if addons & without: sys.exit("Cannot include and exclude the same addon!") if args.dependencies and args.fullpath: sys.exit("Unsupported combination of --dependencies and --fullpath") try: for addon, repo in addons_config(strict=args.explicit): if addon in without: continue core_ok = args.core and repo == CORE enterprise_ok = args.enterprise and repo == ENTERPRISE extra_ok = args.extra and repo not in {CORE, ENTERPRISE, PRIVATE} private_ok = args.private and repo == PRIVATE manual_ok = addon in addons if private_ok or core_ok or extra_ok or enterprise_ok or manual_ok: addon_path = os.path.join(SRC_DIR, repo, addon) manifest = {} for manifest_name in MANIFESTS: try: manifest_path = os.path.join(addon_path, manifest_name) with open(manifest_path, "r") as code: manifest = ast.literal_eval(code.read()) break except IOError: continue if args.installable and not manifest.get("installable", True): continue dependencies.update(manifest.get("depends", [])) if args.fullpath and args.action == "list": addon = addon_path addons.add(addon) except AddonsConfigError as error: sys.exit(error.message) # Use dependencies instead, if requested if args.dependencies: addons = dependencies - addons addons -= without # Do the required action if not addons: print("No addons found", file=sys.stderr) sys.exit(EXIT_NO_ADDONS) addons = args.separator.join(sorted(addons)) if args.action == "list": print(addons) else: command = ["odoo", "--stop-after-init", "--{}".format(args.action), addons] if args.test: command += ["--test-enable", "--workers", "0"] if os.environ.get("PGDATABASE"): command += ["--db-filter", u"^{}$".format(os.environ.get("PGDATABASE"))] logger.info("Executing %s", " ".join(command)) check_call(command)