Skip to content

Feat/native volumes#106

Open
w1zdun wants to merge 2 commits into
Mcrich23:mainfrom
w1zdun:feat/NativeVolumes
Open

Feat/native volumes#106
w1zdun wants to merge 2 commits into
Mcrich23:mainfrom
w1zdun:feat/NativeVolumes

Conversation

@w1zdun

@w1zdun w1zdun commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Named volumes were emulated as host directories under ~/.containers/Volumes/... bind-mounted via virtiofs. Containers whose entrypoint chowns its data directory (MySQL,
Postgres, most databases) die on virtiofs (chown: Operation not permitted). Apple container ≥ 0.12 supports volumes natively, exposed by the pinned dependency via
ClientVolume.

Changes:

  • Top-level volumes: are created as native volumes named <project>_<key> (docker compose naming parity); external: true volumes are never created; explicit name: is
    honored. Creation is idempotent — existing volumes are detected via ClientVolume.list() and an "already exists" error from create is tolerated.
  • Named volumes referenced by services but not declared top-level are created on demand (docker compose errors here; this tool has historically been tolerant, so that behavior
    is kept).
  • composeVolumeToRunArgs passes -v <nativeName>:<destination>[:mode] for named volumes — this also fixes a pre-existing bug where the named-volume branch mounted the
    parent of the destination (deletingLastPathComponent). Bind-mount behavior is byte-for-byte unchanged, covered by the existing tests.
  • New down -v/--volumes flag removes the project's named volumes (including on-demand ones, skipping external). Containers are removed first, since a volume cannot be
    deleted while a container references it — matching docker compose down, which always removes containers.

Note: unlike docker, Apple container does not populate a freshly created volume from the image's directory content — that is a runtime limitation, not addressed here.

w1zdun and others added 2 commits June 7, 2026 12:17
Named volumes were previously emulated by bind-mounting host directories
under ~/.containers/Volumes/<project>/, which breaks containers whose
entrypoint chowns its data directory (virtiofs forbids chown — e.g.
mysql dies with 'changing ownership of /data: Operation not permitted').

The container CLI (>= 0.12) supports volumes natively, so:
- top-level 'volumes:' entries are created via ClientVolume.create with
  docker-compose naming (<project>_<key>, explicit 'name:' verbatim,
  'external:' never created), idempotently
- named volume references in services mount as -v <nativeName>:<dest>,
  fixing a bug where the destination's parent directory was mounted
  instead of the destination itself
- named volumes referenced by services but not declared top-level are
  created on demand (docker compose errors here; this tool stays
  tolerant)
- 'down -v/--volumes' removes the project's named volumes (and the
  containers, since a referenced volume cannot be deleted), skipping
  external ones

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR switches named-volume handling from “emulated host directories under ~/.containers/Volumes/... bind-mounted via virtiofs” to native Apple container volumes, addressing virtiofs chown failures for common database images and adding down -v/--volumes support to remove project volumes.

Changes:

  • Add named-volume classification + Docker Compose–style name resolution (<project>_<key>, honor name:, skip creation/removal for external: true).
  • Update composeVolumeToRunArgs to emit -v <nativeName>:<destination>[:mode] for named volumes (and fix destination-parent mounting bug).
  • Add down -v/--volumes parsing and implementation to remove the project’s named volumes (including on-demand ones).

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Tests/Container-Compose-StaticTests/HelperFunctionsTests.swift Updates volume arg tests for new signature and adds coverage for named-volume mapping + resolution helpers.
Tests/Container-Compose-StaticTests/ComposeBuildParsingTests.swift Adds CLI parsing tests for ComposeDown -v/--volumes.
Sources/Container-Compose/Helper Functions.swift Introduces named-volume detection + resolution and updates volume-to-run-args generation to use native volumes.
Sources/Container-Compose/Commands/ComposeUp.swift Creates native volumes up-front and on-demand; maintains a mapping used when building container run args.
Sources/Container-Compose/Commands/ComposeDown.swift Adds -v/--volumes and implements named-volume removal logic.
.gitignore Ignores /tmp/.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +144 to +155
// Also remove named volumes that `up` created on demand for service
// references not declared top-level.
for (_, service) in services {
for volume in service.volumes ?? [] {
guard let source = volume.split(separator: ":", maxSplits: 2).map(String.init).first,
isNamedVolumeSource(source), !handledKeys.contains(source)
else { continue }
handledKeys.insert(source)
let (nativeName, _) = resolveNamedVolume(key: source, config: nil, projectName: projectName)
await removeNamedVolume(key: source, name: nativeName)
}
}
@Argument(help: "Specify the services to stop")
var services: [String] = []

@Flag(name: [.customShort("v"), .customLong("volumes")], help: "Remove named volumes declared in the compose file")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants