feat(volume): add the possibilty to mount local directory into the container (like docker volume)

This commit is contained in:
2025-03-11 15:58:13 -06:00
parent 092f497ecc
commit b72f1eef9a
3 changed files with 62 additions and 4 deletions

View File

@@ -46,6 +46,10 @@ mc session create --driver goose
# Create a session with environment variables
mc session create -e VAR1=value1 -e VAR2=value2
# Mount custom volumes (similar to Docker's -v flag)
mc session create -v /local/path:/container/path
mc session create -v ~/data:/data -v ./configs:/etc/app/config
# Shorthand for creating a session with a project repository
mc github.com/username/repo
```

View File

@@ -109,6 +109,9 @@ def create_session(
env: List[str] = typer.Option(
[], "--env", "-e", help="Environment variables (KEY=VALUE)"
),
volume: List[str] = typer.Option(
[], "--volume", "-v", help="Mount volumes (LOCAL_PATH:CONTAINER_PATH)"
),
name: Optional[str] = typer.Option(None, "--name", "-n", help="Session name"),
no_connect: bool = typer.Option(
False, "--no-connect", help="Don't automatically connect to the session"
@@ -139,6 +142,29 @@ def create_session(
f"[yellow]Warning: Ignoring invalid environment variable format: {var}[/yellow]"
)
# Parse volume mounts
volume_mounts = {}
for vol in volume:
if ":" in vol:
local_path, container_path = vol.split(":", 1)
# Convert to absolute path if relative
if not os.path.isabs(local_path):
local_path = os.path.abspath(local_path)
# Validate local path exists
if not os.path.exists(local_path):
console.print(
f"[yellow]Warning: Local path '{local_path}' does not exist. Volume will not be mounted.[/yellow]"
)
continue
# Add to volume mounts
volume_mounts[local_path] = {"bind": container_path, "mode": "rw"}
else:
console.print(
f"[yellow]Warning: Ignoring invalid volume format: {vol}. Use LOCAL_PATH:CONTAINER_PATH.[/yellow]"
)
with console.status(f"Creating session with driver '{driver}'..."):
session = container_manager.create_session(
driver_name=driver,
@@ -146,6 +172,7 @@ def create_session(
environment=environment,
session_name=name,
mount_local=not no_mount and user_config.get("defaults.mount_local", True),
volumes=volume_mounts,
)
if session:
@@ -284,6 +311,9 @@ def quick_create(
env: List[str] = typer.Option(
[], "--env", "-e", help="Environment variables (KEY=VALUE)"
),
volume: List[str] = typer.Option(
[], "--volume", "-v", help="Mount volumes (LOCAL_PATH:CONTAINER_PATH)"
),
name: Optional[str] = typer.Option(None, "--name", "-n", help="Session name"),
no_connect: bool = typer.Option(
False, "--no-connect", help="Don't automatically connect to the session"
@@ -303,6 +333,7 @@ def quick_create(
driver=driver,
project=project,
env=env,
volume=volume,
name=name,
no_connect=no_connect,
no_mount=no_mount,

View File

@@ -125,6 +125,7 @@ class ContainerManager:
environment: Optional[Dict[str, str]] = None,
session_name: Optional[str] = None,
mount_local: bool = True,
volumes: Optional[Dict[str, Dict[str, str]]] = None,
) -> Optional[Session]:
"""Create a new MC session
@@ -134,6 +135,7 @@ class ContainerManager:
environment: Optional environment variables
session_name: Optional session name
mount_local: Whether to mount the current directory to /app
volumes: Optional additional volumes to mount (dict of {host_path: {"bind": container_path, "mode": mode}})
"""
try:
# Validate driver exists
@@ -178,25 +180,46 @@ class ContainerManager:
self.client.images.pull(driver.image)
# Set up volume mounts
volumes = {}
session_volumes = {}
# If project URL is provided, don't mount local directory (will clone into /app)
# If no project URL and mount_local is True, mount local directory to /app
if not project and mount_local:
# Mount current directory to /app in the container
current_dir = os.getcwd()
volumes[current_dir] = {"bind": "/app", "mode": "rw"}
session_volumes[current_dir] = {"bind": "/app", "mode": "rw"}
print(f"Mounting local directory {current_dir} to /app")
elif project:
print(
f"Project URL provided - container will clone {project} into /app during initialization"
)
# Add user-specified volumes
if volumes:
for host_path, mount_spec in volumes.items():
container_path = mount_spec["bind"]
# Check for conflicts with /app mount
if container_path == "/app" and not project and mount_local:
print(
"[yellow]Warning: Volume mount to /app conflicts with automatic local directory mount. User-specified mount takes precedence.[/yellow]"
)
# Remove the automatic mount if there's a conflict
if current_dir in session_volumes:
del session_volumes[current_dir]
# Add the volume
session_volumes[host_path] = mount_spec
print(f"Mounting volume: {host_path} -> {container_path}")
# Set up persistent project configuration
project_config_path = self._get_project_config_path(project)
print(f"Using project configuration directory: {project_config_path}")
# Mount the project configuration directory
volumes[str(project_config_path)] = {"bind": "/mc-config", "mode": "rw"}
session_volumes[str(project_config_path)] = {
"bind": "/mc-config",
"mode": "rw",
}
# Add environment variables for config path
env_vars["MC_CONFIG_DIR"] = "/mc-config"
@@ -230,7 +253,7 @@ class ContainerManager:
tty=True,
stdin_open=True,
environment=env_vars,
volumes=volumes,
volumes=session_volumes,
labels={
"mc.session": "true",
"mc.session.id": session_id,