Skip to content

Commit

Permalink
Change addons-install for a better CLI experience (#89)
Browse files Browse the repository at this point in the history
* Change addons-install for a better CLI experience

Includes fix for currently broken CI, where some code is getting
removed because environment variables never match at build time.
  • Loading branch information
yajo authored Oct 31, 2017
1 parent ecc55be commit 6c7d2e0
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 38 deletions.
2 changes: 1 addition & 1 deletion 11.0.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ RUN apt-get update \
python3-dev \
zlib1g-dev \
&& pip install --no-cache-dir -r https://raw.githubusercontent.com/$ODOO_SOURCE/$ODOO_VERSION/requirements.txt \
&& python3 -m compileall -q /usr/local/lib/python3.5/ || true \
&& (python3 -m compileall -q /usr/local/lib/python3.5/ || true) \
&& apt-get purge -yqq build-essential '*-dev' \
&& apt-mark -qq manual '*' \
&& rm -Rf /var/lib/apt/lists/*
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,14 @@ now keep this in mind:

## Bundled tools

### `addons-install`
### `addons`

A handy CLI tool to automate addon management based on the current environment.
It allows you to install, update, test and/or list private, extra and/or core
addons available to current container, based on current [`addons.yaml`][]
configuration.

Call `addons-install --help` for usage instructions.
Call `addons --help` for usage instructions.

### [`nano`][]

Expand Down
34 changes: 14 additions & 20 deletions bin/addons-install → bin/addons
Original file line number Diff line number Diff line change
@@ -1,62 +1,56 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
from argparse import ArgumentParser
from subprocess import check_call
from odoobaselib import addons_config, CORE, PRIVATE, logging
from odoobaselib import addons_config, CORE, PRIVATE, SRC_DIR, logging

# 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="Install all Odoo core addons")
parser.add_argument(
"-e", "--extra", action="store_true",
help="Install all extra addons")
parser.add_argument(
"-l", "--list", action="store_true",
help="Only list addons instead of installing them")
"-f", "--fullpath", action="store_true",
help="Print addon's full path, only useful with list mode")
parser.add_argument(
"-p", "--private", action="store_true",
help="Install all private addons")
parser.add_argument(
"-s", "--separator", type=str, default=",",
help="String that separates addons when using --list")
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(
"-u", "--update", action="store_true",
help="Update addons instead of installing them")

# Check no CLI conflicts
args = parser.parse_args()
if not (args.private or args.core or args.extra):
parser.error("You have to choose an option at least")
if args.list and args.update:
parser.error("Cannot --list and --update together")
if args.separator != "," and not args.list:
parser.error("Cannot use --separator without --list")
help="Run unit tests for these addons, usually combined with update")

# Generate the matching addons set
args = parser.parse_args()
addons = set()
for addon, repo in addons_config():
core_ok = args.core and repo == CORE
extra_ok = args.extra and repo not in {CORE, PRIVATE}
private_ok = args.private and repo == PRIVATE
if private_ok or core_ok or extra_ok:
if args.fullpath and args.action == "list":
addon = os.path.join(SRC_DIR, repo, addon)
addons.add(addon)

# Do the required action
if not addons:
sys.exit("No addons found")
addons = args.separator.join(sorted(addons))
if args.list:
if args.action == "list":
print(addons)
else:
command = ["odoo", "--stop-after-init"]
command = ["odoo", "--stop-after-init", "--{}".format(args.action), addons]
if args.test:
command += ["--test-enable", "--workers", "0"]
command += ["--update" if args.update else "--init", addons]
logging.info("Executing %s", " ".join(command))
check_call(command)
2 changes: 1 addition & 1 deletion build.d/400-clean
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if not CLEAN:
logging.warning("Not cleaning garbage")
sys.exit()

addons = set(addons_config())
addons = set(addons_config(False))
repos = {addon[1] for addon in addons} | {CORE, PRIVATE}
for directory in os.listdir(SRC_DIR):
# Special directories must be preserved
Expand Down
21 changes: 17 additions & 4 deletions lib/odoobaselib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,34 @@
logging.root.setLevel(_log_level)


def addons_config():
"""Yield addon name and path from ``ADDONS_YAML``."""
def addons_config(filtered=True):
"""Yield addon name and path from ``ADDONS_YAML``.
:param bool filtered:
Use ``False`` to include all addon definitions. Use ``True`` (default)
to include only those matched by ``ONLY`` clauses, if any.
"""
config = dict()
special_missing = {PRIVATE, CORE}
manifest_files = ['__manifest__.py', '__openerp__.py']
try:
with open(ADDONS_YAML) as addons_file:
for doc in yaml.load_all(addons_file):
# When not filtering, private and core addons should be either
# defined under every doc, or defaulted to `*` in the
# ones where it is missing
if not filtered:
doc.setdefault(CORE, ["*"])
doc.setdefault(PRIVATE, ["*"])
# Skip sections with ONLY and that don't match
if any(os.environ.get(key) not in values
for key, values in doc.get("ONLY", dict()).items()):
elif any(os.environ.get(key) not in values
for key, values in doc.get("ONLY", dict()).items()):
logging.debug("Skipping section with ONLY %s", doc["ONLY"])
continue
# Flatten all sections in a single dict
for repo, addons in doc.items():
if repo == "ONLY":
continue
logging.debug("Processing %s repo", repo)
special_missing.discard(repo)
for glob in addons:
Expand Down
23 changes: 13 additions & 10 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,36 +95,39 @@ def compose_test(self, workdir, sub_env, *commands):
def test_addons_filtered(self):
"""Test addons filtering with ``ONLY`` keyword in ``addons.yaml``."""
project_dir = join(SCAFFOLDINGS_DIR, "dotd")
for sub_env in matrix(odoo={"10.0"}):
for sub_env in matrix():
self.compose_test(
project_dir,
dict(sub_env, DBNAME="prod"),
("test", "-e", "auto/addons/website"),
("test", "-e", "auto/addons/dummy_addon"),
("test", "-e", "auto/addons/private_addon"),
("bash", "-c", 'test "$(addons-install -lp)" == private_addon'),
("bash", "-c", 'test "$(addons-install -le)" == dummy_addon'),
("bash", "-c", 'addons-install -lc | grep ,crm,'),
("bash", "-c", 'test "$(addons list -p)" == private_addon'),
("bash", "-c",
'test "$(addons list -e)" == dummy_addon,product'),
("bash", "-c", 'addons list -c | grep ,crm,'),
)
self.compose_test(
project_dir,
dict(sub_env, DBNAME="limited_private"),
("test", "-e", "auto/addons/website"),
("test", "-e", "auto/addons/dummy_addon"),
("test", "!", "-e", "auto/addons/private_addon"),
("bash", "-c", 'test -z "$(addons-install -lp)"'),
("bash", "-c", 'test "$(addons-install -le)" == dummy_addon'),
("bash", "-c", 'addons-install -lc | grep ,crm,'),
("bash", "-c", 'test -z "$(addons list -p)"'),
("bash", "-c",
'test "$(addons list -e)" == dummy_addon,product'),
("bash", "-c", 'addons list -c | grep ,crm,'),
)
self.compose_test(
project_dir,
dict(sub_env, DBNAME="limited_core"),
("test", "!", "-e", "auto/addons/website"),
("test", "-e", "auto/addons/dummy_addon"),
("test", "!", "-e", "auto/addons/private_addon"),
("bash", "-c", 'test -z "$(addons-install -lp)"'),
("bash", "-c", 'test "$(addons-install -le)" == dummy_addon'),
("bash", "-c", 'test "$(addons-install -lc)" == crm,sale'),
("bash", "-c", 'test -z "$(addons list -p)"'),
("bash", "-c",
'test "$(addons list -e)" == dummy_addon,product'),
("bash", "-c", 'test "$(addons list -c)" == crm,sale'),
)

def test_smallest(self):
Expand Down
Empty file.

0 comments on commit 6c7d2e0

Please sign in to comment.