mirror of
https://github.com/tcsenpai/deu.git
synced 2025-06-03 10:10:10 +00:00
global configs
This commit is contained in:
parent
546ffb5f10
commit
6a460d16cf
59
README.md
59
README.md
@ -1,62 +1,67 @@
|
||||
# deu (Docker Environment Utility)
|
||||
# DEU - Docker Environment Utility
|
||||
|
||||
A simple utility to create and manage development containers.
|
||||
A simple utility to create and manage development containers using Docker Compose.
|
||||
|
||||
## Overview
|
||||
|
||||
deu helps you quickly set up development containers with a consistent configuration. It creates a Docker Compose setup and manages container lifecycle.
|
||||
`deu` helps you quickly set up development environments in Docker containers. It creates a Docker Compose configuration and manages container states (start, stop, logs, etc.).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Make the script executable
|
||||
chmod +x deu.py
|
||||
|
||||
# Optionally, create a symlink
|
||||
ln -s $(pwd)/deu.py /usr/local/bin/deu
|
||||
|
||||
# Or copy it
|
||||
|
||||
cp $(pwd)/deu.py /usr/local/bin/deu
|
||||
sudo ln -s $(pwd)/deu.py /usr/local/bin/deu
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Initialize a container
|
||||
### Initialize a Container
|
||||
|
||||
Create a new development container:
|
||||
|
||||
```bash
|
||||
# Initialize with a random service name
|
||||
deu init .container --image python:3.11
|
||||
# Local container (in current directory)
|
||||
deu init --image ubuntu:24.04
|
||||
|
||||
# Initialize with a specific service name
|
||||
deu init .container --image python:3.11 --service my_service
|
||||
# Global container (stored in ~/.config/deu/)
|
||||
deu init -g --image ubuntu:24.04
|
||||
|
||||
# With custom service name
|
||||
deu init --image ubuntu:24.04 --service my_container
|
||||
```
|
||||
|
||||
### Container Management
|
||||
### Manage Containers
|
||||
|
||||
All commands support both local and global containers:
|
||||
|
||||
```bash
|
||||
# Start container in background
|
||||
deu background
|
||||
|
||||
# Activate container shell
|
||||
deu activate
|
||||
deu activate # Use local container
|
||||
deu activate my_container # Use specific container (local or global)
|
||||
|
||||
# Start container in background
|
||||
deu background # Use local container
|
||||
deu background my_container
|
||||
|
||||
# View container logs
|
||||
deu logs
|
||||
deu logs # Use local container
|
||||
deu logs my_container
|
||||
|
||||
# Stop container
|
||||
deu stop
|
||||
deu stop # Use local container
|
||||
deu stop my_container
|
||||
|
||||
# Remove container
|
||||
deu rm
|
||||
deu rm # Use local container
|
||||
deu rm my_container
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
deu creates two configuration files:
|
||||
`deu` creates two configuration files:
|
||||
|
||||
1. `.container/docker-compose.yml`: Docker Compose configuration
|
||||
2. `deu.toml`: Container metadata and settings
|
||||
1. `deu.toml` - Container configuration (local or in ~/.config/deu/)
|
||||
2. `.container/docker-compose.yml` - Docker Compose configuration (local or in ~/.config/deu/.container_name/)
|
||||
|
||||
## Requirements
|
||||
|
||||
|
256
deu.py
256
deu.py
@ -199,60 +199,66 @@ def get_container_config() -> ContainerConfig:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def handle_activate() -> None:
|
||||
"""Activate the container shell."""
|
||||
config = get_container_config()
|
||||
print(f"Trying to activate container shell for service '{config.service}'...")
|
||||
|
||||
# Check if container is running, start it if not
|
||||
try:
|
||||
ps_output = subprocess.run(
|
||||
["docker", "compose", "-f", str(config.path / "docker-compose.yml"), "ps"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if config.service not in ps_output.stdout:
|
||||
logger.info(f"Container '{config.service}' is not running. Starting it...")
|
||||
run_docker_compose_command(config.path, "up -d")
|
||||
except subprocess.CalledProcessError:
|
||||
logger.info(f"Container '{config.service}' is not running. Starting it...")
|
||||
run_docker_compose_command(config.path, "up -d")
|
||||
|
||||
# Use appropriate shell based on configuration
|
||||
shell = "bash" if config.shell == ShellType.BASH else "sh"
|
||||
run_docker_compose_command(config.path, f"exec {config.service} {shell}")
|
||||
def get_global_config_dir() -> Path:
|
||||
"""Get the global configuration directory."""
|
||||
return Path.home() / ".config" / "deu"
|
||||
|
||||
|
||||
def handle_background() -> None:
|
||||
"""Start the container in background mode."""
|
||||
container_path = get_container_config().path
|
||||
run_docker_compose_command(container_path, "up", detach=True)
|
||||
def find_container_config(
|
||||
container_name: Optional[str] = None,
|
||||
) -> Optional[ContainerConfig]:
|
||||
"""Find container configuration, checking local then global."""
|
||||
# If container name is provided, search for it
|
||||
if container_name:
|
||||
# First check local deu.toml
|
||||
local_toml = Path.cwd() / "deu.toml"
|
||||
if local_toml.exists():
|
||||
try:
|
||||
config = toml.loads(local_toml.read_text())
|
||||
if config["container"]["service"] == container_name:
|
||||
return get_container_config()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Then check global configs
|
||||
global_dir = get_global_config_dir()
|
||||
if global_dir.exists():
|
||||
for toml_file in global_dir.glob("*.toml"):
|
||||
try:
|
||||
config = toml.loads(toml_file.read_text())
|
||||
if config["container"]["service"] == container_name:
|
||||
return ContainerConfig(
|
||||
path=Path(config["container"]["path"]),
|
||||
service=config["container"]["service"],
|
||||
image=config["container"]["image"],
|
||||
shell=ShellType[config["container"]["shell"]],
|
||||
)
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
# If no container name, just check local deu.toml
|
||||
local_toml = Path.cwd() / "deu.toml"
|
||||
if local_toml.exists():
|
||||
return get_container_config()
|
||||
return None
|
||||
|
||||
|
||||
def handle_logs() -> None:
|
||||
"""Show container logs."""
|
||||
container_path = get_container_config().path
|
||||
run_docker_compose_command(container_path, "logs -f")
|
||||
|
||||
|
||||
def handle_stop() -> None:
|
||||
"""Stop the container."""
|
||||
container_path = get_container_config().path
|
||||
run_docker_compose_command(container_path, "stop")
|
||||
|
||||
|
||||
def handle_rm() -> None:
|
||||
"""Remove the container."""
|
||||
container_path = get_container_config().path
|
||||
run_docker_compose_command(container_path, "down")
|
||||
|
||||
|
||||
def create_dev_container(path: str, image: str, service_name: str) -> None:
|
||||
def create_dev_container(
|
||||
path: str, image: str, service_name: str, is_global: bool = False
|
||||
) -> None:
|
||||
"""Create a development container configuration."""
|
||||
try:
|
||||
container_path = Path(path)
|
||||
validate_path(container_path)
|
||||
if is_global:
|
||||
# Create global config directory first
|
||||
global_dir = get_global_config_dir()
|
||||
global_dir.mkdir(parents=True, exist_ok=True)
|
||||
container_path = global_dir / f".{service_name}"
|
||||
toml_path = global_dir / f"{service_name}.toml"
|
||||
else:
|
||||
container_path = Path(path)
|
||||
toml_path = Path.cwd() / "deu.toml"
|
||||
|
||||
validate_image(image)
|
||||
|
||||
# Ensure image exists and detect shell
|
||||
@ -264,7 +270,7 @@ def create_dev_container(path: str, image: str, service_name: str) -> None:
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# Create the container directory if it doesn't exist
|
||||
# Create the container directory
|
||||
container_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create configurations
|
||||
@ -278,7 +284,7 @@ def create_dev_container(path: str, image: str, service_name: str) -> None:
|
||||
|
||||
# Write configurations
|
||||
write_config(container_path / "docker-compose.yml", compose_config, "yaml")
|
||||
write_config(Path.cwd() / "deu.toml", toml_config, "toml")
|
||||
write_config(toml_path, toml_config, "toml")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create development container: {e}")
|
||||
@ -302,6 +308,96 @@ def generate_service_name() -> str:
|
||||
return f"{random.choice(adjectives)}_{random.choice(nouns)}_{random_number}"
|
||||
|
||||
|
||||
def handle_activate(container_name: Optional[str] = None) -> None:
|
||||
"""Activate the container shell."""
|
||||
config = find_container_config(container_name)
|
||||
if not config:
|
||||
if container_name:
|
||||
logger.error(f"Container '{container_name}' not found locally or globally.")
|
||||
else:
|
||||
logger.error(
|
||||
"No local container configuration found. Run 'deu init' first or specify a container name."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Trying to activate container shell for service '{config.service}'...")
|
||||
|
||||
# Check if container is running, start it if not
|
||||
try:
|
||||
ps_output = subprocess.run(
|
||||
["docker", "compose", "-f", str(config.path / "docker-compose.yml"), "ps"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if config.service not in ps_output.stdout:
|
||||
logger.info(f"Container '{config.service}' is not running. Starting it...")
|
||||
run_docker_compose_command(config.path, "up -d")
|
||||
except subprocess.CalledProcessError:
|
||||
logger.info(f"Container '{config.service}' is not running. Starting it...")
|
||||
run_docker_compose_command(config.path, "up -d")
|
||||
|
||||
# Use appropriate shell based on configuration
|
||||
shell = "bash" if config.shell == ShellType.BASH else "sh"
|
||||
run_docker_compose_command(config.path, f"exec {config.service} {shell}")
|
||||
|
||||
|
||||
def handle_background(container_name: Optional[str] = None) -> None:
|
||||
"""Start the container in background mode."""
|
||||
config = find_container_config(container_name)
|
||||
if not config:
|
||||
if container_name:
|
||||
logger.error(f"Container '{container_name}' not found locally or globally.")
|
||||
else:
|
||||
logger.error(
|
||||
"No local container configuration found. Run 'deu init' first or specify a container name."
|
||||
)
|
||||
sys.exit(1)
|
||||
run_docker_compose_command(config.path, "up", detach=True)
|
||||
|
||||
|
||||
def handle_logs(container_name: Optional[str] = None) -> None:
|
||||
"""Show container logs."""
|
||||
config = find_container_config(container_name)
|
||||
if not config:
|
||||
if container_name:
|
||||
logger.error(f"Container '{container_name}' not found locally or globally.")
|
||||
else:
|
||||
logger.error(
|
||||
"No local container configuration found. Run 'deu init' first or specify a container name."
|
||||
)
|
||||
sys.exit(1)
|
||||
run_docker_compose_command(config.path, "logs -f")
|
||||
|
||||
|
||||
def handle_stop(container_name: Optional[str] = None) -> None:
|
||||
"""Stop the container."""
|
||||
config = find_container_config(container_name)
|
||||
if not config:
|
||||
if container_name:
|
||||
logger.error(f"Container '{container_name}' not found locally or globally.")
|
||||
else:
|
||||
logger.error(
|
||||
"No local container configuration found. Run 'deu init' first or specify a container name."
|
||||
)
|
||||
sys.exit(1)
|
||||
run_docker_compose_command(config.path, "stop")
|
||||
|
||||
|
||||
def handle_rm(container_name: Optional[str] = None) -> None:
|
||||
"""Remove the container."""
|
||||
config = find_container_config(container_name)
|
||||
if not config:
|
||||
if container_name:
|
||||
logger.error(f"Container '{container_name}' not found locally or globally.")
|
||||
else:
|
||||
logger.error(
|
||||
"No local container configuration found. Run 'deu init' first or specify a container name."
|
||||
)
|
||||
sys.exit(1)
|
||||
run_docker_compose_command(config.path, "down")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Main entry point for the script."""
|
||||
parser = argparse.ArgumentParser(
|
||||
@ -312,35 +408,69 @@ def main() -> None:
|
||||
|
||||
# Init command
|
||||
init_parser = subparsers.add_parser("init", help="Initialize a new container")
|
||||
init_parser.add_argument("path", help="Path to the .container directory")
|
||||
init_parser.add_argument("path", nargs="?", help="Path to the .container directory")
|
||||
init_parser.add_argument("--image", required=True, help="Docker image to use")
|
||||
init_parser.add_argument(
|
||||
"--service",
|
||||
default=generate_service_name(),
|
||||
help="Name of the container service",
|
||||
)
|
||||
init_parser.add_argument(
|
||||
"-g",
|
||||
"--global",
|
||||
dest="is_global",
|
||||
action="store_true",
|
||||
help="Create container in global config",
|
||||
)
|
||||
|
||||
# Other commands
|
||||
subparsers.add_parser("activate", help="Activate container shell")
|
||||
subparsers.add_parser("background", help="Start container in background")
|
||||
subparsers.add_parser("logs", help="Show container logs")
|
||||
subparsers.add_parser("stop", help="Stop container")
|
||||
subparsers.add_parser("rm", help="Remove container")
|
||||
# Activate command
|
||||
activate_parser = subparsers.add_parser("activate", help="Activate container shell")
|
||||
activate_parser.add_argument(
|
||||
"container_name", nargs="?", help="Name of the container to activate"
|
||||
)
|
||||
|
||||
# Background command
|
||||
background_parser = subparsers.add_parser(
|
||||
"background", help="Start container in background"
|
||||
)
|
||||
background_parser.add_argument(
|
||||
"container_name", nargs="?", help="Name of the container to start"
|
||||
)
|
||||
|
||||
# Logs command
|
||||
logs_parser = subparsers.add_parser("logs", help="Show container logs")
|
||||
logs_parser.add_argument(
|
||||
"container_name", nargs="?", help="Name of the container to show logs for"
|
||||
)
|
||||
|
||||
# Stop command
|
||||
stop_parser = subparsers.add_parser("stop", help="Stop container")
|
||||
stop_parser.add_argument(
|
||||
"container_name", nargs="?", help="Name of the container to stop"
|
||||
)
|
||||
|
||||
# Remove command
|
||||
rm_parser = subparsers.add_parser("rm", help="Remove container")
|
||||
rm_parser.add_argument(
|
||||
"container_name", nargs="?", help="Name of the container to remove"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "init":
|
||||
create_dev_container(args.path, args.image, args.service)
|
||||
create_dev_container(
|
||||
args.path or ".container", args.image, args.service, args.is_global
|
||||
)
|
||||
elif args.command == "activate":
|
||||
handle_activate()
|
||||
handle_activate(args.container_name)
|
||||
elif args.command == "background":
|
||||
handle_background()
|
||||
handle_background(args.container_name)
|
||||
elif args.command == "logs":
|
||||
handle_logs()
|
||||
handle_logs(args.container_name)
|
||||
elif args.command == "stop":
|
||||
handle_stop()
|
||||
handle_stop(args.container_name)
|
||||
elif args.command == "rm":
|
||||
handle_rm()
|
||||
handle_rm(args.container_name)
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user