Skip to content
Merged
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
38 changes: 38 additions & 0 deletions libexec/mcserver-kit/compose-state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Classify Docker Compose's JSON container listing for the CLI and TUI."""

import json
import sys


def classify(raw: str) -> str:
raw = raw.strip()
if not raw:
return "absent"

try:
parsed = json.loads(raw)
except json.JSONDecodeError:
try:
parsed = [json.loads(line) for line in raw.splitlines()]
except json.JSONDecodeError:
return "unavailable"

if isinstance(parsed, dict):
containers = [parsed]
elif isinstance(parsed, list) and all(isinstance(item, dict) for item in parsed):
containers = parsed
else:
return "unavailable"

if any(
item.get("Service") == "minecraft"
and str(item.get("State", "")).lower() == "running"
for item in containers
):
return "running"
return "stopped" if containers else "absent"


if __name__ == "__main__":
print(classify(sys.stdin.read()))
22 changes: 1 addition & 21 deletions libexec/mcserver-kit/server-manager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,7 @@ container_state() {
printf 'unavailable\n'
return
fi
printf '%s\n' "$listing" | python3 -c '
import json
import sys

data = sys.stdin.read().strip()
if not data:
print("absent")
sys.exit()
try:
containers = json.loads(data) if data.startswith("[") else [json.loads(line) for line in data.splitlines()]
except (ValueError, TypeError):
print("unavailable")
sys.exit()
minecraft = [c for c in containers if c.get("Service") == "minecraft"]
if any(c.get("State", "").lower() == "running" for c in minecraft):
print("running")
elif containers:
print("stopped")
else:
print("absent")
'
printf '%s\n' "$listing" | python3 "${SCRIPT_DIR}/compose-state.py"
}

server_state() {
Expand Down
12 changes: 12 additions & 0 deletions tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,17 @@ CONFIG
assert_equal '600' "$(stat -c '%a' "$config_file")" 'config editor preserves restricted permissions'
}

test_compose_state_parser() {
local parser="${REPO_ROOT}/libexec/mcserver-kit/compose-state.py"
assert_equal 'absent' "$(printf '\n' | python3 "$parser")" 'empty Compose output means no containers'
assert_equal 'absent' "$(printf '[]\n' | python3 "$parser")" 'an empty Compose array means no containers'
assert_equal 'running' "$(printf '[{"Service":"minecraft","State":"running"}]\n' | python3 "$parser")" 'array output detects the running server'
assert_equal 'stopped' "$(printf '{"Service":"minecraft","State":"exited"}\n' | python3 "$parser")" 'object output detects a retained container'
assert_equal 'running' "$(printf '%s\n%s\n' '{"Service":"playit","State":"running"}' '{"Service":"minecraft","State":"running"}' | python3 "$parser")" 'newline-delimited output finds the Minecraft container'
assert_equal 'unavailable' "$(printf '{invalid\n' | python3 "$parser")" 'malformed Compose JSON is not mistaken for no container'
assert_equal 'unavailable' "$(printf '123\n' | python3 "$parser")" 'unexpected Compose JSON shapes are rejected'
}

test_server_management() {
local temp_dir="$1"
local root="${temp_dir}/server-management/servers"
Expand Down Expand Up @@ -957,6 +968,7 @@ main() {
test_setup_command "$TEST_TEMP_DIR"
test_reset_command "$TEST_TEMP_DIR"
test_config_value_editor "$TEST_TEMP_DIR"
test_compose_state_parser
test_server_management "$TEST_TEMP_DIR"
test_server_property_editor "$TEST_TEMP_DIR"
test_property_import_and_explorer "$TEST_TEMP_DIR"
Expand Down