[ADD] Add shell command
To jump in an odoo shell on an instance already started using odoo run
This commit is contained in:
parent
cad882d58b
commit
5a854287c7
|
|
@ -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)
|
||||
|
|
|
|||
107
odoo_openupgrade_wizard/cli/cli_shell.py
Normal file
107
odoo_openupgrade_wizard/cli/cli_shell.py
Normal 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)
|
||||
79
tests/cli_33_shell_test.py
Normal file
79
tests/cli_33_shell_test.py
Normal 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)"',
|
||||
]
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user