import os import subprocess import sys import click import docker from loguru import logger from odoo_openupgrade_wizard.cli.cli_options import ( database_option_required, get_migration_step_from_options, step_option, ) from odoo_openupgrade_wizard.tools.tools_odoo import ( generate_odoo_command_options, ) from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database @click.command() @step_option @database_option_required @click.option( "--code", default=None, help="Python code to execute in the Odoo shell. " "Example: 'print(env.user.name)'", ) @click.pass_context def shell(ctx, step, database, code): """Run an Odoo shell in the running Odoo container.""" migration_step = get_migration_step_from_options(ctx, step) ensure_database(ctx, database, state="present") config = ctx.obj.get("config", {}) project_name = config.get("project_name") if not project_name: click.echo("Unable to find the project name.") sys.exit(1) expected_container_name_prefix = f"oow-{project_name}-{database}" # Connect to the Docker daemon docker_client = docker.from_env() # List all running containers running_containers = docker_client.containers.list( filters={"status": "running"} ) # Find the running Odoo container matching_container = next( ( c for c in running_containers if expected_container_name_prefix in c.name and "step" in c.name ), None, ) if not matching_container: logger.error( "No running Odoo container found. " "Please run oow run before running the shell." ) sys.exit(1) logger.info(f"Execute shell in {matching_container.name} container...") common_options = generate_odoo_command_options( ctx, migration_step, "regular", database ) # Build the docker exec command command = [ "docker", "exec", "-i", # Interactive mode to enable stdin matching_container.name, "/odoo_env/src/odoo/odoo-bin", "shell", "--no-http", ] + common_options logger.info(f"Command: {' '.join(command)}") # If code is provided, send it via stdin if code: logger.info(f"Executing code: {code}") process = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, # Enables text mode ) stdout, stderr = process.communicate(code) if process.returncode != 0: logger.error(f"Error executing code: {stderr}") sys.exit(1) else: click.echo(stdout) else: # Interactive session requires TTY command.insert(2, "-t") os.execvp(command[0], command)