Browse Source

[NEW] new 14.0 odoo image inspirate by doodba

14.0
Nicolas JEUDY 2 years ago
parent
commit
4c2b97e47f
  1. 44
      Dockerfile
  2. 144
      bin/addons
  3. 165
      bin/autoaggregate
  4. 52
      bin/config-generate
  5. 75
      bin/direxec
  6. 15
      bin/log
  7. 11
      bin/pot
  8. 18
      bin/preparedb
  9. 18
      custom/build.d/100-repos-aggregate
  10. 18
      custom/build.d/110-addons-link
  11. 30
      custom/build.d/200-dependencies
  12. 31
      custom/build.d/300-fontconfig
  13. 51
      custom/build.d/400-clean
  14. 10
      custom/build.d/500-compile
  15. 21
      custom/build.d/900-dependencies-cleanup
  16. 8
      custom/dependencies/apt.txt
  17. 3
      custom/dependencies/apt_build.txt
  18. 0
      custom/dependencies/gem.txt
  19. 0
      custom/dependencies/npm.txt
  20. 43
      custom/dependencies/pip.txt
  21. 164
      custom/src/addons.yaml
  22. 20
      custom/src/private/.editorconfig
  23. 884
      custom/src/repos.yaml
  24. 38
      custom/ssh/cloudron_git.rsa
  25. 1
      custom/ssh/cloudron_git.rsa.pub
  26. 7
      custom/ssh/config
  27. 14
      custom/ssh/known_hosts
  28. 173
      lib/doodbalib/__init__.py
  29. 119
      lib/doodbalib/installer.py
  30. 18
      start.sh

44
Dockerfile

