# HG changeset patch
# User Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>
# Date 1605026132 -3600
#      Tue Nov 10 17:35:32 2020 +0100
# Node ID 9bdab72a5b2d0fabde74c2b952aae4992fb5a592
# Parent  7caefd33faeb3f8547394b0906fd25e359299e71
✨ add a script to start postgresql container

diff --git a/NEWS.rst b/NEWS.rst
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -7,7 +7,9 @@
 
 Use semver.
 
-docker_dev_start and do_tests: use socket when starting postgresql rather than a port that might be used on the host
+docker_dev_start and do_tests: use socket when starting postgresql rather than a port that might be used on the host.
+
+Add :ref:`docker_pg.py` command to start postgres like :ref:`docker_dev_start.py` does when using ``--start-postgresql``, but without starting odoo.
 
 4.2.1
 -----
diff --git a/README.rst b/README.rst
--- a/README.rst
+++ b/README.rst
@@ -117,20 +117,37 @@
 docker_dev_start.py
 -------------------
 
-This script can be used to start an odoo from a docker but with the local addons modules mounted, and eventually a local copy of the odoo sources mounted too.
+This script starts an odoo from a docker but with the local addons modules mounted, and eventually a local copy of the odoo sources mounted too.
 
-Using it avoids having to create a virtual env for every project.
+Using it avoids having to create a virtual environment for every project.
+
+Prerequisites:
 
-Your user also needs to be in the docker group.
+- Your user needs to be in the docker group.
+- It expects the `configuration file <setup.cfg>`_ to have the following keys:
 
-It expects the configuration file (`setup.cfg`_) to have the following keys:
-
-- ``modules``: list of directories and files to include
-- …
+  ``modules``
+    list of directories and files to include
+  …
+    …
 
 When the package is installed, the executable for this script is ``docker_dev_start``.
 This is part of the docker section.
 
+docker_pg.py
+------------
+
+This script start a postgresql server the same way `docker_dev_start.py`_ does.
+
+By default it provides an interactive psql shell, but can also be used to run SQL commands, use an interactive shell or a shell command.
+
+Prerequisites:
+
+- Your user needs to be in the docker group.
+- It uses the `configuration file <setup.cfg>`_’s keys: postgresql_version.
+
+This is part of the docker section.
+
 docker_build.py
 ---------------
 
@@ -198,6 +215,8 @@
     postgresql extensions to install (unaccent is added automatically depending on odoo configuration)
 load-language
     languages to install into a newly created database
+postgresql_version
+    version of postgresql to use. defaults to 9.6.
 
 Completion files for zsh
 ========================
@@ -219,7 +238,7 @@
 
 Generate completion file for python scripts (from the superproject for the scripts that need to be run from there, and with the required requirements too)::
 
-  for command_name in docker_dev_start docker_build docker_build_copy docker_build_clean do_tests conf2reST import_base_import import_jsonrpc import_sql docker_flake8 docker_isort ; do
+  for command_name in docker_dev_start docker_build docker_build_copy docker_build_clean do_tests conf2reST import_base_import import_jsonrpc import_sql docker_flake8 docker_isort docker_pg; do
     $command_name --help | ~/src/zsh-completion-generator/help2comp.py $command_name > ~/.local/share/zsh/completion/_$command_name
   done
 
diff --git a/odoo_scripts/docker_client.py b/odoo_scripts/docker_client.py
--- a/odoo_scripts/docker_client.py
+++ b/odoo_scripts/docker_client.py
@@ -1,9 +1,10 @@
 import logging
 import os
 import tarfile
-from typing import Dict
+from typing import Dict, List
 
 import docker
+import dockerpty
 
 _logger = logging.getLogger(__name__)
 if docker.__version__ < "3.4.0":
@@ -52,3 +53,29 @@
 
         data = open(src + ".tar", "rb").read()
         container.put_archive(os.path.dirname(dst), data)
+
+    @classmethod
+    def exec(
+        cls,
+        container: docker.models.containers.Container,
+        command: List[str],
+        user: str,
+        interactive: bool = False,
+    ) -> int:
+        """Execute a command in a container
+
+        :param container: Container to exec on
+        :param command: Command to be executed
+        :param user: User to execute command as.
+        :param interactive: True if the container needs to be interactive
+        """
+        if interactive:
+            dockerpty.exec_command(cls.client.api, container.id, command)
+            # it would be nice to return the exec command return code, but
+            # there is no way to do that apparently
+            result = 0
+        else:
+            run_result = container.exec_run(command, user=user)
+            result = run_result.exit_code
+            print(run_result.output.decode())
+        return result
diff --git a/odoo_scripts/docker_dev_start.py b/odoo_scripts/docker_dev_start.py
--- a/odoo_scripts/docker_dev_start.py
+++ b/odoo_scripts/docker_dev_start.py
@@ -30,7 +30,7 @@
 
 __version__ = "3.0.0"
 __date__ = "2017-08-11"
-__updated__ = "2020-09-15"
+__updated__ = "2020-11-10"
 
 
 def main(argv=None):  # IGNORE:C0111
