{"id":24200101,"url":"https://github.com/lesiw/ctrctl","last_synced_at":"2025-09-21T23:32:28.830Z","repository":{"id":190324064,"uuid":"682383831","full_name":"lesiw/ctrctl","owner":"lesiw","description":"A Go wrapper for container CLIs (docker, nerdctl, podman, buildah, etc.)","archived":false,"fork":false,"pushed_at":"2024-04-09T20:07:13.000Z","size":324,"stargazers_count":13,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-08-03T09:05:51.393Z","etag":null,"topics":["buildah","containerd","containers","docker","go","golang","nerdctl","podman"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lesiw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-24T03:59:44.000Z","updated_at":"2023-11-10T19:55:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"a31906ab-73b6-4e24-8766-7d6924701d07","html_url":"https://github.com/lesiw/ctrctl","commit_stats":null,"previous_names":["lesiw/ctrctl"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lesiw%2Fctrctl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lesiw%2Fctrctl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lesiw%2Fctrctl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lesiw%2Fctrctl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lesiw","download_url":"https://codeload.github.com/lesiw/ctrctl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233808214,"owners_count":18733541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["buildah","containerd","containers","docker","go","golang","nerdctl","podman"],"created_at":"2025-01-13T20:41:06.702Z","updated_at":"2025-09-21T23:32:23.513Z","avatar_url":"https://github.com/lesiw.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ctrctl\n\n[![Go Reference](https://pkg.go.dev/badge/lesiw.io/ctrctl.svg)](https://pkg.go.dev/lesiw.io/ctrctl)\n\nPackage `ctrctl` wraps container CLIs.\n\n## Example\n\n```go\npackage main\n\nimport \"lesiw.io/ctrctl\"\n\nfunc main() {\n    ctrctl.Cli = []string{\"docker\"} // or {\"podman\"}, or {\"lima\", \"nerdctl\"}...\n\n    id, err := ctrctl.ContainerRun(\n        \u0026ctrctl.ContainerRunOpts{\n            Detach: true,\n            Tty:    true,\n        },\n        \"alpine\",\n        \"cat\",\n    )\n    if err != nil {\n        panic(err)\n    }\n\n    out, err := ctrctl.ContainerExec(nil, id, \"echo\", \"Hello from alpine!\")\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(out)\n\n    _, err = ctrctl.ContainerRm(\u0026ctrctl.ContainerRmOpts{Force: true}, id)\n    if err != nil {\n        panic(err)\n    }\n}\n```\n\n## Motivation\n\nMost container engines ship alongside a CLI that provides an experience similar\nto that of Docker on Linux. In the pursuit of this goal, they often hide several\nlayers of indirection through internal APIs and VM boundaries while maintaining\nargument-for-argument compatibility with the [Docker\nCLI](https://docs.docker.com/engine/reference/commandline/cli/).\n\nSince the CLI is the primary interface that users and automation scripts\ninteract with, it’s also the most likely interface where bugs will be noticed\nand, hopefully, fixed. Conversely, the primary consumer of engines’ internal\nAPIs are their own command lines and a handful of plugins, so issues and\ndocumentation gaps in the API layer are less likely to be noticed and\nprioritized.\n\nFor these reasons, Docker-compatible CLIs serve as excellent abstraction points\nfor projects that manage containers. `docker`, `nerdctl`, `podman`, and even\n`kubectl` have more in common with one another than any of their internal APIs\nor SDKs do. However, working with `exec.Command` is verbose and lacks in-editor\ncompletion for container commands.\n\n`ctrctl` fills this gap by providing CLI wrapper functions and option structs\nautomatically generated from the\n[Dockermentation](https://github.com/docker/docs). While no container engine\nimplements Docker’s entire interface, generating `ctrctl` wrappers from Docker\nensures that all potential shared functionality will be covered.\n\nTo switch between `docker` and other Docker-compatible CLIs, just set\n`ctrctl.Cli` to the appropriate value.\n\n## Simple usage\n\nAll wrapper functions take an optional struct as the first argument. The format\nof the option struct is always `CommandOpts`, where `Command` is the name of the\nfunction being called.\n\nCommands return a `string` containing stdout and an optional `error`. `error`\nmay be of type `ctrctl.CliError`, which contains a `Stderr` field for debugging\npurposes.\n\nSet `ctrctl.Verbose = true` to stream the exact commands being run, along with\ntheir output, to standard out. The format is similar to using `set +x` in a\nshell script.\n\n## Advanced usage\n\nAll wrapper functions’ options structs have a `Cmd` field. Set this to an\n`\u0026exec.Cmd` to override the default command behavior.\n\nNote that setting `Cmd.Stdout` or `Cmd.Stderr` to an `io.Writer` will disable\nautomatic capture of those outputs. Bypassing capture allows the underlying\ncontainer CLI to work in interactive mode when they are attached to `os.Stdout`\nand `os.Stderr`, respectively.\n\nIn this example, standard streams are overridden to expose the output of the\n`ImagePull` to the end user, then drop them into an interactive shell in an\n`alpine` container. Once they exit the shell, the container is removed.\n\n```go\npackage main\n\nimport (\n    \"os\"\n    \"os/exec\"\n\n    \"lesiw.io/ctrctl\"\n)\n\nfunc main() {\n    _, err := ctrctl.ImagePull(\n        \u0026ctrctl.ImagePullOpts{\n            Cmd: \u0026exec.Cmd{\n                Stdout: os.Stdout,\n                Stderr: os.Stderr,\n            },\n        },\n        \"alpine:latest\",\n    )\n    if err != nil {\n        panic(err)\n    }\n\n    id, err := ctrctl.ContainerRun(\n        \u0026ctrctl.ContainerRunOpts{\n            Detach: true,\n            Tty:    true,\n        },\n        \"alpine\",\n        \"cat\",\n    )\n    if err != nil {\n        panic(err)\n    }\n\n    _, _ = ctrctl.ContainerExec(\n        \u0026ctrctl.ContainerExecOpts{\n            Cmd: \u0026exec.Cmd{\n                Stdin:  os.Stdin,\n                Stdout: os.Stdout,\n                Stderr: os.Stderr,\n            },\n            Interactive: true,\n            Tty:         true,\n        },\n        id,\n        \"/bin/sh\",\n    )\n\n    _, err = ctrctl.ContainerRm(\u0026ctrctl.ContainerRmOpts{Force: true}, id)\n    if err != nil {\n        panic(err)\n    }\n}\n```\n\n## Regenerating the interface\n\nInstall [`gofmt`](https://pkg.go.dev/cmd/gofmt) and\n[`goimports`](https://pkg.go.dev/golang.org/x/tools/cmd/goimports), then run `go\ngenerate ./...`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flesiw%2Fctrctl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flesiw%2Fctrctl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flesiw%2Fctrctl/lists"}