@ -1,7 +1,7 @@
FROM cloudron/base:3.2.0@sha256:ba1d566164a67c266782545ea9809dc611c4152e27686fd14060332dd88263ea
# Reference: https://github.com/odoo/docker/blob/master/15.0/Dockerfile
RUN mkdir -p /app/code /app/pkg /app/data
RUN mkdir -p /app/code /app/pkg /app/data /app/code/auto/addons
WORKDIR /app/code
RUN apt-get update && \
@ -18,26 +18,52 @@ RUN curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/wkhtmltopdf/releas
RUN npm install -g rtlcss
COPY bin/* /usr/local/bin/
COPY lib/doodbalib /usr/local/lib/python3.8/dist-packages/doodbalib
COPY custom /app/code/custom
RUN chmod -R a+rx /usr/local/bin \
&& chmod -R a+rX /usr/local/lib/python3.8/dist-packages/doodbalib \
&& sync
# Install Odoo
ARG ODOO_VERSION=15.0
ARG ODOO_COMMIT_HASH=f07c63d3e4135d658bb952f1b4880e97d0b66992
# sync extra addons
ENV ODOO_VERSION=14.0
ENV ODOO_SOURCE=OCA/OCB
ENV DEPTH_DEFAULT=100
ENV DEPTH_MERGE=500
RUN git config --global user.email "$CLOUDRON_MAIL_SMTP_USERNAME"
RUN git config --global user.name "Cloudron service"
RUN curl -L https://github.com/odoo/odoo/archive/${ODOO_COMMIT_HASH}.tar.gz | tar zx --strip-components 1 -C /app/code && \
pip3 install wheel && \
pip3 install -r requirements.txt
# RUN curl -L https://github.com/odoo/odoo/archive/${ODOO_COMMIT_HASH}.tar.gz | tar zx --strip-components 1 -C /app/code && \
RUN git clone https://github.com/odoo/odoo.git --depth 1 -b $ODOO_VERSION /app/code/odoo
RUN pip3 install wheel && \
pip3 install -r https://raw.githubusercontent.com/$ODOO_SOURCE/$ODOO_VERSION/requirements.txt && \
pip3 install psycopg2==2.8.6 \
&& pip3 install git-aggregator \
&& (python3 -m compileall -q /usr/local/lib/python3.8/ || true)
# Patch Odoo to prevent connecting to the default database named 'postgres' every now and then.
RUN sed -i.bak "748i\ to = tools.config['db_name']" /app/code/odoo/sql_db.py
RUN sed -i.bak "718i\ to = tools.config['db_name']" /app/code/odoo/odoo/sql_db.py
# Properly map the LDAP attribute 'displayname' instead of 'cn' to the display name of the logged in user.
RUN sed -i.bak "194s/'cn'/'displayname'/" /app/code/addons/auth_ldap/models/res_company_ldap.py
RUN sed -i.bak "181s/'cn'/'displayname'/" /app/code/odoo/addons/auth_ldap/models/res_company_ldap.py
RUN rm -rf /var/log/nginx && mkdir /run/nginx && ln -s /run/nginx /var/log/nginx
# Copy entrypoint script and Odoo configuration file
ADD start.sh odoo.conf.sample nginx.conf /app/pkg/
WORKDIR /app/code/custom/src
RUN gitaggregate -c /app/code/custom/src/repos.yaml --expand-env
RUN /app/code/custom/build.d/110-addons-link
RUN /app/code/custom/build.d/200-dependencies
RUN /app/code/custom/build.d/400-clean
RUN /app/code/custom/build.d/900-dependencies-cleanup
RUN mkdir -p /app/data/odoo/filestore /app/data/odoo/addons && \
chown -R cloudron:cloudron /app/data
CMD [ "/app/pkg/start.sh" ]
CMD [ "/app/pkg/start.sh" ]

144
bin/addons

@ -0,0 +1,144 @@
#!/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)

165
bin/autoaggregate

@ -0,0 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
from multiprocessing import cpu_count
from subprocess import check_call
import yaml
from doodbalib import (
ADDONS_YAML,
AUTO_REPOS_YAML,
CORE,
ODOO_DIR,
PRIVATE,
REPOS_YAML,
SRC_DIR,
logger,
)
# if the umask matches the `chmod -R u+rwX,g+rX-w,o= /opt/odoo` command the build is faster as we don't need to fix as
# many permissions after auto aggregation
UMASK = os.environ.get("UMASK") or "0027"
UID = int(os.environ.get("UID") or -1)
GID = int(os.environ.get("GID") or -1)
DEFAULT_REPO_PATTERN = os.environ.get("DEFAULT_REPO_PATTERN")
DEFAULT_REPO_PATTERN_ODOO = os.environ.get("DEFAULT_REPO_PATTERN_ODOO")
log_level = os.environ.get("LOG_LEVEL", "INFO")
def aggregate(config):
"""Execute git aggregator to pull git code.
:param str config:
Path where to find the ``repos.yaml`` file.
"""
logger.info("Running gitaggregate with %s", config)
def pre_exec_umask():
# Download git code with the specified umask, if set, otherwise use "0027"
os.umask(int(UMASK, 8))
pre_execs = [pre_exec_umask]
def pre_exec():
for _exec in pre_execs:
try:
_exec()
except Exception as e:
logger.error("Error in %s: %s" % (_exec, e))
logger.exception(e)
raise
if ~GID:
def pre_exec_gid():
# execute git with GID
os.setgid(GID)
pre_execs.append(pre_exec_gid)
if ~UID:
def pre_exec_uid():
# execute git with UID
os.setuid(UID)
# set odoo home directory
# (git checks if user has a config in $HOME, and we cannot read /root as odoo user)
os.environ["HOME"] = "/home/odoo"
pre_execs.append(pre_exec_uid)
check_call(
[
"gitaggregate",
"--expand-env",
"--config",
config,
"--log-level",
log_level,
"--jobs",
str(cpu_count() or 1),
"aggregate",
],
cwd=SRC_DIR,
stderr=sys.stderr,
stdout=sys.stdout,
preexec_fn=pre_exec,
)
def origin_for(
folder,
default_repo_pattern=DEFAULT_REPO_PATTERN,
odoo_repo_pattern=DEFAULT_REPO_PATTERN_ODOO,
):
"""Guess the default git origin for that folder.
:param str folder:
Normally an absolute path to an expected git repo, whose name should
match the git repository where it comes from, using the env-supplied
pattern.
"""
base = os.path.basename(folder)
pattern = default_repo_pattern
if base == "odoo":
pattern = odoo_repo_pattern
return pattern.format(base)
def missing_repos_config():
"""Find the undefined repositories and return their default configuration.
:return dict:
git-aggregator-ready configuration dict for undefined repositories.
"""
defined, expected = set(), {ODOO_DIR}
# Find the repositories defined by hand
try:
with open(REPOS_YAML) as yaml_file:
for doc in yaml.safe_load_all(yaml_file):
for repo in doc:
defined.add(os.path.abspath(os.path.join(SRC_DIR, repo)))
except (IOError, AttributeError):
logger.debug("No repositories defined by hand")
addons_env = {}
# Find the repositories that should be present
try:
with open(ADDONS_YAML) as yaml_file:
for doc in yaml.safe_load_all(yaml_file):
env = dict(os.environ, **doc.get("ENV", {}))
for repo in doc:
if repo in {PRIVATE, "ONLY", "ENV"}:
continue
if repo == CORE:
repo_path = ODOO_DIR
else:
repo_path = os.path.abspath(os.path.join(SRC_DIR, repo))
if not os.path.exists(repo_path) or os.path.isdir(
os.path.join(repo_path, ".git")
):
expected.add(repo_path)
addons_env[repo_path] = env
except (IOError, AttributeError):
logger.debug("No addons are expected to be present")
# Find the undefined repositories and generate a config for them
missing = expected - defined
config = {}
for repo_path in missing:
env = addons_env.get(repo_path, os.environ)
depth = env["DEPTH_DEFAULT"]
origin_version = "origin %s" % env["ODOO_VERSION"]
config[repo_path] = {
"defaults": {"depth": depth},
"merges": [origin_version],
"remotes": {
"origin": origin_for(
repo_path,
env["DEFAULT_REPO_PATTERN"],
env["DEFAULT_REPO_PATTERN_ODOO"],
)
},
"target": origin_version,
}
logger.debug("Generated missing repos config %r", config)
return config

52
bin/config-generate

@ -0,0 +1,52 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Generate Odoo server configuration from templates"""
import os
from contextlib import closing
from string import Template
from doodbalib import logger
try:
# Python 2, where io.StringIO fails because it is unicode-only
from StringIO import StringIO
except ImportError:
from io import StringIO
try:
from configparser import RawConfigParser
parser = RawConfigParser(strict=False)
except ImportError:
# Python 2, where strict=True doesn't exist
from ConfigParser import RawConfigParser
parser = RawConfigParser()
ODOO_VERSION = os.environ.get("ODOO_VERSION")
TARGET_FILE = os.environ.get("ODOO_RC", "/opt/odoo/auto/odoo.conf")
CONFIG_DIRS = ("/opt/odoo/common/conf.d", "/opt/odoo/custom/conf.d")
CONFIG_FILES = []
# Read all configuraiton files found in those folders
logger.info("Merging found configuration files in %s", TARGET_FILE)
for dir_ in CONFIG_DIRS:
try:
for file_ in sorted(os.listdir(dir_)):
parser.read(os.path.join(dir_, file_))
except OSError: # TODO Use FileNotFoundError when we drop python 2
continue
# Write it to a memory string object
with closing(StringIO()) as resultfp:
parser.write(resultfp)
resultfp.seek(0)
# Obtain the config string
result = resultfp.read()
# Expand environment variables found within
result = Template(result).substitute(os.environ)
logger.debug("Resulting configuration:\n%s", result)
# Write it to destination
with open(TARGET_FILE, "w") as targetfp:
targetfp.write(result)

75
bin/direxec

@ -0,0 +1,75 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import subprocess
import sys
from logging import DEBUG, INFO, WARNING
from doodbalib import logger, which
# Call this file linked from another file called `build` or `entrypoint`
mode = os.path.basename(__file__)
dir_odoo = "/opt/odoo"
dir_common = os.path.join(dir_odoo, "common", "%s.d" % mode)
dir_custom = os.path.join(dir_odoo, "custom", "%s.d" % mode)
# Find scripts
files = [(d, dir_common) for d in os.listdir(dir_common)]
try:
files += [(d, dir_custom) for d in os.listdir(dir_custom)]
except OSError:
pass
# Run scripts
for executable, folder in sorted(files):
command = os.path.join(folder, executable)
if os.access(command, os.X_OK):
logger.debug("Executing %s", command)
subprocess.check_call(command)
# Allow to omit 1st command and default to `odoo`
extra_command = sys.argv[1:]
if extra_command:
if extra_command[0] == "shell" or extra_command[0].startswith("-"):
extra_command.insert(0, "odoo")
# Set the DB creation language, if needed
if extra_command[0] in {"odoo", "/usr/local/bin/odoo"}:
if os.environ.get("INITIAL_LANG"):
from psycopg2 import OperationalError, connect
try:
connection = connect(dbname=os.environ.get("PGDATABASE"))
connection.close()
except OperationalError:
# No DB exists, set initial language
extra_command += ["--load-language", os.environ["INITIAL_LANG"]]
if os.environ.get("PTVSD_ENABLE") == "1":
# Warn deprecation
logger.log(
WARNING,
"ptvsd has beed deprecated for python debugging. "
"Please use debugpy (see https://github.com/Tecnativa/doodba#debugpy)",
)
# See `python -m ptvsd -h` to understand this
extra_command[0] = os.path.realpath(which(extra_command[0]))
extra_command = (
["python", "-m", "ptvsd"]
+ os.environ.get("PTVSD_ARGS", "").split()
+ extra_command
)
elif os.environ["DEBUGPY_ENABLE"] == "1":
# See `python -m debugpy -h` to understand this
extra_command[0] = os.path.realpath(which(extra_command[0]))
extra_command = (
["python", "-m", "debugpy"]
+ os.environ["DEBUGPY_ARGS"].split()
+ extra_command
)
logger.log(
DEBUG if extra_command[0] == "/qa/insider" else INFO,
"Executing %s",
" ".join(extra_command),
)
os.execvp(extra_command[0], extra_command)

15
bin/log

@ -0,0 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import argparse
import logging
from doodbalib import LOG_LEVELS, logger
parser = argparse.ArgumentParser(description="Easy logging for scripts")
parser.add_argument("level", choices=LOG_LEVELS)
parser.add_argument("message", nargs="+")
arguments = parser.parse_args()
logger.log(getattr(logging, arguments.level), " ".join(arguments.message))

11
bin/pot

@ -0,0 +1,11 @@
#!/bin/bash
# Shortcut to run Odoo in unit testing mode
set -e
addons=$1
shift
log INFO Executing Odoo in i18n export mode for addons $addons
# HACK Odoo needs a *.po file to guess the output format
ln -sf /dev/stdout /tmp/stdout.po
set -x
exec odoo --stop-after-init -d "$PGDATABASE" --i18n-export /tmp/stdout.po \
--modules "$addons" --update "$addons" --workers 0 "$@"

18
bin/preparedb

@ -0,0 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Script to prepare the database with initial data
import click
import click_odoo
@click.command()
@click_odoo.env_options(default_log_level="info", database_must_exist=True)
def main(env):
"""Set report.url in the database to be pointing at localhost."""
env["ir.config_parameter"].set_param("report.url", "http://localhost:8069")
env.cr.commit()
if __name__ == "__main__":
main()

18
custom/build.d/100-repos-aggregate

@ -0,0 +1,18 @@
#!/bin/bash
set -e
# make sure odoo has a user.name configured, as merges would not succeed otherwise
# (even if GIT_AUTHOR_NAME and EMAIL are set and should be used, it seems gitaggregate is not passing them to git)
su --shell="$SHELL" odoo -c 'git config user.name 1>/dev/null || git config --global user.name "'"$GIT_AUTHOR_NAME"'"'
# copy ssh directory to odoo user as well (gitaggregate may also be run as odoo user)
if [[ ! -e ~odoo/.ssh ]] ; then
cp -a /opt/odoo/custom/ssh ~odoo/.ssh
fi
if [ "$AGGREGATE" != true ]; then
log WARNING Not aggregating code repositories
exit 0
fi
exec autoaggregate

18
custom/build.d/110-addons-link

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from glob import iglob
from doodbalib import ADDONS_DIR, ADDONS_YAML, SRC_DIR, addons_config, logger
logger.info("Linking all addons from %s in %s", ADDONS_YAML, ADDONS_DIR)
# Remove all links in addons dir
for link in iglob(os.path.join(ADDONS_DIR, "*")):
os.remove(link)
# Add new links
for addon, repo in addons_config():
src = os.path.relpath(os.path.join(SRC_DIR, repo, addon), ADDONS_DIR)
dst = os.path.join(ADDONS_DIR, addon)
os.symlink(src, dst)
logger.debug("Linked %s in %s", src, dst)

30
custom/build.d/200-dependencies

@ -0,0 +1,30 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
from glob import glob
from os.path import basename, join, splitext
from doodbalib import CUSTOM_DIR, FILE_APT_BUILD, SRC_DIR
from doodbalib.installer import INSTALLERS, install, logger
# Build dependencies installed before any others
install("apt", FILE_APT_BUILD)
for name in INSTALLERS:
req_files = []
# Normal dependency installation
req_files.append(join(CUSTOM_DIR, "dependencies", "%s.txt" % name))
for req_file in req_files:
install(name, req_file)
# Sorted dependencies installation
dep_files = sorted(glob(join(CUSTOM_DIR, "dependencies", "[0-9]*-*")))
for dep_file in dep_files:
root, ext = splitext(basename(dep_file))
# Get the installer (xxx-installer[-description][.ext])
installer = root.split("-", 2)[1]
if installer not in INSTALLERS:
logger.error("Unknown installer: %s", installer)
raise Exception
install(installer, dep_file)

31
custom/build.d/300-fontconfig

@ -0,0 +1,31 @@
#!/bin/bash
set -e
mkdir -p ~cloudron/.config/fontconfig/conf.d
cat <<END > ~odoo/.config/fontconfig/conf.d/100-doodba.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- Odoo default fonts, generated by Doodba -->
<fontconfig>
<alias>
<family>monospace</family>
<prefer>
<family>$FONT_MONO</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>$FONT_SANS</family>
</prefer>
</alias>
<alias>
<family>serif</family>
<prefer>
<family>$FONT_SERIF</family>
</prefer>
</alias>
</fontconfig>
END
chown cloudron:cloudron ~cloudron/.config

51
custom/build.d/400-clean

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import shutil
import sys
from doodbalib import CLEAN, ODOO_DIR, PRIVATE_DIR, SRC_DIR, addons_config, logger
if not CLEAN:
logger.warning("Not cleaning garbage")
sys.exit()
# Get the enabled paths
repos_addons = {}
for addon, repo in addons_config(filtered=False):
repo_path = os.path.realpath(os.path.join(SRC_DIR, repo))
repos_addons.setdefault(repo_path, set())
repos_addons[repo_path].add(addon)
logger.debug("Addon paths enabled: %s", repos_addons)
# Traverse src dir and remove anything not explicitly enabled
for directory, subdirectories, subfiles in os.walk(SRC_DIR):
logger.debug("Checking for cleanup directory %s", directory)
# Skip main src directory
if directory == SRC_DIR:
continue
# Always skip private/*
if directory == PRIVATE_DIR:
subdirectories[:] = []
continue
# Inside the odoo dir, skip all but addons dir
if directory == ODOO_DIR:
subdirectories[:] = ["addons"]
continue
try:
# Get addons enalbed in current directory
enabled_addons = repos_addons[directory]
except KeyError:
# This isn't a repo; is there anything inside to preserve?
directory += os.path.sep
if any(repo.startswith(directory) for repo in repos_addons):
# Then, let's walk in; we'll remove later if needed
continue
else:
# This is an addons repo; do not walk into the enabled ones
for addon in enabled_addons:
subdirectories.remove(addon)
continue
# Remove every other directory
logger.info("Removing directory %s", directory)
shutil.rmtree(directory)

10
custom/build.d/500-compile

@ -0,0 +1,10 @@
#!/bin/bash
set -e
if [ "$COMPILE" != true ]; then
log WARNING Not compiling Python code
exit 0
fi
log INFO Compiling all Python code in /opt/odoo
python -m compileall -q /opt/odoo

21
custom/build.d/900-dependencies-cleanup

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
import os
from doodbalib import CUSTOM_DIR, FILE_APT_BUILD
from doodbalib.installer import INSTALLERS
# Build-time dependencies must be removed when finishing build
if os.path.isfile(FILE_APT_BUILD):
installer = INSTALLERS["apt"](FILE_APT_BUILD)
installer.remove()
installer.cleanup()
# Clean up garbage generated by respective package managers
for name, class_ in INSTALLERS.items():
req_file = os.path.join(CUSTOM_DIR, "dependencies", "%s.txt" % name)
if os.path.isfile(req_file):
class_(req_file).cleanup()

8
custom/dependencies/apt.txt

@ -0,0 +1,8 @@
python3-pandas
cups
libcups2-dev
python3-dev
build-essential
libcairo2-dev
pkg-config
xmlsec1

3
custom/dependencies/apt_build.txt

@ -0,0 +1,3 @@
libldap2-dev
libssl-dev
libsasl2-dev

0
custom/dependencies/gem.txt

0
custom/dependencies/npm.txt

43
custom/dependencies/pip.txt

@ -0,0 +1,43 @@
git+https://github.com/OCA/openupgradelib.git@master
unicodecsv
unidecode
py3o.template
PyPDF2
py3o.formats
zeep
parse-accept-language
pyquerystring
cerberus==1.3.2
apispec>=4.0.0
marshmallow
marshmallow-objects>=2.0.0
cachetools
boto
pycups
bravado_core
facebook_business
python-telegram-bot
swagger_spec_validator
viberbot
PyMuPDF==1.16.14
factur-x
regex
dateparser
pycairo
rocketchat_API
ovh
weboob
payplug
qrcode
markdownify
requests_oauthlib
pyocclient
cryptography>=2.3
jwcrypto==0.5.0
freezegun
pysaml2
formio-data
pysaml2
odoo_test_helper
python-jose
click-odoo-contrib

164
custom/src/addons.yaml

@ -0,0 +1,164 @@
sale-workflow:
- "*"
openupgrade:
- "openupgrade_framework"
- "openupgrade_scripts"
partner-contact:
- "*"
server-ux:
- "*"
bank-payment:
- "*"
account-financial-tools:
- "account_*"
- "base_*"
community-data-files:
- "*"
hr:
- "*"
l10n-france:
- "*"
l10n-switzerland:
- "*"
product-attribute:
- "*"
project:
- "*"
project-reporting:
- "*"
web:
- "*"
website:
- "*"
mis-builder:
- "*"
operating-unit:
- "*"
connector:
- "*"
purchase-workflow:
- "*"
server-env:
- "*"
odoo-theme:
- "*"
report-engine:
- "*"
formio:
- "*"
# learning_addons:
# - "*"
muk-web:
- "*"
rest-framework:
- "*"
server-auth:
- "*"
server-tools:
- "*"
wms:
- "*"
stock-logistics-warehouse:
- "*"
contract:
- "*"
field-service:
- "*"
queue:
- "*"
commission:
- "*"
pms:
- "*"
dms:
- "*"
social:
- "*"
pos:
- "*"
product-configurator:
- "*"
stock-logistics-workflow:
- "*"
account-financial-reporting:
- "*"
bank-statement-import:
- "*"
account-reconcile:
- "*"
manufacture:
- "*"
multi-company:
- "*"
account-analytic:
- "*"
stock-logistics-reporting:
- "*"
account-invoice-reporting:
- "*"
sale-reporting:
- "*"
account-closing:
- "*"
account-payment:
- "*"
edi:
- "*"
timesheet:
- "*"
odoo-pim:
- "*"
delivery-carrier:
- "*"
storage:
- "*"
product-variant:
- "*"
e-commerce:
- "*"
hr-expense:
- "*"
crm:
- "*"
maintenance:
- "*"
connector-telephony:
- "*"
server-backend:
- "*"
intrastat-extrastat:
- "*"
brand:
- "*"
hr-holidays:
- "*"
server-brand:
- "*"
report-print-send:
- "*"
calendar:
- "*"
credit-control:
- "*"
# myc-extra-addons:
# - "*"
account-invoicing:
- "*"
sync-addons:
- "*"
vertical-cooperative:
- "*"
# nj-addons:
# - "*"
vertical-association:
- "*"
account-move-import:
- "*"
galicea-addons:
- "*"
straga-main:
- "*"
odoo-usability:
- "*"
odoo-py3o-report-templates:
- "*"

20
custom/src/private/.editorconfig

@ -0,0 +1,20 @@
# Configuration for known file extensions
[*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{json,yml,yaml,rst,md}]
indent_size = 2
# Do not configure editor for libs and autogenerated content
[{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}]
charset = unset
end_of_line = unset
indent_size = unset
indent_style = unset
insert_final_newline = false
trim_trailing_whitespace = false

884
custom/src/repos.yaml

@ -0,0 +1,884 @@
./sale-workflow:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/sale-workflow.git
target: origin 14.0
merges:
- origin 14.0
./partner-contact:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/partner-contact.git
# myc: ssh://git@git.myceliandre.fr:5022/OCA/partner-contact.git
target: oca 14.0
merges:
#- myc 14.0_partner_favorite
- oca 14.0
./server-ux:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/server-ux.git
target: oca 14.0
merges:
- oca 14.0
./bank-payment:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/bank-payment.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/820/head
- oca refs/pull/822/head
#- oca refs/pull/831/head
#- oca refs/pull/858/head
./account-financial-tools:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/account-financial-tools.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/1087/head
- oca refs/pull/1236/head
./community-data-files:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/community-data-files.git
target: oca 14.0
merges:
- oca 14.0
./hr:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/hr.git
target: oca 14.0
merges:
- oca 14.0
./l10n-switzerland:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/l10n-switzerland.git
target: oca 12.0
merges:
- oca 12.0
./l10n-france:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/l10n-france.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/257/head
- oca refs/pull/321/head
./product-attribute:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/product-attribute.git
target: oca 14.0
merges:
- oca 14.0
./project:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/project.git
target: oca 14.0
merges:
- oca 14.0
./project-reporting:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/project-reporting.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/44/head
./website:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/website.git
target: oca 14.0
merges:
- oca 14.0
./web:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/web.git
target: oca 14.0
merges:
- oca 14.0
./mis-builder:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/mis-builder.git
target: oca 14.0
merges:
- oca 14.0
./operating-unit:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/operating-unit.git
target: oca 14.0
merges:
- oca 14.0
./connector:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/connector.git
target: oca 14.0
merges:
- oca 14.0
./delivery-carrier:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/delivery-carrier.git
target: origin 14.0
merges:
- origin 14.0
./purchase-workflow:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/purchase-workflow.git
target: origin 14.0
merges:
- origin 14.0
./server-env:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/server-env.git
target: origin 14.0
merges:
- origin 14.0
./odoo-theme:
defaults:
depth: $DEPTH_DEFAULT
remotes:
myc: https://git.myceliandre.fr/Myceliandre/odoo_theme.git
target: myc 14.0
merges:
- myc 14.0
./report-engine:
defaults:
depth: 200
remotes:
oca: https://github.com/OCA/reporting-engine.git
target: oca 14.0
merges:
#- oca refs/pull/445/head
#- oca refs/pull/506/head
#- oca refs/pull/526/head
#- oca refs/pull/502/head
# report_py3o PR
#- oca refs/pull/445/head
- oca 14.0
./formio:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/novacode-nl/odoo-formio.git
target: origin 14.0
merges:
- origin 14.0
# ./learning_addons:
# defaults:
# # Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# # You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# # for a sane value of 100 commits)
# depth: $DEPTH_DEFAULT
# remotes:
# origin: ssh://git@git.myceliandre.fr:5022/Myceliandre/odoo_learning_addons.git
# target: origin 14.0
# merges:
# - origin 14.0
./muk-web:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/muk-it/muk_web.git
target: origin 14.0
merges:
- origin 14.0
./rest-framework:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/rest-framework.git
target: oca 14.0
merges:
- oca 14.0
./server-auth:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/server-auth.git
target: oca 14.0
merges:
- oca 14.0
./server-tools:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/server-tools.git
target: oca 14.0
merges:
- oca 14.0
./wms:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/wms.git
target: oca 14.0
merges:
- oca 14.0
./stock-logistics-warehouse:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/stock-logistics-warehouse.git
target: oca 14.0
merges:
- oca 14.0
./contract:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/contract.git
target: oca 14.0
merges:
- oca 14.0
./field-service:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/field-service.git
target: oca 14.0
merges:
- oca 14.0
./queue:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/queue.git
target: oca 14.0
merges:
- oca 14.0
./commission:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/commission.git
target: oca 14.0
merges:
- oca 14.0
./pms:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/pms.git
target: oca 14.0
merges:
- oca 14.0
./dms:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/dms.git
target: oca 14.0
merges:
- oca 14.0
./social:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/social.git
target: oca 14.0
merges:
- oca 14.0
./pos:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/pos.git
target: oca 14.0
merges:
- oca 14.0
./product-configurator:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/product-configurator.git
target: oca 14.0
merges:
- oca 14.0
./stock-logistics-workflow:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/stock-logistics-workflow.git
target: oca 14.0
merges:
- oca 14.0
./account-financial-reporting:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/account-financial-reporting.git
target: oca 14.0
merges:
- oca 14.0
./bank-statement-import:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/bank-statement-import.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/396/head
- oca refs/pull/417/head
- oca refs/pull/423/head
./account-reconcile:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/account-reconcile.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/361/head
- oca refs/pull/382/head
- oca refs/pull/402/head
- oca refs/pull/412/head
./manufacture:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/manufacture.git
target: oca 14.0
merges:
- oca 14.0
./multi-company:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/multi-company.git
target: oca 14.0
merges:
- oca 14.0
./account-analytic:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/account-analytic.git
target: oca 14.0
merges:
- oca 14.0
./stock-logistics-reporting:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/stock-logistics-reporting.git
target: oca 14.0
merges:
- oca 14.0
./account-invoice-reporting:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/account-invoice-reporting.git
target: oca 14.0
merges:
- oca 14.0
./account-invoicing:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/account-invoicing.git
target: oca 14.0
merges:
- oca 14.0
./sale-reporting:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/sale-reporting.git
target: oca 14.0
merges:
- oca 14.0
./account-closing:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/account-closing.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/155/head
- oca refs/pull/174/head
./account-payment:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/account-payment.git
target: oca 14.0
merges:
- oca 14.0
./edi:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: 200
remotes:
oca: https://github.com/OCA/edi.git
target: oca 14.0
merges:
- oca 14.0
- oca refs/pull/326/head
#- oca refs/pull/334/head
- oca refs/pull/454/head
./timesheet:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/timesheet.git
target: oca 14.0
merges:
- oca 14.0
./odoo-pim:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/odoo-pim.git
target: oca 14.0
merges:
- oca 14.0
./storage:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/storage.git
target: oca 14.0
merges:
- oca 14.0
./product-variant:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/product-variant.git
target: oca 14.0
merges:
- oca 14.0
./e-commerce:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/e-commerce.git
target: oca 14.0
merges:
- oca 14.0
./hr-expense:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/hr-expense.git
target: oca 14.0
merges:
- oca 14.0
./crm:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/crm.git
target: oca 14.0
merges:
- oca 14.0
./maintenance:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/maintenance.git
target: oca 14.0
merges:
- oca 14.0
./connector-telephony:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/connector-telephony.git
target: oca 14.0
merges:
- oca 14.0
./server-backend:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/server-backend.git
target: oca 14.0
merges:
- oca 14.0
./intrastat-extrastat:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/intrastat-extrastat.git
target: oca 14.0
merges:
- oca 14.0
./brand:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/brand.git
target: oca 14.0
merges:
- oca 14.0
./hr-holidays:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/hr-holidays.git
target: oca 14.0
merges:
- oca 14.0
./server-brand:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/server-brand.git
target: oca 14.0
merges:
- oca 14.0
./report-print-send:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/report-print-send.git
target: oca 14.0
merges:
- oca 14.0
./calendar:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/calendar.git
target: oca 14.0
merges:
- oca 14.0
./credit-control:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
oca: https://github.com/OCA/credit-control.git
target: oca 14.0
merges:
- oca 14.0
# ./myc-extra-addons:
# defaults:
# depth: $DEPTH_DEFAULT
# remotes:
# myc: ssh://git@git.myceliandre.fr:5022/njeudy/myc-extra-addons.git
# target: myc 14.0
# merges:
# - myc 14.0
./sync-addons:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/itpp-labs/sync-addons.git
target: origin 14.0
merges:
- origin 14.0
./vertical-cooperative:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://git.myceliandre.fr/njeudy/vertical-cooperative.git
target: origin 14.0-MIG-INITIAL
merges:
- origin 14.0-MIG-INITIAL
# ./nj-addons:
# defaults:
# depth: $DEPTH_DEFAULT
# remotes:
# origin: ssh://git@git.myceliandre.fr:5022/nj.0k.io/nj-addons.git
# target: origin 14.0
# merges:
# - origin 14.0
./vertical-association:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/vertical-association.git
target: origin 14.0
merges:
- origin 14.0
./account-move-import:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/akretion/account-move-import.git
target: origin 14.0
merges:
- origin 14.0
./galicea-addons:
defaults:
# Shallow repositories ($DEPTH_DEFAULT=1) are faster & thinner
# You may need a bigger depth when merging PRs (use $DEPTH_MERGE
# for a sane value of 100 commits)
depth: $DEPTH_DEFAULT
remotes:
origin: https://git.myceliandre.fr/Myceliandre/galicea-odoo-addons-ecosystem.git
target: origin 14.0
merges:
- origin 14.0
./openupgrade:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/OCA/OpenUpgrade.git
target: origin 14.0
merges:
- origin 14.0
./straga-main:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/straga/odoo_vik_main.git
target: origin 14.0
merges:
- origin 14.0
./odoo-usability:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/akretion/odoo-usability.git
target: origin 14.0
merges:
- origin 14.0
./odoo-py3o-report-templates:
defaults:
depth: $DEPTH_DEFAULT
remotes:
origin: https://github.com/akretion/odoo-py3o-report-templates.git
target: origin 14.0
merges:
- origin 14.0

38
custom/ssh/cloudron_git.rsa

@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAxTkiUEpg2rhVAbvImkk2BAKIB13kCg2IyNuiUtPwKWBt4gyDzQwS
r9+lhDcTb41UmQFn0++dBCveRkTTafY+d23aWSHf+vfM470CSzdwothHIukNnPyRvWAwhO
Z7X51evA2hYuUvdeZex0Rqrwdxu1vrpCsPwHxiEAMm5Adc8ybqEiKBkoRv20PKas1WEl/m
RpSTadGUZVh0fJFp9gRFKmZMqXWm81hB5MpKL4OBd/APhRZfqNT0WOTIBHFKySjAqNi4H8
eUW3voi/ivSMTCv1MyybzSEHRLS8fzDa9zJ6uXp6/SOVSNyIT8oNqBBOG0Bk0w2y9E32lR
tnqmugVU40CSoIwf9LyCy3pSdqM1mM+sXTsd/tqY4Vo/H1m6U+zjEX1/9pLYbS0uDbdCAv
ChoxQg+HtCZ74wX2c+yFrVcDqqHNOqCbbPdjSNrdCFVdZtx2A2AuqALFnXskc1lJ4VTOsJ
Fr5QoAmLGRYN0lvqzNVUwI/BklmIYOgi8cvXf4PxAAAFkItx43GLceNxAAAAB3NzaC1yc2
EAAAGBAMU5IlBKYNq4VQG7yJpJNgQCiAdd5AoNiMjbolLT8ClgbeIMg80MEq/fpYQ3E2+N
VJkBZ9PvnQQr3kZE02n2Pndt2lkh3/r3zOO9Aks3cKLYRyLpDZz8kb1gMITme1+dXrwNoW
LlL3XmXsdEaq8Hcbtb66QrD8B8YhADJuQHXPMm6hIigZKEb9tDymrNVhJf5kaUk2nRlGVY
dHyRafYERSpmTKl1pvNYQeTKSi+DgXfwD4UWX6jU9FjkyARxSskowKjYuB/HlFt76Iv4r0
jEwr9TMsm80hB0S0vH8w2vcyerl6ev0jlUjciE/KDagQThtAZNMNsvRN9pUbZ6proFVONA
kqCMH/S8gst6UnajNZjPrF07Hf7amOFaPx9ZulPs4xF9f/aS2G0tLg23QgLwoaMUIPh7Qm
e+MF9nPsha1XA6qhzTqgm2z3Y0ja3QhVXWbcdgNgLqgCxZ17JHNZSeFUzrCRa+UKAJixkW
DdJb6szVVMCPwZJZiGDoIvHL13+D8QAAAAMBAAEAAAGAAxi7jjEsxiJgy08sfieqHnP/uM
Xjn7jIrgaszMohGjU2ZHc31o9a98H2MlY/CuBYNLLN84jumTMrIUVRYHeKUYu7Au1CPAmK
AQVltNKhBR2KOGUaXp2kmCmbeWq5Ay5QX3mDUC8zCJHeaRiM6ESgp4Vw9LnsXGRXkdLK2I
e5EORKhpBeInPL4dB1rCmfMViqH++TRPUSdGjoI1CRLliw0VKb34lGXsnC9xmqAob5EG4H
gFpylA8L6x1kepVgzDnEjYf9DEHwapmBrqFzamItaVX0/tCbz9Z+pJKPwbQUNiI685vpto
y+1N3ebPlQWIYVMe8nNJk5sHU1fHSvwaUy7LHC7rQS5M8+rPk9uJ6Gn4IzrMT+krUXhLQ7
ty8MeA2MJfkZPh2hewp+oBInocNrQY/YoEIG+GymWl5bWd14Oq1aD3c6kiQx4wFbS+UQ8v
K24PwXQMp44Js8tu8VzW8PkJDS0tWIBbj6vb3VLnLzPSi96RXcUwGNtB5nIkgKbdt1AAAA
wQDarcaxa7NIz5MkRgLhWNUPSZRh9upUnck6Ul7JnMYeVkNTm6u17V5sl1qj6Tk+EhZvHL
5pwMra8XtCDq5rtQuG6d7SQp0aB1uQEXioIkSzazaMO2KRxSJsLjXpSwPQn6dcrwEpDafX
1bgTocYA+fg54qv0F1luBOojv5XaUYY/6Qh0avdVohP00uS5vnNCSrFR4K/VB2Xgi3F0Io
dm7gdGwN/VCXpkydW3o8x/ka1vWQhAWdhfcd4ZNu10tya3m1wAAADBAPveoaaPPK0k4v5B
5TMXlnz939H7i+iwBx3cDgZNRX8c1nnhb+rjy/JQV0N01v6CUmAR4NgRe4SrCb7HgRcvAd
Ac2uYzT3f5/F3Gj/zETGM1cCrMox64BPqIPkMrQVtq58AdclJqqiqvbYYl5oycbkKd2CcF
dhMh5GAI2RTDMcxQzcM5EBGh9vWxUtCosNBsGMRm8jvUXg8fpNIduf6B+qU3pNen6otPPt
ydGZStR+iAkf4p8ny0OJQ+lTPMfimzvwAAAMEAyHUXp/60l7g6A1s5lOgvnUwJYlVk5MRl
QEfdAHVbIhqM+Vig4po1nk2zVf+VKtZe6JIalcrelHydohMgFIsMsfFOn/lhjuL+yUaeb9
ud0aJmP7MPOcf2uFv5iqN87Q893OHdkoZSak2SHWQm/Sho3tHKaM7OdQwOiwJqnzyPc8Dg
YD/JJWsqzNRCQ9BL7zuaf1+0gb5lBJGw95kBDg7rOuKQXdk7uWxQCZPXj3/xO2kk0t/cTa
cgHT4D/mOucfRPAAAAFm5qZXVkeUBERVNLVE9QLU1MUk5HOEQBAgME
-----END OPENSSH PRIVATE KEY-----

1
custom/ssh/cloudron_git.rsa.pub

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDFOSJQSmDauFUBu8iaSTYEAogHXeQKDYjI26JS0/ApYG3iDIPNDBKv36WENxNvjVSZAWfT750EK95GRNNp9j53bdpZId/698zjvQJLN3Ci2Eci6Q2c/JG9YDCE5ntfnV68DaFi5S915l7HRGqvB3G7W+ukKw/AfGIQAybkB1zzJuoSIoGShG/bQ8pqzVYSX+ZGlJNp0ZRlWHR8kWn2BEUqZkypdabzWEHkykovg4F38A+FFl+o1PRY5MgEcUrJKMCo2Lgfx5Rbe+iL+K9IxMK/UzLJvNIQdEtLx/MNr3Mnq5enr9I5VI3IhPyg2oEE4bQGTTDbL0TfaVG2eqa6BVTjQJKgjB/0vILLelJ2ozWYz6xdOx3+2pjhWj8fWbpT7OMRfX/2kthtLS4Nt0IC8KGjFCD4e0JnvjBfZz7IWtVwOqoc06oJts92NI2t0IVV1m3HYDYC6oAsWdeyRzWUnhVM6wkWvlCgCYsZFg3SW+rM1VTAj8GSWYhg6CLxy9d/g/E= njeudy@DESKTOP-MLRNG8D

7
custom/ssh/config

@ -0,0 +1,7 @@
# See syntax in https://www.ssh.com/ssh/config/ and `man ssh_config`
Host *
IgnoreUnknown UseKeychain
UseKeychain yes
IdentityFile /root/.ssh/cloudron_git.rsa
PubkeyAcceptedKeyTypes=+ssh-dss
AddKeysToAgent yes

14
custom/ssh/known_hosts

@ -0,0 +1,14 @@
# Use `ssh-keyscan` to fill this file and ensure remote git hosts ssh keys
# bitbucket.org:22 SSH-2.0-conker_1.0.298-8c5a6f7 app-126
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
# github.com:22 SSH-2.0-libssh-0.7.0
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
# gitlab.com:22 SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.2
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
# gitlab.com:22 SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.2
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
# gitlab.com:22 SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.2
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf

173
lib/doodbalib/__init__.py

@ -0,0 +1,173 @@
# -*- coding: utf-8 -*-
import logging
import os
from glob import glob
from pprint import pformat
from subprocess import check_output
import yaml
# Constants needed in scripts
CUSTOM_DIR = "/app/code/custom"
AUTO_DIR = "/app/code/auto"
ADDONS_DIR = os.path.join(AUTO_DIR, "addons")
SRC_DIR = os.path.join(CUSTOM_DIR, "src")
ADDONS_YAML = os.path.join(SRC_DIR, "addons")
if os.path.isfile("%s.yaml" % ADDONS_YAML):
ADDONS_YAML = "%s.yaml" % ADDONS_YAML
else:
ADDONS_YAML = "%s.yml" % ADDONS_YAML
REPOS_YAML = os.path.join(SRC_DIR, "repos")
if os.path.isfile("%s.yaml" % REPOS_YAML):
REPOS_YAML = "%s.yaml" % REPOS_YAML
else:
REPOS_YAML = "%s.yml" % REPOS_YAML
AUTO_REPOS_YAML = os.path.join(AUTO_DIR, "repos")
if os.path.isfile("%s.yml" % AUTO_REPOS_YAML):
AUTO_REPOS_YAML = "%s.yml" % AUTO_REPOS_YAML
else:
AUTO_REPOS_YAML = "%s.yaml" % AUTO_REPOS_YAML
CLEAN = os.environ.get("CLEAN") == "true"
LOG_LEVELS = frozenset({"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"})
FILE_APT_BUILD = os.path.join(CUSTOM_DIR, "dependencies", "apt_build.txt")
PRIVATE = "private"
CORE = "odoo/addons"
ENTERPRISE = "enterprise"
PRIVATE_DIR = os.path.join(SRC_DIR, PRIVATE)
CORE_DIR = os.path.join(SRC_DIR, CORE)
ODOO_DIR = os.path.join(SRC_DIR, "odoo")
ODOO_VERSION = os.environ["ODOO_VERSION"]
MANIFESTS = ("__manifest__.py", "__openerp__.py")
# Customize logging for build
logger = logging.getLogger("doodba")
log_handler = logging.StreamHandler()
log_formatter = logging.Formatter("%(name)s %(levelname)s: %(message)s")
log_handler.setFormatter(log_formatter)
logger.addHandler(log_handler)
_log_level = os.environ.get("LOG_LEVEL", "")
if _log_level.isdigit():
_log_level = int(_log_level)
elif _log_level in LOG_LEVELS:
_log_level = getattr(logging, _log_level)
else:
if _log_level:
logger.warning("Wrong value in $LOG_LEVEL, falling back to INFO")
_log_level = logging.INFO
logger.setLevel(_log_level)
class AddonsConfigError(Exception):
def __init__(self, message, *args):
super(AddonsConfigError, self).__init__(message, *args)
self.message = message
def addons_config(filtered=True, strict=False):
"""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.
:param bool strict:
Use ``True`` to raise an exception if any declared addon is not found.
:return Iterator[str, str]:
A generator that yields ``(addon, repo)`` pairs.
"""
config = dict()
missing_glob = set()
missing_manifest = set()
all_globs = {}
try:
with open(ADDONS_YAML) as addons_file:
for doc in yaml.safe_load_all(addons_file):
# Skip sections with ONLY and that don't match
only = doc.pop("ONLY", {})
if not filtered:
doc.setdefault(CORE, ["*"])
doc.setdefault(PRIVATE, ["*"])
elif any(
os.environ.get(key) not in values for key, values in only.items()
):
logger.debug("Skipping section with ONLY %s", only)
continue
# Flatten all sections in a single dict
for repo, partial_globs in doc.items():
if repo == "ENV":
continue
logger.debug("Processing %s repo", repo)
all_globs.setdefault(repo, set())
all_globs[repo].update(partial_globs)
except IOError:
logger.debug("Could not find addons configuration yaml.")
# Add default values for special sections
for repo in (CORE, PRIVATE):
all_globs.setdefault(repo, {"*"})
logger.debug("Merged addons definition before expanding: %r", all_globs)
# Expand all globs and store config
for repo, partial_globs in all_globs.items():
for partial_glob in partial_globs:
logger.debug("Expanding in repo %s glob %s", repo, partial_glob)
full_glob = os.path.join(SRC_DIR, repo, partial_glob)
found = glob(full_glob)
if not found:
# Projects without private addons should never fail
if (repo, partial_glob) != (PRIVATE, "*"):
missing_glob.add(full_glob)
logger.debug("Skipping unexpandable glob '%s'", full_glob)
continue
for addon in found:
if not os.path.isdir(addon):
continue
manifests = (os.path.join(addon, m) for m in MANIFESTS)
if not any(os.path.isfile(m) for m in manifests):
missing_manifest.add(addon)
logger.debug(
"Skipping '%s' as it is not a valid Odoo " "module", addon
)
continue
logger.debug("Registering addon %s", addon)
addon = os.path.basename(addon)
config.setdefault(addon, set())
config[addon].add(repo)
# Fail now if running in strict mode
if strict:
error = []
if missing_glob:
error += ["Addons not found:", pformat(missing_glob)]
if missing_manifest:
error += ["Addons without manifest:", pformat(missing_manifest)]
if error:
raise AddonsConfigError("\n".join(error), missing_glob, missing_manifest)
logger.debug("Resulting configuration after expanding: %r", config)
for addon, repos in config.items():
# Private addons are most important
if PRIVATE in repos:
yield addon, PRIVATE
continue
# Odoo core addons are least important
if repos == {CORE}:
yield addon, CORE
continue
repos.discard(CORE)
# Other addons fall in between
if filtered and len(repos) != 1:
raise AddonsConfigError(
u"Addon {} defined in several repos {}".format(addon, repos)
)
for repo in repos:
yield addon, repo
try:
from shutil import which
except ImportError:
# Custom which implementation for Python 2
def which(binary):
return check_output(["which", binary]).strip()

119
lib/doodbalib/installer.py

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
from collections import OrderedDict
from os.path import exists
from subprocess import check_call
from doodbalib import logger
class Installer(object):
"""Base class to install packages with some package system."""
_cleanup_commands = []
_install_command = None
_remove_command = None
def __init__(self, file_path):
self.file_path = file_path
self._requirements = self.requirements()
def _run_command(self, command):
logger.info("Executing: %s", command)
return check_call(command, shell=isinstance(command, str))
def cleanup(self):
"""Remove cache and other garbage produced by the installer engine."""
for command in self._cleanup_commands:
self._run_command(command)
def install(self):
"""Install the requirements from the given file."""
if self._requirements:
return not self._run_command(self._install_command + self._requirements)
else:
logger.info("No installable requirements found in %s", self.file_path)
return False
def remove(self):
"""Uninstall the requirements from the given file."""
if not self._remove_command:
return
if self._requirements:
self._run_command(self._remove_command + self._requirements)
else:
logger.info("No removable requirements found in %s", self.file_path)
def requirements(self):
"""Get a list of requirements from the given file."""
requirements = []
try:
with open(self.file_path, "r") as fh:
for line in fh:
line = line.strip()
if not line or line.startswith("#"):
continue
requirements += line.split()
except IOError:
# No requirements file
pass
return requirements
class AptInstaller(Installer):
_cleanup_commands = [["apt-get", "-y", "autoremove"], "rm -Rf /var/lib/apt/lists/*"]
_install_command = [
"apt-get",
"-o",
"Dpkg::Options::=--force-confdef",
"-o",
"Dpkg::Options::=--force-confold",
"-y",
"--no-install-recommends",
"install",
]
_remove_command = ["apt-get", "purge", "-y"]
def _dirty(self):
return exists("/var/lib/apt/lists/lock")
def cleanup(self):
if self._dirty():
super(AptInstaller, self).cleanup()
def install(self):
if not self._dirty() and self._requirements:
self._run_command(["apt-get", "update"])
return super(AptInstaller, self).install()
class GemInstaller(Installer):
_cleanup_commands = ["rm -Rf ~/.gem /var/lib/gems/*/cache/"]
_install_command = ["gem", "install", "--no-document", "--no-update-sources"]
class NpmInstaller(Installer):
_cleanup_commands = ["rm -Rf ~/.npm /tmp/*"]
_install_command = ["npm", "install", "-g"]
class PipInstaller(Installer):
_install_command = ["pip", "install", "--no-cache-dir", "-r"]
def requirements(self):
"""Pip will use its ``--requirements`` feature."""
return [self.file_path] if exists(self.file_path) else []
INSTALLERS = OrderedDict(
[
("apt", AptInstaller),
("gem", GemInstaller),
("npm", NpmInstaller),
("pip", PipInstaller),
]
)
def install(installer, file_path):
"""Perform a given type of installation from a given file."""
return INSTALLERS[installer](file_path).install()