@@ -75,10 +75,7 @@
     )
     parser.add_argument(
         "--name",
-        help=(
-            "If you do not assign a container name with the "
-            "--name option, then project name can be used"
-        ),
+        help="Container name to use [default: %(default)s]",
         default=project_name,
     )
     parser.add_argument(
diff --git a/odoo_scripts/docker_postgresql.py b/odoo_scripts/docker_postgresql.py
--- a/odoo_scripts/docker_postgresql.py
+++ b/odoo_scripts/docker_postgresql.py
@@ -1,17 +1,31 @@
+#!/usr/bin/env python3
 # vim: set shiftwidth=4 softtabstop=4:
+"""Run a postgresql docker with volume based on project name.
+"""
+import argparse
 import atexit
 import logging
+import os
+import sys
 import tempfile
 import time
 from typing import Callable, Tuple
 
 import docker
 
+from .config import Config
 from .docker_client import DockerClient
+from .parsing import apply, basic_parser
 
 _logger = logging.getLogger(__name__)
 
+__version__ = "1.0.0"
+__date__ = "2020-11-09"
+__updated__ = "2020-11-10"
+
 POSTGRES_PASSWORD = "this-could-be-anything"
+PSQL = "psql"
+SH = "SH"
 
 
 def docker_run_postgresql(
@@ -48,14 +62,15 @@
         #  maybe by looking at pg.status
         # TODO factorized with other methods that start dockers
         try:
-            _logger.info("Stopping postgresql")
-            # Need to stop too?
+            _logger.info("Stopping postgresql %s", pg_container.name)
             pg_container.stop()
             pg_container.wait()
-            _logger.info("Removing container postgresql")
+            _logger.info("Removing postgresql container %s", pg_container.name)
             pg_container.remove()
         except docker.errors.NotFound:
-            _logger.info("Postgresql already stopped")
+            _logger.info(
+                "Postgresql container %s already stopped", pg_container.name
+            )
         # crash because docker or pg changes the owner of the directory
         # temp_directory.cleanup()
 
@@ -90,7 +105,7 @@
         environment=env,
     )
 
-    _logger.debug("Starting postgresql container")
+    _logger.info("Starting postgresql container %s", pg.name)
     pg.start()
 
     def stop_pg():
@@ -102,3 +117,112 @@
     # give pg the time to start up
     time.sleep(5)
     return pg, stop_pg, path
+
+
+def __parser() -> argparse.ArgumentParser:
+    program_version = __version__
+    program_build_date = str(__updated__)
+    program_version_message = "%%(prog)s %s (%s)" % (
+        program_version,
+        program_build_date,
+    )
+    program_shortdesc = __doc__.split(".")[0]
+    program_license = """%s
+
+      Created by Vincent Hatakeyama on %s.
+      Copyright 2020 XCG Consulting. All rights reserved.
+
+      Licensed under the MIT License
+
+      Distributed on an "AS IS" basis without warranties
+      or conditions of any kind, either express or implied.
+
+    USAGE
+    """ % (
+        program_shortdesc,
+        str(__date__),
+    )
+    parser = basic_parser(program_license, program_version_message)
+    project_path = os.path.realpath(".")
+    project_name = os.path.basename(project_path)
+    parser.add_argument(
+        "--name",
+        help="Container name to use [default: %(default)s]",
+        default=project_name,
+    )
+    parser.add_argument(
+        "-c",
+        "--command",
+        help="Command to run. If specified the command will not be interactive"
+        ", otherwise it will be interactive.",
+        metavar="command",
+        default=None,
+    )
+    exec_group = parser.add_mutually_exclusive_group()
+    exec_group.add_argument(
+        "--psql",
+        help="Exec psql (default)",
+        action="store_const",
+        const=PSQL,
+        dest="exec",
+        default=PSQL,
+    )
+    exec_group.add_argument(
+        "--sh",
+        help="Exec a shell",
+        action="store_const",
+        const=SH,
+        dest="exec",
+    )
+    # no simple way to indicate that these options are only used with psql exec
+    parser.add_argument("-d", "--database", help="Database name", default=None)
+    parser.add_argument("-u", "--user", help="User", default=None)
+    return parser
+
+
+def main(argv=None):
+    """Run postgresql docker, and exec a psql into it
+    """
+    parser = __parser()
+    namespace = parser.parse_args(argv)
+    apply(namespace)
+    project_name = namespace.name
+    exec = namespace.exec
+    command = namespace.command
+    user = namespace.user
+    # get postgres version from config
+    c = Config()
+    postgresql_version = c.postgresql_version
+    pg, stop_pg, path = docker_run_postgresql(project_name, postgresql_version)
+    # run an exec command
+    docker_command = None
+    interactive = not bool(command)
+    if exec == PSQL:
+        if not user:
+            user = "postgres"
+        docker_command = ["psql", "--user", user]
+        if command:
+            _logger.info("Exec command in the container")
+            docker_command.extend(["-c", command])
+        else:
+            _logger.info("Exec psql in the container")
+        if namespace.database:
+            docker_command.append(namespace.database)
+        user = "root"
+    elif exec == SH:
+        if not user:
+            user = "root"
+        docker_command = ["sh"]
+        if command:
+            _logger.info("Exec shell command in the container")
+            docker_command.extend(["-c", command])
+        else:
+            _logger.info("Exec sh in the container")
+    if docker_command:
+        return DockerClient.exec(pg, docker_command, user, interactive)
+
+
+if __name__ == "__main__":
+    return_code = main(sys.argv[1:])
+    if return_code:
+        exit(return_code)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -42,6 +42,7 @@
             "docker_build_copy=odoo_scripts.docker_build_copy:main",
             "docker_flake8=odoo_scripts.docker_flake8:main [docker]",
             "docker_isort=odoo_scripts.docker_isort:main [docker]",
+            "docker_pg=odoo_scripts.docker_postgresql:main [docker]",
             "conf2reST=odoo_scripts.conf2reST:main [conf2reST]",
             "list_modules=odoo_scripts.list_modules:main",
             "update_duplicate_sources="