mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
cleanup
This commit is contained in:
parent
39a8e864b9
commit
1ec809ec8a
14 changed files with 152 additions and 241 deletions
|
|
@ -6,7 +6,7 @@ test
|
|||
.goreleaser.yml
|
||||
*.md
|
||||
coverage.txt
|
||||
Dockerfile
|
||||
Containerfile
|
||||
LICENSE
|
||||
test.sh
|
||||
.git
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
lazydocker*
|
||||
lazypodman*
|
||||
TODO.md
|
||||
Lazydocker.code-workspace
|
||||
.vscode
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ brews:
|
|||
# # apps:
|
||||
#
|
||||
# # # The name of the app must be the same name as the binary built or the snapcraft name.
|
||||
# # lazydocker:
|
||||
# # lazypodman:
|
||||
#
|
||||
# # # If your app requires extra permissions to work outside of its default
|
||||
# # # confined space, declare them here.
|
||||
|
|
|
|||
118
CLAUDE.md
118
CLAUDE.md
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
## Project Overview
|
||||
|
||||
This is a fork of **lazydocker** being converted to **lazypodman** - a terminal UI for managing Podman containers.
|
||||
This is a fork of **lazydocker** converted to **lazypodman** - a terminal UI for managing Podman containers.
|
||||
|
||||
**Goals:**
|
||||
1. Support native libpod (Podman's Go library) instead of Docker SDK
|
||||
2. Enable socket-less operation for Podman commands (no daemon required)
|
||||
|
||||
**Current State:** The codebase uses Docker Go SDK (`github.com/docker/docker` v28.5.2) and requires conversion to libpod.
|
||||
**Current State:** Conversion complete. The codebase now uses Podman bindings (`github.com/containers/podman/v5` v5.7.1) with a hybrid runtime architecture supporting both socket mode (REST API) and socket-less mode (direct libpod).
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ go build -mod=vendor
|
|||
./lazypodman -d
|
||||
|
||||
# Run with specific compose files
|
||||
./lazypodman -f docker-compose.yml -f docker-compose.override.yml
|
||||
./lazypodman -f podman-compose.yml -f podman-compose.override.yml
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
|
@ -48,78 +48,83 @@ pkg/
|
|||
└── cheatsheet/ # Keybinding reference
|
||||
```
|
||||
|
||||
### Key Files for Podman Integration
|
||||
### Key Files
|
||||
|
||||
**Primary targets for libpod conversion:**
|
||||
- `pkg/commands/docker.go` - Main client connection and initialization
|
||||
- `pkg/commands/container.go` - Container operations
|
||||
- `pkg/commands/image.go` - Image operations
|
||||
- `pkg/commands/volume.go` - Volume operations
|
||||
- `pkg/commands/network.go` - Network operations
|
||||
**Runtime abstraction layer:**
|
||||
- `pkg/commands/runtime.go` - `ContainerRuntime` interface abstracting all container operations
|
||||
- `pkg/commands/runtime_socket.go` - Socket mode implementation using Podman REST API bindings
|
||||
- `pkg/commands/runtime_libpod.go` - Direct libpod implementation (Linux+CGO only)
|
||||
- `pkg/commands/runtime_libpod_stub.go` - Stub for non-Linux platforms
|
||||
- `pkg/commands/runtime_types.go` - Custom types (ContainerSummary, ImageSummary, etc.)
|
||||
|
||||
**Podman integration:**
|
||||
- `pkg/commands/podman.go` - Main client connection, auto-detection, and initialization
|
||||
- `pkg/commands/container.go` - Container wrapper operations
|
||||
- `pkg/commands/image.go` - Image wrapper operations
|
||||
- `pkg/commands/volume.go` - Volume wrapper operations
|
||||
- `pkg/commands/network.go` - Network wrapper operations
|
||||
- `pkg/commands/service.go` - Compose service operations
|
||||
- `pkg/commands/docker_host_unix.go` - Unix socket detection
|
||||
- `pkg/commands/docker_host_windows.go` - Windows pipe detection
|
||||
- `pkg/commands/podman_host_unix.go` - Unix socket detection
|
||||
- `pkg/commands/podman_host_windows.go` - Windows pipe detection
|
||||
|
||||
**Application entry:**
|
||||
- `main.go` - Entry point, CLI flags
|
||||
- `pkg/app/app.go` - App struct, initialization flow
|
||||
|
||||
## Current Docker Integration
|
||||
## Runtime Architecture
|
||||
|
||||
### Hybrid Runtime System
|
||||
|
||||
The codebase uses a `ContainerRuntime` interface with two implementations:
|
||||
|
||||
1. **Socket Mode** (`runtime_socket.go`)
|
||||
- Uses Podman REST API via `pkg/bindings`
|
||||
- Connects to local or remote Podman instances
|
||||
- Supports SSH tunneling for remote hosts
|
||||
- Real event streaming
|
||||
|
||||
2. **Libpod Mode** (`runtime_libpod.go`)
|
||||
- Direct libpod library calls (no socket required)
|
||||
- Linux + CGO only
|
||||
- Event polling (2-second intervals)
|
||||
- Fallback when socket unavailable
|
||||
|
||||
### Connection Flow
|
||||
1. `NewDockerCommand()` in `docker.go` initializes client
|
||||
2. Docker host determined from `DOCKER_HOST` env or platform defaults
|
||||
3. Uses `github.com/docker/docker/client` SDK for API calls
|
||||
4. SSH tunneling supported for remote hosts
|
||||
1. `NewPodmanCommand()` in `podman.go` initializes runtime
|
||||
2. Host determined from `CONTAINER_HOST` env or platform defaults
|
||||
3. Tries socket mode first, falls back to libpod if unavailable
|
||||
4. Auto-detects compose tool: `podman-compose`, `podman compose`, or `docker-compose`
|
||||
|
||||
### API Methods Used
|
||||
### Runtime Interface Methods
|
||||
```go
|
||||
// Container operations
|
||||
Client.ContainerList()
|
||||
Client.ContainerInspect()
|
||||
Client.ContainerStats() // Streaming
|
||||
Client.ContainerStart/Stop/Pause/Unpause/Restart/Remove()
|
||||
Client.ContainersPrune()
|
||||
ListContainers() / InspectContainer() / ContainerStats()
|
||||
StartContainer() / StopContainer() / PauseContainer() / UnpauseContainer()
|
||||
RestartContainer() / RemoveContainer() / PruneContainers() / ContainerTop()
|
||||
|
||||
// Image operations
|
||||
Client.ImageList()
|
||||
Client.ImagesPrune()
|
||||
ListImages() / InspectImage() / ImageHistory() / RemoveImage() / PruneImages()
|
||||
|
||||
// Volume/Network
|
||||
Client.VolumeList/VolumesPrune()
|
||||
Client.NetworkList/NetworksPrune()
|
||||
ListVolumes() / RemoveVolume() / PruneVolumes()
|
||||
ListNetworks() / RemoveNetwork() / PruneNetworks()
|
||||
|
||||
// Events
|
||||
GetEvents() - Streaming (socket) or polling (libpod)
|
||||
```
|
||||
|
||||
### Command Execution Patterns
|
||||
1. **SDK calls** - For most container/image operations
|
||||
1. **Runtime interface calls** - For most container/image operations
|
||||
2. **Shell commands** - For interactive operations (attach, logs) and compose
|
||||
3. **Template-based** - Configurable command templates in config
|
||||
|
||||
## Libpod Integration Path
|
||||
## Platform Support
|
||||
|
||||
### Required Changes
|
||||
|
||||
1. **Replace Docker SDK with libpod bindings**
|
||||
- Add `github.com/containers/podman/v5/pkg/bindings` dependency
|
||||
- Replace `*client.Client` with libpod connection
|
||||
|
||||
2. **Update type mappings**
|
||||
- Docker `container.Summary` -> Podman equivalent
|
||||
- Docker `image.Summary` -> Podman equivalent
|
||||
- All API response types need mapping
|
||||
|
||||
3. **Socket-less mode**
|
||||
- Implement direct libpod calls without socket
|
||||
- Use `bindings.NewConnection()` with appropriate URI
|
||||
|
||||
4. **Compose support**
|
||||
- Detect `podman-compose` vs `docker-compose`
|
||||
- Update command templates
|
||||
|
||||
### Files NOT requiring changes
|
||||
- `pkg/gui/*` - UI layer is container-runtime agnostic
|
||||
- `pkg/config/*` - Configuration structure remains same
|
||||
- `pkg/i18n/*` - Translations unaffected
|
||||
| Platform | Socket Mode | Libpod Mode |
|
||||
|----------|-------------|-------------|
|
||||
| Linux | ✅ | ✅ (requires CGO) |
|
||||
| macOS | ✅ | ❌ (stub) |
|
||||
| Windows | ✅ | ❌ (stub) |
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
|
|
@ -153,4 +158,11 @@ go test -mod=vendor ./pkg/gui/...
|
|||
## Module Info
|
||||
- Module: `github.com/christophe-duc/lazypodman`
|
||||
- Go: 1.22+ (toolchain 1.23.6)
|
||||
- Key deps: gocui, docker/docker, logrus
|
||||
- Key deps: gocui, containers/podman/v5, logrus
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- **Network Prune**: Libpod mode has a TODO for manual pruning implementation
|
||||
- **Event Streaming**: Libpod mode uses polling (2-second intervals) instead of true event streaming
|
||||
- **Libpod Availability**: Socket-less mode requires Linux + CGO compilation
|
||||
- **Docker SDK**: Present in go.mod as indirect transitive dependency (pulled by Podman itself, not used by application code)
|
||||
|
|
|
|||
53
Containerfile
Normal file
53
Containerfile
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
ARG BASE_IMAGE_BUILDER=golang
|
||||
ARG ALPINE_VERSION=3.20
|
||||
ARG GO_VERSION=1.23
|
||||
|
||||
FROM ${BASE_IMAGE_BUILDER}:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
|
||||
ARG GOARCH=amd64
|
||||
ARG GOARM
|
||||
ARG VERSION
|
||||
ARG VCS_REF
|
||||
WORKDIR /tmp/gobuild
|
||||
COPY ./ .
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} GOARM=${GOARM} \
|
||||
go build -a -mod=vendor \
|
||||
-ldflags="-s -w \
|
||||
-X main.commit=${VCS_REF} \
|
||||
-X main.version=${VERSION} \
|
||||
-X main.buildSource=Podman"
|
||||
|
||||
FROM ${BASE_IMAGE_BUILDER}:${GO_VERSION}-alpine${ALPINE_VERSION} AS podman-builder
|
||||
ARG GOARCH=amd64
|
||||
ARG GOARM
|
||||
ARG PODMAN_VERSION=v5.3.1
|
||||
RUN apk add -U -q --progress --no-cache curl tar gzip
|
||||
WORKDIR /tmp/podman
|
||||
# Download pre-built podman-remote binary from GitHub releases
|
||||
RUN ARCH=$(case "${GOARCH}" in \
|
||||
amd64) echo "amd64" ;; \
|
||||
arm64) echo "arm64" ;; \
|
||||
arm) echo "arm" ;; \
|
||||
*) echo "amd64" ;; \
|
||||
esac) && \
|
||||
curl -fsSL "https://github.com/containers/podman/releases/download/${PODMAN_VERSION}/podman-remote-static-linux_${ARCH}.tar.gz" | \
|
||||
tar -xzf - && \
|
||||
mv bin/podman-remote-static-linux_${ARCH} /usr/local/bin/podman && \
|
||||
chmod +x /usr/local/bin/podman
|
||||
|
||||
FROM scratch
|
||||
ARG BUILD_DATE
|
||||
ARG VCS_REF
|
||||
ARG VERSION
|
||||
LABEL \
|
||||
org.opencontainers.image.authors="christophe-duc" \
|
||||
org.opencontainers.image.created=$BUILD_DATE \
|
||||
org.opencontainers.image.version=$VERSION \
|
||||
org.opencontainers.image.revision=$VCS_REF \
|
||||
org.opencontainers.image.url="https://github.com/christophe-duc/lazypodman" \
|
||||
org.opencontainers.image.documentation="https://github.com/christophe-duc/lazypodman" \
|
||||
org.opencontainers.image.source="https://github.com/christophe-duc/lazypodman" \
|
||||
org.opencontainers.image.title="lazypodman" \
|
||||
org.opencontainers.image.description="The lazier way to manage everything podman"
|
||||
ENTRYPOINT [ "/bin/lazypodman" ]
|
||||
COPY --from=podman-builder /usr/local/bin/podman /bin/podman
|
||||
COPY --from=builder /tmp/gobuild/lazypodman /bin/lazypodman
|
||||
49
Dockerfile
49
Dockerfile
|
|
@ -1,49 +0,0 @@
|
|||
ARG BASE_IMAGE_BUILDER=golang
|
||||
ARG ALPINE_VERSION=3.20
|
||||
ARG GO_VERSION=1.23
|
||||
|
||||
FROM ${BASE_IMAGE_BUILDER}:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
|
||||
ARG GOARCH=amd64
|
||||
ARG GOARM
|
||||
ARG VERSION
|
||||
ARG VCS_REF
|
||||
WORKDIR /tmp/gobuild
|
||||
COPY ./ .
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} GOARM=${GOARM} \
|
||||
go build -a -mod=vendor \
|
||||
-ldflags="-s -w \
|
||||
-X main.commit=${VCS_REF} \
|
||||
-X main.version=${VERSION} \
|
||||
-X main.buildSource=Docker"
|
||||
|
||||
FROM ${BASE_IMAGE_BUILDER}:${GO_VERSION}-alpine${ALPINE_VERSION} AS docker-builder
|
||||
ARG GOARCH=amd64
|
||||
ARG GOARM
|
||||
ARG DOCKER_VERSION=v27.0.3
|
||||
RUN apk add -U -q --progress --no-cache git bash coreutils gcc musl-dev
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
RUN git clone --branch ${DOCKER_VERSION} --single-branch --depth 1 https://github.com/docker/cli.git . > /dev/null 2>&1
|
||||
ENV CGO_ENABLED=0 \
|
||||
GOARCH=${GOARCH} \
|
||||
GOARM=${GOARM} \
|
||||
DISABLE_WARN_OUTSIDE_CONTAINER=1
|
||||
RUN ./scripts/build/binary
|
||||
RUN rm build/docker && mv build/docker-linux-* build/docker
|
||||
|
||||
FROM scratch
|
||||
ARG BUILD_DATE
|
||||
ARG VCS_REF
|
||||
ARG VERSION
|
||||
LABEL \
|
||||
org.opencontainers.image.authors="jessedduffield@gmail.com" \
|
||||
org.opencontainers.image.created=$BUILD_DATE \
|
||||
org.opencontainers.image.version=$VERSION \
|
||||
org.opencontainers.image.revision=$VCS_REF \
|
||||
org.opencontainers.image.url="https://github.com/jesseduffield/lazydocker" \
|
||||
org.opencontainers.image.documentation="https://github.com/jesseduffield/lazydocker" \
|
||||
org.opencontainers.image.source="https://github.com/jesseduffield/lazydocker" \
|
||||
org.opencontainers.image.title="lazydocker" \
|
||||
org.opencontainers.image.description="The lazier way to manage everything docker"
|
||||
ENTRYPOINT [ "/bin/lazydocker" ]
|
||||
COPY --from=docker-builder /go/src/github.com/docker/cli/build/docker /bin/docker
|
||||
COPY --from=builder /tmp/gobuild/lazydocker /bin/lazydocker
|
||||
117
README.md
117
README.md
File diff suppressed because one or more lines are too long
|
|
@ -1,16 +0,0 @@
|
|||
version: '3'
|
||||
services:
|
||||
lazypodman:
|
||||
build:
|
||||
context: https://github.com/christophe-duc/lazypodman.git
|
||||
args:
|
||||
BASE_IMAGE_BUILDER: golang
|
||||
GOARCH: amd64
|
||||
GOARM:
|
||||
image: christophe-duc/lazypodman
|
||||
container_name: lazypodman
|
||||
stdin_open: true
|
||||
tty: true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./config:/.config/christophe-duc/lazypodman
|
||||
|
|
@ -5,7 +5,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||
## Proje
|
||||
|
||||
<pre>
|
||||
<kbd>e</kbd>: lazzydocker ayarlarını düzenle
|
||||
<kbd>e</kbd>: lazypodman ayarlarını düzenle
|
||||
<kbd>o</kbd>: lazypodman ayarlarını aç
|
||||
<kbd>m</kbd>: kayıt defterini görüntüle
|
||||
<kbd>enter</kbd>: ana panele odaklan
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker build --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
podman build -f Containerfile \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=`git describe --abbrev=0 --tag` \
|
||||
-t $IMAGE_NAME .
|
||||
|
|
|
|||
BIN
lazypodman
BIN
lazypodman
Binary file not shown.
|
|
@ -126,7 +126,7 @@ func addBinding(title string, bindingSections []*bindingSection, binding *gui.Bi
|
|||
}
|
||||
|
||||
func formatSections(mApp *app.App, bindingSections []*bindingSection) string {
|
||||
content := fmt.Sprintf("# Lazydocker %s\n", mApp.Tr.Menu)
|
||||
content := fmt.Sprintf("# Lazypodman %s\n", mApp.Tr.Menu)
|
||||
|
||||
for _, section := range bindingSections {
|
||||
content += formatTitle(section.title)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func (c *OSCommand) RunExecutable(cmd *exec.Cmd) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// ExecutableFromString takes a string like `docker ps -a` and returns an executable command for it
|
||||
// ExecutableFromString takes a string like `podman ps -a` and returns an executable command for it
|
||||
func (c *OSCommand) ExecutableFromString(commandStr string) *exec.Cmd {
|
||||
splitCmd := str.ToArgv(commandStr)
|
||||
return c.NewCmd(splitCmd[0], splitCmd[1:]...)
|
||||
|
|
@ -369,7 +369,7 @@ func (c *OSCommand) Kill(cmd *exec.Cmd) error {
|
|||
return kill.Kill(cmd)
|
||||
}
|
||||
|
||||
// PrepareForChildren sets Setpgid to true on the cmd, so that when we run it as a subprocess, we can kill its group rather than the process itself. This is because some commands, like `docker-compose logs` spawn multiple children processes, and killing the parent process isn't sufficient for killing those child processes. We set the group id here, and then in subprocess.go we check if the group id is set and if so, we kill the whole group rather than just the one process.
|
||||
// PrepareForChildren sets Setpgid to true on the cmd, so that when we run it as a subprocess, we can kill its group rather than the process itself. This is because some commands, like `podman-compose logs` spawn multiple children processes, and killing the parent process isn't sufficient for killing those child processes. We set the group id here, and then in subprocess.go we check if the group id is set and if so, we kill the whole group rather than just the one process.
|
||||
func (c *OSCommand) PrepareForChildren(cmd *exec.Cmd) {
|
||||
kill.PrepareForChildren(cmd)
|
||||
}
|
||||
|
|
|
|||
24
podman-compose.yml
Normal file
24
podman-compose.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
version: '3'
|
||||
services:
|
||||
lazypodman:
|
||||
build:
|
||||
context: https://github.com/christophe-duc/lazypodman.git
|
||||
dockerfile: Containerfile
|
||||
args:
|
||||
BASE_IMAGE_BUILDER: golang
|
||||
GOARCH: amd64
|
||||
GOARM:
|
||||
image: christophe-duc/lazypodman
|
||||
container_name: lazypodman
|
||||
stdin_open: true
|
||||
tty: true
|
||||
volumes:
|
||||
# Rootless Podman socket (default for most users)
|
||||
# For rootful: use /run/podman/podman.sock instead
|
||||
- ${XDG_RUNTIME_DIR:-/run/user/1000}/podman/podman.sock:/run/podman/podman.sock:ro
|
||||
# Config directory
|
||||
- ./config:/.config/lazypodman
|
||||
environment:
|
||||
- CONTAINER_HOST=unix:///run/podman/podman.sock
|
||||
security_opt:
|
||||
- label=disable
|
||||
Loading…
Add table
Reference in a new issue