18
start.sh

@ -18,15 +18,16 @@ chown -R cloudron:cloudron /run
# Check for First Run
if [[ ! -f /app/data/odoo.conf ]]; then
echo "First run. Initializing DB..."
# Initialize the database, and exit.
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo-bin -i base,auth_ldap,fetchmail --without-demo all --data-dir /app/data/odoo --logfile /run/odoo/runtime.log -d $CLOUDRON_POSTGRESQL_DATABASE --db_host $CLOUDRON_POSTGRESQL_HOST --db_port $CLOUDRON_POSTGRESQL_PORT --db_user $CLOUDRON_POSTGRESQL_USERNAME --db_pass $CLOUDRON_POSTGRESQL_PASSWORD --stop-after-init
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo/odoo-bin -i base,auth_ldap,fetchmail --without-demo all --data-dir /app/data/odoo --logfile /run/odoo/runtime.log -d $CLOUDRON_POSTGRESQL_DATABASE --db_host $CLOUDRON_POSTGRESQL_HOST --db_port $CLOUDRON_POSTGRESQL_PORT --db_user $CLOUDRON_POSTGRESQL_USERNAME --db_pass $CLOUDRON_POSTGRESQL_PASSWORD --stop-after-init
echo "Initialized successfully."
echo "Adding required tables/relations for mail settings."
pg_cli "INSERT INTO public.res_config_settings (create_uid, create_date, write_uid, write_date, company_id, user_default_rights, external_email_server_default, module_base_import, module_google_calendar, module_microsoft_calendar, module_mail_plugin, module_google_drive, module_google_spreadsheet, module_auth_oauth, module_auth_ldap, module_base_gengo, module_account_inter_company_rules, module_pad, module_voip, module_web_unsplash, module_partner_autocomplete, module_base_geolocalize, module_google_recaptcha, group_multi_currency, show_effect, profiling_enabled_until, module_product_images, unsplash_access_key, fail_counter, alias_domain, restrict_template_rendering, use_twilio_rtc_servers, twilio_account_sid, twilio_account_token, auth_signup_reset_password, auth_signup_uninvited, auth_signup_template_user_id) VALUES (2, 'NOW()', 2, 'NOW()', 1, false, true, true, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, NULL, false, NULL, 0, '$CLOUDRON_APP_DOMAIN', false, false, NULL, NULL, false, 'b2b', 5) ON CONFLICT (id) DO NOTHING;"
# echo "Adding required tables/relations for mail settings."
# pg_cli "INSERT INTO public.res_config_settings (create_uid, create_date, write_uid, write_date, company_id, user_default_rights, external_email_server_default, module_base_import, module_google_calendar, module_microsoft_calendar, module_google_drive, module_google_spreadsheet, module_auth_oauth, module_auth_ldap, module_base_gengo, module_account_inter_company_rules, module_pad, module_voip, module_web_unsplash, module_partner_autocomplete, module_base_geolocalize, module_google_recaptcha, group_multi_currency, show_effect, module_product_images, unsplash_access_key, fail_counter, alias_domain, restrict_template_rendering, use_twilio_rtc_servers, twilio_account_sid, twilio_account_token, auth_signup_reset_password, auth_signup_uninvited, auth_signup_template_user_id) VALUES (2, 'NOW()', 2, 'NOW()', 1, false, true, true, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, false, NULL, 0, '$CLOUDRON_APP_DOMAIN', false, false, NULL, NULL, false, 'b2b', 5) ON CONFLICT (id) DO NOTHING;"
pg_cli "INSERT INTO public.ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date) VALUES ('base_setup.default_external_email_server', 'True', 2, 'NOW()', 2, 'NOW()');"
pg_cli "INSERT INTO public.ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date) VALUES ('mail.catchall.domain', '$CLOUDRON_APP_DOMAIN', 2, 'NOW()', 2, 'NOW()');"
@ -36,7 +37,9 @@ if [[ ! -f /app/data/odoo.conf ]]; then
echo "Copying default configuration file to /app/data/odoo.conf..."
cp /app/pkg/odoo.conf.sample /app/data/odoo.conf
crudini --set /app/data/odoo.conf 'options' list_db "False"
crudini --set /app/data/odoo.conf 'options' admin_password "$CLOUDRON_MAIL_SMTP_PASSWORD"
echo "First run complete."
fi
@ -44,7 +47,7 @@ fi
echo "Ensuring proper [options] in /app/data/odoo.conf ..."
# Custom paths
crudini --set /app/data/odoo.conf 'options' addons_path "/app/code/addons,/app/data/extra-addons"
crudini --set /app/data/odoo.conf 'options' addons_path "/app/code/auto/addons,/app/data/extra-addons,/app/code/odoo/addons"
crudini --set /app/data/odoo.conf 'options' data_dir "/app/data/odoo"
# Logging
@ -61,7 +64,6 @@ crudini --set /app/data/odoo.conf 'options' port '8069'
crudini --set /app/data/odoo.conf 'options' longpolling_port '8072'
# Securing Odoo
crudini --set /app/data/odoo.conf 'options' list_db "False"
crudini --set /app/data/odoo.conf 'options' test_enable "False"
crudini --set /app/data/odoo.conf 'options' test_file "False"
crudini --set /app/data/odoo.conf 'options' test_report_directory "False"
@ -93,7 +95,7 @@ if [[ -z "${CLOUDRON_MAIL_SMTP_SERVER+x}" ]]; then
pg_cli "UPDATE public.ir_mail_server SET active='f' WHERE name LIKE 'Cloudron%';"
else
echo "SMTP is enabled. Adding values to config."
pg_cli "INSERT INTO public.ir_mail_server (id, name, from_filter, smtp_host, smtp_port, smtp_authentication, smtp_user, smtp_pass, smtp_encryption, smtp_ssl_certificate, smtp_ssl_private_key, smtp_debug, sequence, active, create_uid, create_date, write_uid, write_date) VALUES (1, 'Cloudron SMTP Service', NULL, '$CLOUDRON_MAIL_SMTP_SERVER', $CLOUDRON_MAIL_SMTP_PORT, 'login', '$CLOUDRON_MAIL_SMTP_USERNAME', '$CLOUDRON_MAIL_SMTP_PASSWORD', 'none', NULL, NULL, false, 10, true, 2, 'NOW()', 2, 'NOW()') ON CONFLICT (id) DO NOTHING;"
pg_cli "INSERT INTO public.ir_mail_server (id, name, smtp_host, smtp_port, smtp_user, smtp_pass, smtp_encryption, smtp_debug, sequence, active, create_uid, create_date, write_uid, write_date) VALUES (1, 'Cloudron SMTP Service', '$CLOUDRON_MAIL_SMTP_SERVER', $CLOUDRON_MAIL_SMTP_PORT, '$CLOUDRON_MAIL_SMTP_USERNAME', '$CLOUDRON_MAIL_SMTP_PASSWORD', 'none', false, 10, true, 2, 'NOW()', 2, 'NOW()') ON CONFLICT (id) DO NOTHING;"
fi
# LDAP Configuration
@ -147,4 +149,4 @@ echo "Done. Starting server with $worker_count workers.."
chown -R cloudron:cloudron /app/data/
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo-bin -c /app/data/odoo.conf
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo/odoo-bin -c /app/data/odoo.conf
Loading…
Cancel
Save