[ADD] Add shell command

To jump in an odoo shell on an instance already started using odoo run
This commit is contained in:
Simon Maillard 2024-12-05 09:24:25 +00:00
parent cad882d58b
commit 5a854287c7
3 changed files with 188 additions and 0 deletions

View File

@ -31,6 +31,7 @@ from odoo_openupgrade_wizard.cli.cli_psql import psql
from odoo_openupgrade_wizard.cli.cli_pull_submodule import pull_submodule
from odoo_openupgrade_wizard.cli.cli_restoredb import restoredb
from odoo_openupgrade_wizard.cli.cli_run import run
from odoo_openupgrade_wizard.cli.cli_shell import shell
from odoo_openupgrade_wizard.cli.cli_upgrade import upgrade
from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_exists
@ -166,4 +167,5 @@ main.add_command(install_from_csv)
main.add_command(psql)
main.add_command(pull_submodule)
main.add_command(run)
main.add_command(shell)
main.add_command(upgrade)

View File

@ -0,0 +1,107 @@
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)

View File

@ -0,0 +1,79 @@
import pathlib
import shutil
from pytest import raises
from odoo_openupgrade_wizard.cli.cli_options import (
get_migration_step_from_options,
)
from odoo_openupgrade_wizard.tools.tools_odoo import run_odoo
from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
from . import (
build_ctx_from_config_file,
cli_runner_invoke,
move_to_test_folder,
)
def test_cli_shell():
move_to_test_folder()
ctx = build_ctx_from_config_file()
migration_step = get_migration_step_from_options(ctx, 1)
stop_after_init = False
# Ensure environment is clean
db_name = "database_test_cli___shell"
ensure_database(ctx, db_name, state="absent")
dest_filestore_path = pathlib.Path(f"./filestore/filestore/{db_name}")
shutil.rmtree(dest_filestore_path, ignore_errors=True)
# Set the log prefix
ctx.obj["log_prefix"] = "test_cli_shell"
# Initialize the database
run_odoo(
ctx,
migration_step,
database=db_name,
detached_container=not stop_after_init,
stop_after_init=stop_after_init,
init="base",
execution_context="regular",
publish_ports=False,
)
# Test that a simple script executes successfully
result = cli_runner_invoke(
[
"shell",
f"--database={db_name}",
"--step=1",
'--code="print("Hello, World!")"',
]
)
assert result.exit_code == 0
assert "Hello, World!" in result.output
# Test with a script that queries a model
result = cli_runner_invoke(
[
"shell",
f"--database={db_name}",
"--step=1",
"--code=\"print(env['res.partner'].search_count([]))\"",
]
)
assert result.exit_code == 0
assert result.output.strip().isdigit() # Should return a number
# Test with missing database
with raises(Exception):
cli_runner_invoke(
[
"shell",
"--database=nonexistent_database",
"--step=1",
'--script="print(env.user.name)"',
]
)