Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions completion/bash/podman-compose
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ _completeUpArgs() {

# complete the arguments for `podman-compose exec` and return 0
_completeExecArgs() {
exec_opts="${help_opts} -d --detach --privileged -u --user -T --index -e --env -w --workdir"
exec_opts="${help_opts} -d --detach --privileged -u --user -T --no-tty --index -e --env -w --workdir"
if [[ ${prev} == "-u" || ${prev} == "--user" || ${prev} == "--index" || ${prev} == "-e" || ${prev} == "--env" || ${prev} == "-w" || ${prev} == "--workdir" ]]; then
return 0
elif [[ ${cur} == -* ]]; then
Expand Down Expand Up @@ -237,7 +237,7 @@ _completeStartArgs() {

# complete the arguments for `podman-compose run` and return 0
_completeRunArgs() {
run_opts="${help_opts} -d --detach --privileged -u --user -T --index -e --env -w --workdir"
run_opts="${help_opts} -d --detach --privileged -u --user -T --no-tty --index -e --env -w --workdir"
if [[ ${prev} == "-u" || ${prev} == "--user" || ${prev} == "--index" || ${prev} == "-e" || ${prev} == "--env" || ${prev} == "-w" || ${prev} == "--workdir" ]]; then
return 0
elif [[ ${cur} == -* ]]; then
Expand Down Expand Up @@ -267,7 +267,7 @@ _podmanCompose() {
help_opts="-h --help"

# global options that don't take additional arguments
basic_global_opts="${help_opts} -v --no-ansi --no-cleanup --dry-run"
basic_global_opts="${help_opts} -v --no-ansi --no-cleanup --dry-run"

# global options that take paths as arguments
path_arg_global_opts="-f --file --podman-path"
Expand All @@ -291,7 +291,7 @@ _podmanCompose() {
if [[ $? -eq 0 ]]; then
return 0
fi

# computing comp_cword_adj, which thruthfully tells us how deep in the subcommands tree we are
# additionally, set the chosen_root_command if possible
comp_cword_adj=${COMP_CWORD}
Expand All @@ -309,7 +309,7 @@ _podmanCompose() {
fi
if [[ ${el} == -* && ${el} != ${cur} ]]; then
let "comp_cword_adj--"

for opt in ${arg_global_opts_array[@]}; do
if [[ ${el} == ${opt} ]]; then
skip_next="yes"
Expand All @@ -320,7 +320,7 @@ _podmanCompose() {
fi
done
fi

if [[ ${comp_cword_adj} -eq 1 ]]; then
_completeRoot

Expand Down
1 change: 1 addition & 0 deletions newsfragments/improve-no-tty-compat.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Increased compatibility with exec/run parameters `-T`, `--no-tty`, `-t`, and `-tty`, default is now detected
29 changes: 20 additions & 9 deletions podman_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -3892,7 +3892,7 @@ def compose_run_update_container_from_args(
volumes = clone(cnt.get("volumes", []))
volumes.extend(args.volume)
cnt["volumes"] = volumes
cnt["tty"] = not args.T
cnt["tty"] = args.tty
if args.cnt_command is not None and len(args.cnt_command) > 0:
cnt["command"] = args.cnt_command
# can't restart and --rm
Expand All @@ -3912,14 +3912,15 @@ async def compose_exec(compose: PodmanCompose, args: argparse.Namespace) -> None


def compose_exec_args(cnt: dict, container_name: str, args: argparse.Namespace) -> list[str]:
podman_args = ["--interactive"]
podman_args = []
if args.privileged:
podman_args += ["--privileged"]
if args.user:
podman_args += ["--user", args.user]
if args.workdir:
podman_args += ["--workdir", args.workdir]
if not args.T:
if args.tty:
podman_args += ["--interactive"]
podman_args += ["--tty"]
env = dict(cnt.get("environment", {}))
if args.env:
Expand Down Expand Up @@ -4378,11 +4379,16 @@ def compose_run_parse(parser: argparse.ArgumentParser) -> None:
action="append",
help="Bind mount a volume (can be used multiple times)",
)
parser.add_argument(
tty_parser = parser.add_mutually_exclusive_group(required=False)
tty_parser.add_argument(
"-T",
action="store_true",
help="Disable pseudo-tty allocation. By default `podman-compose run` allocates a TTY.",
"--no-tty",
dest="tty",
action="store_false",
help="Disable pseudo-TTY allocation (default: auto-detected)",
)
tty_parser.add_argument("-t", "--tty", dest="tty", action="store_true", help=argparse.SUPPRESS)
parser.set_defaults(tty=sys.stdout.isatty())
parser.add_argument(
"-w",
"--workdir",
Expand Down Expand Up @@ -4416,11 +4422,16 @@ def compose_exec_parse(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"-u", "--user", type=str, default=None, help="Run as specified username or uid"
)
parser.add_argument(
tty_parser = parser.add_mutually_exclusive_group(required=False)
tty_parser.add_argument(
"-T",
action="store_true",
help="Disable pseudo-tty allocation. By default `podman-compose run` allocates a TTY.",
"--no-tty",
dest="tty",
action="store_false",
help="Disable pseudo-TTY allocation (default: auto-detected)",
)
tty_parser.add_argument("-t", "--tty", dest="tty", action="store_true", help=argparse.SUPPRESS)
parser.set_defaults(tty=sys.stdout.isatty())
parser.add_argument(
"--index",
type=int,
Expand Down
Empty file.
3 changes: 3 additions & 0 deletions tests/integration/exec/context/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM nopush/podman-compose-test

CMD ["sleep", "120"]
6 changes: 6 additions & 0 deletions tests/integration/exec/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: "3"
services:
web1:
build:
context: ./context
dockerfile: Dockerfile
98 changes: 98 additions & 0 deletions tests/integration/exec/test_podman_compose_exec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# SPDX-License-Identifier: GPL-2.0

import os
import unittest

from tests.integration.test_utils import RunSubprocessMixin
from tests.integration.test_utils import podman_compose_path
from tests.integration.test_utils import test_path


def compose_yaml_path() -> str:
"""Returns the path to the compose file used for this test module"""
base_path = os.path.join(test_path(), "exec")
return os.path.join(base_path, "docker-compose.yml")


class TestComposeExtraHosts(unittest.TestCase, RunSubprocessMixin):
def test_exec(self) -> None:
try:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"build",
"--no-cache",
])

self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"up",
"-d",
])

# TTY auto detected (no tty)
self.run_subprocess_assert_returncode(
[
podman_compose_path(),
"-f",
compose_yaml_path(),
"exec",
"web1",
"tty",
"-s",
],
expected_returncode=1, # exit code 1 == no tty
)

# TTY auto detected (tty emulated by 'script' command)
self.run_subprocess_assert_returncode(
[
"script",
"--return",
"--quiet",
"--log-out",
"/dev/null",
"--command",
f"{podman_compose_path()} -f {compose_yaml_path()} exec web1 tty -s",
],
expected_returncode=0, # exit code 0 == tty
)

# TTY disabled (even though an emulated tty is available through the 'script' command)
self.run_subprocess_assert_returncode(
[
"script",
"--return",
"--log-out",
"/dev/null",
"--quiet",
"--command",
f"{podman_compose_path()} -f {compose_yaml_path()} exec --no-tty web1 tty -s",
],
expected_returncode=1, # exit code 1 == no tty
)

# TTY enabled (tty emulated by 'script' command)
self.run_subprocess_assert_returncode(
[
"script",
"--return",
"--log-out",
"/dev/null",
"--quiet",
"--command",
f"{podman_compose_path()} -f {compose_yaml_path()} exec --tty web1 tty -s",
],
expected_returncode=0, # exit code 0 == tty
)

finally:
self.run_subprocess_assert_returncode([
podman_compose_path(),
"-f",
compose_yaml_path(),
"down",
])
11 changes: 10 additions & 1 deletion tests/unit/test_compose_exec_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,23 @@ def test_additional_env_value_equals(self) -> None:
]
self.assertEqual(result, expected)

def test_noninteractive(self) -> None:
cnt = get_minimal_container()
args = get_minimal_args()
args.tty = False

result = compose_exec_args(cnt, "container_name", args)
expected = ["container_name"]
self.assertEqual(result, expected)


def get_minimal_container() -> dict:
return {}


def get_minimal_args() -> argparse.Namespace:
return argparse.Namespace(
T=None,
tty=True,
cnt_command=None,
env=None,
privileged=None,
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_compose_run_update_container_from_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def get_minimal_compose() -> PodmanCompose:

def get_minimal_args() -> argparse.Namespace:
return argparse.Namespace(
T=None,
tty=True,
cnt_command=None,
entrypoint=None,
env=None,
Expand Down
Loading