chore: Update .gitignore and Makefile for development release
- Add 'dist/' directory to .gitignore to prevent build artifacts from being tracked. - Introduce a new 'dev-release' target in the Makefile to automate the creation of development GitHub releases with timestamped tags. - Update README installation instructions to reflect the correct GitHub release URL.
- commit
- 69d0d4bf05a074843198bfe309bf097c8e673bb7
- author
- bamen · · 2025-06-07 08:15 UTC
- parent
- 27b4107
- signature
- unsigned
4 files · +65 -41
M .gitignore +1 -0
| @@ -1,2 +1,3 @@ | |||
| 1 | 1 | gordon | |
| 2 | 2 | .env | |
| 3 | + | dist/⏎̸ | |
| @@ -1,2 +1,3 @@ | |||||
| 1 | gordon | 1 | gordon | ||
| 2 | .env | 2 | .env | ||
| 3 | + | dist/⏎̸ | |||
M Makefile +25 -1
| @@ -2,6 +2,7 @@ | |||
| 2 | 2 | # Variables | |
| 3 | 3 | REPO := ghcr.io/bnema/gordon | |
| 4 | 4 | TAG := v2-dev | |
| 5 | + | DEV_TAG := v2-dev-$(shell date +%Y%m%d-%H%M%S) | |
| 5 | 6 | DIST_DIR := ./dist | |
| 6 | 7 | ENGINE := podman | |
| 7 | 8 | ||
| @@ -20,7 +21,7 @@ LDFLAGS := -s -w \ | |||
| 20 | 21 | ARCHS := amd64 arm64 | |
| 21 | 22 | ||
| 22 | 23 | # Phony targets | |
| 23 | - | .PHONY: all build build-push clean | |
| 24 | + | .PHONY: all build build-push clean dev-release | |
| 24 | 25 | ||
| 25 | 26 | # Default target | |
| 26 | 27 | all: build | |
| @@ -68,6 +69,29 @@ build-push: build | |||
| 68 | 69 | ||
| 69 | 70 | @echo "Script completed successfully." | |
| 70 | 71 | ||
| 72 | + | # Create dev GitHub release (separate from GoReleaser) | |
| 73 | + | dev-release: build | |
| 74 | + | @echo "Creating dev GitHub release..." | |
| 75 | + | @if [ -z "$(shell which gh)" ]; then \ | |
| 76 | + | echo "Error: GitHub CLI (gh) is not installed. Please install it first."; \ | |
| 77 | + | exit 1; \ | |
| 78 | + | fi | |
| 79 | + | @echo "Creating dev release $(DEV_TAG)..." | |
| 80 | + | @gh release create $(DEV_TAG) \ | |
| 81 | + | --title "Gordon Dev Build $(DEV_TAG)" \ | |
| 82 | + | --notes "🚧 **Development Build** 🚧\n\nThis is an automated development build for testing purposes.\n\n**Commit:** $(COMMIT)\n**Build Date:** $(BUILD_DATE)\n\n⚠️ This is not a stable release. Use at your own risk." \ | |
| 83 | + | --prerelease \ | |
| 84 | + | --draft=false \ | |
| 85 | + | $(DIST_DIR)/gordon-linux-amd64 \ | |
| 86 | + | $(DIST_DIR)/gordon-linux-arm64 | |
| 87 | + | @echo "Dev release created successfully!" | |
| 88 | + | @echo "" | |
| 89 | + | @echo "📦 Download URLs:" | |
| 90 | + | @echo " AMD64: wget https://github.com/bnema/gordon/releases/download/$(DEV_TAG)/gordon-linux-amd64" | |
| 91 | + | @echo " ARM64: wget https://github.com/bnema/gordon/releases/download/$(DEV_TAG)/gordon-linux-arm64" | |
| 92 | + | @echo "" | |
| 93 | + | @echo "🔗 Release page: https://github.com/bnema/gordon/releases/tag/$(DEV_TAG)" | |
| 94 | + | ||
| 71 | 95 | # Clean up | |
| 72 | 96 | clean: | |
| 73 | 97 | @echo "Cleaning up..." | |
| @@ -2,6 +2,7 @@ | |||||
| 2 | # Variables | 2 | # Variables | ||
| 3 | REPO := ghcr.io/bnema/gordon | 3 | REPO := ghcr.io/bnema/gordon | ||
| 4 | TAG := v2-dev | 4 | TAG := v2-dev | ||
| 5 | + | DEV_TAG := v2-dev-$(shell date +%Y%m%d-%H%M%S) | |||
| 5 | DIST_DIR := ./dist | 6 | DIST_DIR := ./dist | ||
| 6 | ENGINE := podman | 7 | ENGINE := podman | ||
| 7 | 8 | ||||
| @@ -20,7 +21,7 @@ LDFLAGS := -s -w \ | |||||
| 20 | ARCHS := amd64 arm64 | 21 | ARCHS := amd64 arm64 | ||
| 21 | 22 | ||||
| 22 | # Phony targets | 23 | # Phony targets | ||
| 23 | - | .PHONY: all build build-push clean | 24 | + | .PHONY: all build build-push clean dev-release |
| 24 | 25 | ||||
| 25 | # Default target | 26 | # Default target | ||
| 26 | all: build | 27 | all: build | ||
| @@ -68,6 +69,29 @@ build-push: build | |||||
| 68 | 69 | ||||
| 69 | @echo "Script completed successfully." | 70 | @echo "Script completed successfully." | ||
| 70 | 71 | ||||
| 72 | + | # Create dev GitHub release (separate from GoReleaser) | |||
| 73 | + | dev-release: build | |||
| 74 | + | @echo "Creating dev GitHub release..." | |||
| 75 | + | @if [ -z "$(shell which gh)" ]; then \ | |||
| 76 | + | echo "Error: GitHub CLI (gh) is not installed. Please install it first."; \ | |||
| 77 | + | exit 1; \ | |||
| 78 | + | fi | |||
| 79 | + | @echo "Creating dev release $(DEV_TAG)..." | |||
| 80 | + | @gh release create $(DEV_TAG) \ | |||
| 81 | + | --title "Gordon Dev Build $(DEV_TAG)" \ | |||
| 82 | + | --notes "🚧 **Development Build** 🚧\n\nThis is an automated development build for testing purposes.\n\n**Commit:** $(COMMIT)\n**Build Date:** $(BUILD_DATE)\n\n⚠️ This is not a stable release. Use at your own risk." \ | |||
| 83 | + | --prerelease \ | |||
| 84 | + | --draft=false \ | |||
| 85 | + | $(DIST_DIR)/gordon-linux-amd64 \ | |||
| 86 | + | $(DIST_DIR)/gordon-linux-arm64 | |||
| 87 | + | @echo "Dev release created successfully!" | |||
| 88 | + | @echo "" | |||
| 89 | + | @echo "📦 Download URLs:" | |||
| 90 | + | @echo " AMD64: wget https://github.com/bnema/gordon/releases/download/$(DEV_TAG)/gordon-linux-amd64" | |||
| 91 | + | @echo " ARM64: wget https://github.com/bnema/gordon/releases/download/$(DEV_TAG)/gordon-linux-arm64" | |||
| 92 | + | @echo "" | |||
| 93 | + | @echo "🔗 Release page: https://github.com/bnema/gordon/releases/tag/$(DEV_TAG)" | |||
| 94 | + | ||||
| 71 | # Clean up | 95 | # Clean up | ||
| 72 | clean: | 96 | clean: | ||
| 73 | @echo "Cleaning up..." | 97 | @echo "Cleaning up..." | ||
M README.md +1 -1
| @@ -119,7 +119,7 @@ EOF | |||
| 119 | 119 | ||
| 120 | 120 | ### 2. Install Gordon | |
| 121 | 121 | ```bash | |
| 122 | - | wget https://github.com/yourusername/gordon/releases/latest/download/gordon-linux-amd64 | |
| 122 | + | wget https://github.com/bnema/gordon/releases/latest/download/gordon-linux-amd64 | |
| 123 | 123 | chmod +x gordon-linux-amd64 | |
| 124 | 124 | sudo mv gordon-linux-amd64 /usr/local/bin/gordon | |
| 125 | 125 | ``` | |
| @@ -119,7 +119,7 @@ EOF | |||||
| 119 | 119 | ||||
| 120 | ### 2. Install Gordon | 120 | ### 2. Install Gordon | ||
| 121 | ```bash | 121 | ```bash | ||
| 122 | - | wget https://github.com/yourusername/gordon/releases/latest/download/gordon-linux-amd64 | 122 | + | wget https://github.com/bnema/gordon/releases/latest/download/gordon-linux-amd64 |
| 123 | chmod +x gordon-linux-amd64 | 123 | chmod +x gordon-linux-amd64 | ||
| 124 | sudo mv gordon-linux-amd64 /usr/local/bin/gordon | 124 | sudo mv gordon-linux-amd64 /usr/local/bin/gordon | ||
| 125 | ``` | 125 | ``` | ||
M internal/container/factory.go +38 -39
| @@ -5,7 +5,6 @@ import ( | |||
| 5 | 5 | "fmt" | |
| 6 | 6 | "os" | |
| 7 | 7 | "os/user" | |
| 8 | - | "path/filepath" | |
| 9 | 8 | "strings" | |
| 10 | 9 | ||
| 11 | 10 | "github.com/docker/docker/client" | |
| @@ -19,9 +18,9 @@ import ( | |||
| 19 | 18 | type RuntimeType string | |
| 20 | 19 | ||
| 21 | 20 | const ( | |
| 22 | - | RuntimeAuto RuntimeType = "auto" | |
| 23 | - | RuntimeDocker RuntimeType = "docker" | |
| 24 | - | RuntimePodman RuntimeType = "podman" | |
| 21 | + | RuntimeAuto RuntimeType = "auto" | |
| 22 | + | RuntimeDocker RuntimeType = "docker" | |
| 23 | + | RuntimePodman RuntimeType = "podman" | |
| 25 | 24 | RuntimePodmanRootless RuntimeType = "podman-rootless" | |
| 26 | 25 | ) | |
| 27 | 26 | ||
| @@ -35,10 +34,10 @@ type RuntimeInfo struct { | |||
| 35 | 34 | // CreateRuntime creates a container runtime based on configuration | |
| 36 | 35 | func CreateRuntime(cfg *config.Config) (runtime.Runtime, error) { | |
| 37 | 36 | runtimeType := RuntimeType(cfg.Server.Runtime) | |
| 38 | - | ||
| 37 | + | ||
| 39 | 38 | // Get socket path from config or environment | |
| 40 | 39 | socketPath := getSocketPath(cfg.Server.SocketPath) | |
| 41 | - | ||
| 40 | + | ||
| 42 | 41 | switch runtimeType { | |
| 43 | 42 | case RuntimeAuto: | |
| 44 | 43 | return createAutoRuntime(socketPath) | |
| @@ -58,13 +57,13 @@ func getSocketPath(configPath string) string { | |||
| 58 | 57 | log.Debug().Str("path", configPath).Msg("Using socket path from config") | |
| 59 | 58 | return configPath | |
| 60 | 59 | } | |
| 61 | - | ||
| 60 | + | ||
| 62 | 61 | // 2. Check CONTAINER_HOST environment variable | |
| 63 | 62 | if envPath := os.Getenv("CONTAINER_HOST"); envPath != "" { | |
| 64 | 63 | log.Debug().Str("path", envPath).Msg("Using socket path from CONTAINER_HOST") | |
| 65 | 64 | return envPath | |
| 66 | 65 | } | |
| 67 | - | ||
| 66 | + | ||
| 68 | 67 | // 3. Return empty string for auto-detection | |
| 69 | 68 | return "" | |
| 70 | 69 | } | |
| @@ -72,7 +71,7 @@ func getSocketPath(configPath string) string { | |||
| 72 | 71 | // createAutoRuntime automatically detects and creates the best available runtime | |
| 73 | 72 | func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |
| 74 | 73 | var candidatePaths []string | |
| 75 | - | ||
| 74 | + | ||
| 76 | 75 | if customSocketPath != "" { | |
| 77 | 76 | // If custom path provided, try it first | |
| 78 | 77 | candidatePaths = []string{customSocketPath} | |
| @@ -80,7 +79,7 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||
| 80 | 79 | // Auto-detect socket paths | |
| 81 | 80 | candidatePaths = getDefaultSocketPaths() | |
| 82 | 81 | } | |
| 83 | - | ||
| 82 | + | ||
| 84 | 83 | // Try each socket path | |
| 85 | 84 | for _, socketPath := range candidatePaths { | |
| 86 | 85 | if rt, info, err := tryCreateRuntime(socketPath); err == nil { | |
| @@ -92,7 +91,7 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||
| 92 | 91 | return rt, nil | |
| 93 | 92 | } | |
| 94 | 93 | } | |
| 95 | - | ||
| 94 | + | ||
| 96 | 95 | return nil, fmt.Errorf("no container runtime found. Tried paths: %v", candidatePaths) | |
| 97 | 96 | } | |
| 98 | 97 | ||
| @@ -100,22 +99,22 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||
| 100 | 99 | func createDockerRuntime(socketPath string) (runtime.Runtime, error) { | |
| 101 | 100 | var opts []client.Opt | |
| 102 | 101 | opts = append(opts, client.FromEnv, client.WithAPIVersionNegotiation()) | |
| 103 | - | ||
| 102 | + | ||
| 104 | 103 | if socketPath != "" { | |
| 105 | 104 | opts = append(opts, client.WithHost(socketPath)) | |
| 106 | 105 | } | |
| 107 | - | ||
| 106 | + | ||
| 108 | 107 | cli, err := client.NewClientWithOpts(opts...) | |
| 109 | 108 | if err != nil { | |
| 110 | 109 | return nil, fmt.Errorf("failed to create Docker client: %w", err) | |
| 111 | 110 | } | |
| 112 | - | ||
| 111 | + | ||
| 113 | 112 | // Test connectivity | |
| 114 | 113 | ctx := context.Background() | |
| 115 | 114 | if _, err := cli.Ping(ctx); err != nil { | |
| 116 | 115 | return nil, fmt.Errorf("Docker ping failed: %w", err) | |
| 117 | 116 | } | |
| 118 | - | ||
| 117 | + | ||
| 119 | 118 | return &DockerRuntime{client: cli}, nil | |
| 120 | 119 | } | |
| 121 | 120 | ||
| @@ -124,7 +123,7 @@ func createPodmanRuntime(socketPath string, rootless bool) (runtime.Runtime, err | |||
| 124 | 123 | if socketPath == "" { | |
| 125 | 124 | socketPath = getDefaultPodmanSocket(rootless) | |
| 126 | 125 | } | |
| 127 | - | ||
| 126 | + | ||
| 128 | 127 | return createPodmanRuntimeWithSocket(socketPath) | |
| 129 | 128 | } | |
| 130 | 129 | ||
| @@ -135,35 +134,35 @@ func tryCreateRuntime(socketPath string) (runtime.Runtime, *RuntimeInfo, error) | |||
| 135 | 134 | client.WithHost(socketPath), | |
| 136 | 135 | client.WithAPIVersionNegotiation(), | |
| 137 | 136 | } | |
| 138 | - | ||
| 137 | + | ||
| 139 | 138 | cli, err := client.NewClientWithOpts(opts...) | |
| 140 | 139 | if err != nil { | |
| 141 | 140 | return nil, nil, fmt.Errorf("failed to create client: %w", err) | |
| 142 | 141 | } | |
| 143 | - | ||
| 142 | + | ||
| 144 | 143 | // Test connectivity and get version | |
| 145 | 144 | ctx := context.Background() | |
| 146 | 145 | ping, err := cli.Ping(ctx) | |
| 147 | 146 | if err != nil { | |
| 148 | 147 | return nil, nil, fmt.Errorf("ping failed: %w", err) | |
| 149 | 148 | } | |
| 150 | - | ||
| 149 | + | ||
| 151 | 150 | // Determine runtime type based on socket path and server info | |
| 152 | 151 | runtimeType := detectRuntimeType(socketPath, ping.APIVersion) | |
| 153 | - | ||
| 152 | + | ||
| 154 | 153 | var rt runtime.Runtime | |
| 155 | 154 | if runtimeType == RuntimeDocker { | |
| 156 | 155 | rt = &DockerRuntime{client: cli} | |
| 157 | 156 | } else { | |
| 158 | 157 | rt = &PodmanRuntime{client: cli} | |
| 159 | 158 | } | |
| 160 | - | ||
| 159 | + | ||
| 161 | 160 | info := &RuntimeInfo{ | |
| 162 | 161 | Type: runtimeType, | |
| 163 | 162 | SocketPath: socketPath, | |
| 164 | 163 | Version: ping.APIVersion, | |
| 165 | 164 | } | |
| 166 | - | ||
| 165 | + | ||
| 167 | 166 | return rt, info, nil | |
| 168 | 167 | } | |
| 169 | 168 | ||
| @@ -176,11 +175,11 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||
| 176 | 175 | } | |
| 177 | 176 | return RuntimePodman | |
| 178 | 177 | } | |
| 179 | - | ||
| 178 | + | ||
| 180 | 179 | if strings.Contains(socketPath, "docker") { | |
| 181 | 180 | return RuntimeDocker | |
| 182 | 181 | } | |
| 183 | - | ||
| 182 | + | ||
| 184 | 183 | // Default socket paths | |
| 185 | 184 | switch socketPath { | |
| 186 | 185 | case "/var/run/docker.sock", "unix:///var/run/docker.sock": | |
| @@ -188,12 +187,12 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||
| 188 | 187 | case "/run/podman/podman.sock", "unix:///run/podman/podman.sock": | |
| 189 | 188 | return RuntimePodman | |
| 190 | 189 | } | |
| 191 | - | ||
| 190 | + | ||
| 192 | 191 | // Check if it's in user runtime directory (rootless) | |
| 193 | 192 | if strings.Contains(socketPath, "/run/user/") { | |
| 194 | 193 | return RuntimePodmanRootless | |
| 195 | 194 | } | |
| 196 | - | ||
| 195 | + | ||
| 197 | 196 | // Default to Docker for unknown paths | |
| 198 | 197 | return RuntimeDocker | |
| 199 | 198 | } | |
| @@ -201,15 +200,15 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||
| 201 | 200 | // getDefaultSocketPaths returns the default socket paths to try | |
| 202 | 201 | func getDefaultSocketPaths() []string { | |
| 203 | 202 | paths := []string{ | |
| 204 | - | "unix:///var/run/docker.sock", // Docker | |
| 205 | - | "unix:///run/podman/podman.sock", // Podman root | |
| 203 | + | "unix:///var/run/docker.sock", // Docker | |
| 204 | + | "unix:///run/podman/podman.sock", // Podman root | |
| 206 | 205 | } | |
| 207 | - | ||
| 206 | + | ||
| 208 | 207 | // Add Podman rootless socket | |
| 209 | 208 | if rootlessSocket := getDefaultPodmanSocket(true); rootlessSocket != "" { | |
| 210 | 209 | paths = append(paths, rootlessSocket) | |
| 211 | 210 | } | |
| 212 | - | ||
| 211 | + | ||
| 213 | 212 | return paths | |
| 214 | 213 | } | |
| 215 | 214 | ||
| @@ -218,17 +217,17 @@ func getDefaultPodmanSocket(rootless bool) string { | |||
| 218 | 217 | if !rootless { | |
| 219 | 218 | return "unix:///run/podman/podman.sock" | |
| 220 | 219 | } | |
| 221 | - | ||
| 220 | + | ||
| 222 | 221 | // Get user runtime directory for rootless Podman | |
| 223 | 222 | if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { | |
| 224 | 223 | return fmt.Sprintf("unix://%s/podman/podman.sock", xdgRuntimeDir) | |
| 225 | 224 | } | |
| 226 | - | ||
| 225 | + | ||
| 227 | 226 | // Fallback: construct from user ID | |
| 228 | 227 | if currentUser, err := user.Current(); err == nil { | |
| 229 | 228 | return fmt.Sprintf("unix:///run/user/%s/podman/podman.sock", currentUser.Uid) | |
| 230 | 229 | } | |
| 231 | - | ||
| 230 | + | ||
| 232 | 231 | log.Warn().Msg("Could not determine rootless Podman socket path") | |
| 233 | 232 | return "" | |
| 234 | 233 | } | |
| @@ -239,30 +238,30 @@ func createPodmanRuntimeWithSocket(socketPath string) (runtime.Runtime, error) { | |||
| 239 | 238 | client.WithHost(socketPath), | |
| 240 | 239 | client.WithAPIVersionNegotiation(), | |
| 241 | 240 | } | |
| 242 | - | ||
| 241 | + | ||
| 243 | 242 | cli, err := client.NewClientWithOpts(opts...) | |
| 244 | 243 | if err != nil { | |
| 245 | 244 | return nil, fmt.Errorf("failed to create Podman client: %w", err) | |
| 246 | 245 | } | |
| 247 | - | ||
| 246 | + | ||
| 248 | 247 | // Test connectivity | |
| 249 | 248 | ctx := context.Background() | |
| 250 | 249 | if _, err := cli.Ping(ctx); err != nil { | |
| 251 | 250 | return nil, fmt.Errorf("Podman ping failed: %w", err) | |
| 252 | 251 | } | |
| 253 | - | ||
| 252 | + | ||
| 254 | 253 | return &PodmanRuntime{client: cli}, nil | |
| 255 | 254 | } | |
| 256 | 255 | ||
| 257 | 256 | // GetAvailableRuntimes returns information about all available runtimes | |
| 258 | 257 | func GetAvailableRuntimes() []RuntimeInfo { | |
| 259 | 258 | var runtimes []RuntimeInfo | |
| 260 | - | ||
| 259 | + | ||
| 261 | 260 | for _, socketPath := range getDefaultSocketPaths() { | |
| 262 | 261 | if _, info, err := tryCreateRuntime(socketPath); err == nil { | |
| 263 | 262 | runtimes = append(runtimes, *info) | |
| 264 | 263 | } | |
| 265 | 264 | } | |
| 266 | - | ||
| 265 | + | ||
| 267 | 266 | return runtimes | |
| 268 | - | }⏎̸ | |
| 267 | + | } | |
| @@ -5,7 +5,6 @@ import ( | |||||
| 5 | "fmt" | 5 | "fmt" | ||
| 6 | "os" | 6 | "os" | ||
| 7 | "os/user" | 7 | "os/user" | ||
| 8 | - | "path/filepath" | |||
| 9 | "strings" | 8 | "strings" | ||
| 10 | 9 | ||||
| 11 | "github.com/docker/docker/client" | 10 | "github.com/docker/docker/client" | ||
| @@ -19,9 +18,9 @@ import ( | |||||
| 19 | type RuntimeType string | 18 | type RuntimeType string | ||
| 20 | 19 | ||||
| 21 | const ( | 20 | const ( | ||
| 22 | - | RuntimeAuto RuntimeType = "auto" | 21 | + | RuntimeAuto RuntimeType = "auto" |
| 23 | - | RuntimeDocker RuntimeType = "docker" | 22 | + | RuntimeDocker RuntimeType = "docker" |
| 24 | - | RuntimePodman RuntimeType = "podman" | 23 | + | RuntimePodman RuntimeType = "podman" |
| 25 | RuntimePodmanRootless RuntimeType = "podman-rootless" | 24 | RuntimePodmanRootless RuntimeType = "podman-rootless" | ||
| 26 | ) | 25 | ) | ||
| 27 | 26 | ||||
| @@ -35,10 +34,10 @@ type RuntimeInfo struct { | |||||
| 35 | // CreateRuntime creates a container runtime based on configuration | 34 | // CreateRuntime creates a container runtime based on configuration | ||
| 36 | func CreateRuntime(cfg *config.Config) (runtime.Runtime, error) { | 35 | func CreateRuntime(cfg *config.Config) (runtime.Runtime, error) { | ||
| 37 | runtimeType := RuntimeType(cfg.Server.Runtime) | 36 | runtimeType := RuntimeType(cfg.Server.Runtime) | ||
| 38 | - | 37 | + | ||
| 39 | // Get socket path from config or environment | 38 | // Get socket path from config or environment | ||
| 40 | socketPath := getSocketPath(cfg.Server.SocketPath) | 39 | socketPath := getSocketPath(cfg.Server.SocketPath) | ||
| 41 | - | 40 | + | ||
| 42 | switch runtimeType { | 41 | switch runtimeType { | ||
| 43 | case RuntimeAuto: | 42 | case RuntimeAuto: | ||
| 44 | return createAutoRuntime(socketPath) | 43 | return createAutoRuntime(socketPath) | ||
| @@ -58,13 +57,13 @@ func getSocketPath(configPath string) string { | |||||
| 58 | log.Debug().Str("path", configPath).Msg("Using socket path from config") | 57 | log.Debug().Str("path", configPath).Msg("Using socket path from config") | ||
| 59 | return configPath | 58 | return configPath | ||
| 60 | } | 59 | } | ||
| 61 | - | 60 | + | ||
| 62 | // 2. Check CONTAINER_HOST environment variable | 61 | // 2. Check CONTAINER_HOST environment variable | ||
| 63 | if envPath := os.Getenv("CONTAINER_HOST"); envPath != "" { | 62 | if envPath := os.Getenv("CONTAINER_HOST"); envPath != "" { | ||
| 64 | log.Debug().Str("path", envPath).Msg("Using socket path from CONTAINER_HOST") | 63 | log.Debug().Str("path", envPath).Msg("Using socket path from CONTAINER_HOST") | ||
| 65 | return envPath | 64 | return envPath | ||
| 66 | } | 65 | } | ||
| 67 | - | 66 | + | ||
| 68 | // 3. Return empty string for auto-detection | 67 | // 3. Return empty string for auto-detection | ||
| 69 | return "" | 68 | return "" | ||
| 70 | } | 69 | } | ||
| @@ -72,7 +71,7 @@ func getSocketPath(configPath string) string { | |||||
| 72 | // createAutoRuntime automatically detects and creates the best available runtime | 71 | // createAutoRuntime automatically detects and creates the best available runtime | ||
| 73 | func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | 72 | func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | ||
| 74 | var candidatePaths []string | 73 | var candidatePaths []string | ||
| 75 | - | 74 | + | ||
| 76 | if customSocketPath != "" { | 75 | if customSocketPath != "" { | ||
| 77 | // If custom path provided, try it first | 76 | // If custom path provided, try it first | ||
| 78 | candidatePaths = []string{customSocketPath} | 77 | candidatePaths = []string{customSocketPath} | ||
| @@ -80,7 +79,7 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||||
| 80 | // Auto-detect socket paths | 79 | // Auto-detect socket paths | ||
| 81 | candidatePaths = getDefaultSocketPaths() | 80 | candidatePaths = getDefaultSocketPaths() | ||
| 82 | } | 81 | } | ||
| 83 | - | 82 | + | ||
| 84 | // Try each socket path | 83 | // Try each socket path | ||
| 85 | for _, socketPath := range candidatePaths { | 84 | for _, socketPath := range candidatePaths { | ||
| 86 | if rt, info, err := tryCreateRuntime(socketPath); err == nil { | 85 | if rt, info, err := tryCreateRuntime(socketPath); err == nil { | ||
| @@ -92,7 +91,7 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||||
| 92 | return rt, nil | 91 | return rt, nil | ||
| 93 | } | 92 | } | ||
| 94 | } | 93 | } | ||
| 95 | - | 94 | + | ||
| 96 | return nil, fmt.Errorf("no container runtime found. Tried paths: %v", candidatePaths) | 95 | return nil, fmt.Errorf("no container runtime found. Tried paths: %v", candidatePaths) | ||
| 97 | } | 96 | } | ||
| 98 | 97 | ||||
| @@ -100,22 +99,22 @@ func createAutoRuntime(customSocketPath string) (runtime.Runtime, error) { | |||||
| 100 | func createDockerRuntime(socketPath string) (runtime.Runtime, error) { | 99 | func createDockerRuntime(socketPath string) (runtime.Runtime, error) { | ||
| 101 | var opts []client.Opt | 100 | var opts []client.Opt | ||
| 102 | opts = append(opts, client.FromEnv, client.WithAPIVersionNegotiation()) | 101 | opts = append(opts, client.FromEnv, client.WithAPIVersionNegotiation()) | ||
| 103 | - | 102 | + | ||
| 104 | if socketPath != "" { | 103 | if socketPath != "" { | ||
| 105 | opts = append(opts, client.WithHost(socketPath)) | 104 | opts = append(opts, client.WithHost(socketPath)) | ||
| 106 | } | 105 | } | ||
| 107 | - | 106 | + | ||
| 108 | cli, err := client.NewClientWithOpts(opts...) | 107 | cli, err := client.NewClientWithOpts(opts...) | ||
| 109 | if err != nil { | 108 | if err != nil { | ||
| 110 | return nil, fmt.Errorf("failed to create Docker client: %w", err) | 109 | return nil, fmt.Errorf("failed to create Docker client: %w", err) | ||
| 111 | } | 110 | } | ||
| 112 | - | 111 | + | ||
| 113 | // Test connectivity | 112 | // Test connectivity | ||
| 114 | ctx := context.Background() | 113 | ctx := context.Background() | ||
| 115 | if _, err := cli.Ping(ctx); err != nil { | 114 | if _, err := cli.Ping(ctx); err != nil { | ||
| 116 | return nil, fmt.Errorf("Docker ping failed: %w", err) | 115 | return nil, fmt.Errorf("Docker ping failed: %w", err) | ||
| 117 | } | 116 | } | ||
| 118 | - | 117 | + | ||
| 119 | return &DockerRuntime{client: cli}, nil | 118 | return &DockerRuntime{client: cli}, nil | ||
| 120 | } | 119 | } | ||
| 121 | 120 | ||||
| @@ -124,7 +123,7 @@ func createPodmanRuntime(socketPath string, rootless bool) (runtime.Runtime, err | |||||
| 124 | if socketPath == "" { | 123 | if socketPath == "" { | ||
| 125 | socketPath = getDefaultPodmanSocket(rootless) | 124 | socketPath = getDefaultPodmanSocket(rootless) | ||
| 126 | } | 125 | } | ||
| 127 | - | 126 | + | ||
| 128 | return createPodmanRuntimeWithSocket(socketPath) | 127 | return createPodmanRuntimeWithSocket(socketPath) | ||
| 129 | } | 128 | } | ||
| 130 | 129 | ||||
| @@ -135,35 +134,35 @@ func tryCreateRuntime(socketPath string) (runtime.Runtime, *RuntimeInfo, error) | |||||
| 135 | client.WithHost(socketPath), | 134 | client.WithHost(socketPath), | ||
| 136 | client.WithAPIVersionNegotiation(), | 135 | client.WithAPIVersionNegotiation(), | ||
| 137 | } | 136 | } | ||
| 138 | - | 137 | + | ||
| 139 | cli, err := client.NewClientWithOpts(opts...) | 138 | cli, err := client.NewClientWithOpts(opts...) | ||
| 140 | if err != nil { | 139 | if err != nil { | ||
| 141 | return nil, nil, fmt.Errorf("failed to create client: %w", err) | 140 | return nil, nil, fmt.Errorf("failed to create client: %w", err) | ||
| 142 | } | 141 | } | ||
| 143 | - | 142 | + | ||
| 144 | // Test connectivity and get version | 143 | // Test connectivity and get version | ||
| 145 | ctx := context.Background() | 144 | ctx := context.Background() | ||
| 146 | ping, err := cli.Ping(ctx) | 145 | ping, err := cli.Ping(ctx) | ||
| 147 | if err != nil { | 146 | if err != nil { | ||
| 148 | return nil, nil, fmt.Errorf("ping failed: %w", err) | 147 | return nil, nil, fmt.Errorf("ping failed: %w", err) | ||
| 149 | } | 148 | } | ||
| 150 | - | 149 | + | ||
| 151 | // Determine runtime type based on socket path and server info | 150 | // Determine runtime type based on socket path and server info | ||
| 152 | runtimeType := detectRuntimeType(socketPath, ping.APIVersion) | 151 | runtimeType := detectRuntimeType(socketPath, ping.APIVersion) | ||
| 153 | - | 152 | + | ||
| 154 | var rt runtime.Runtime | 153 | var rt runtime.Runtime | ||
| 155 | if runtimeType == RuntimeDocker { | 154 | if runtimeType == RuntimeDocker { | ||
| 156 | rt = &DockerRuntime{client: cli} | 155 | rt = &DockerRuntime{client: cli} | ||
| 157 | } else { | 156 | } else { | ||
| 158 | rt = &PodmanRuntime{client: cli} | 157 | rt = &PodmanRuntime{client: cli} | ||
| 159 | } | 158 | } | ||
| 160 | - | 159 | + | ||
| 161 | info := &RuntimeInfo{ | 160 | info := &RuntimeInfo{ | ||
| 162 | Type: runtimeType, | 161 | Type: runtimeType, | ||
| 163 | SocketPath: socketPath, | 162 | SocketPath: socketPath, | ||
| 164 | Version: ping.APIVersion, | 163 | Version: ping.APIVersion, | ||
| 165 | } | 164 | } | ||
| 166 | - | 165 | + | ||
| 167 | return rt, info, nil | 166 | return rt, info, nil | ||
| 168 | } | 167 | } | ||
| 169 | 168 | ||||
| @@ -176,11 +175,11 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||||
| 176 | } | 175 | } | ||
| 177 | return RuntimePodman | 176 | return RuntimePodman | ||
| 178 | } | 177 | } | ||
| 179 | - | 178 | + | ||
| 180 | if strings.Contains(socketPath, "docker") { | 179 | if strings.Contains(socketPath, "docker") { | ||
| 181 | return RuntimeDocker | 180 | return RuntimeDocker | ||
| 182 | } | 181 | } | ||
| 183 | - | 182 | + | ||
| 184 | // Default socket paths | 183 | // Default socket paths | ||
| 185 | switch socketPath { | 184 | switch socketPath { | ||
| 186 | case "/var/run/docker.sock", "unix:///var/run/docker.sock": | 185 | case "/var/run/docker.sock", "unix:///var/run/docker.sock": | ||
| @@ -188,12 +187,12 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||||
| 188 | case "/run/podman/podman.sock", "unix:///run/podman/podman.sock": | 187 | case "/run/podman/podman.sock", "unix:///run/podman/podman.sock": | ||
| 189 | return RuntimePodman | 188 | return RuntimePodman | ||
| 190 | } | 189 | } | ||
| 191 | - | 190 | + | ||
| 192 | // Check if it's in user runtime directory (rootless) | 191 | // Check if it's in user runtime directory (rootless) | ||
| 193 | if strings.Contains(socketPath, "/run/user/") { | 192 | if strings.Contains(socketPath, "/run/user/") { | ||
| 194 | return RuntimePodmanRootless | 193 | return RuntimePodmanRootless | ||
| 195 | } | 194 | } | ||
| 196 | - | 195 | + | ||
| 197 | // Default to Docker for unknown paths | 196 | // Default to Docker for unknown paths | ||
| 198 | return RuntimeDocker | 197 | return RuntimeDocker | ||
| 199 | } | 198 | } | ||
| @@ -201,15 +200,15 @@ func detectRuntimeType(socketPath, apiVersion string) RuntimeType { | |||||
| 201 | // getDefaultSocketPaths returns the default socket paths to try | 200 | // getDefaultSocketPaths returns the default socket paths to try | ||
| 202 | func getDefaultSocketPaths() []string { | 201 | func getDefaultSocketPaths() []string { | ||
| 203 | paths := []string{ | 202 | paths := []string{ | ||
| 204 | - | "unix:///var/run/docker.sock", // Docker | 203 | + | "unix:///var/run/docker.sock", // Docker |
| 205 | - | "unix:///run/podman/podman.sock", // Podman root | 204 | + | "unix:///run/podman/podman.sock", // Podman root |
| 206 | } | 205 | } | ||
| 207 | - | 206 | + | ||
| 208 | // Add Podman rootless socket | 207 | // Add Podman rootless socket | ||
| 209 | if rootlessSocket := getDefaultPodmanSocket(true); rootlessSocket != "" { | 208 | if rootlessSocket := getDefaultPodmanSocket(true); rootlessSocket != "" { | ||
| 210 | paths = append(paths, rootlessSocket) | 209 | paths = append(paths, rootlessSocket) | ||
| 211 | } | 210 | } | ||
| 212 | - | 211 | + | ||
| 213 | return paths | 212 | return paths | ||
| 214 | } | 213 | } | ||
| 215 | 214 | ||||
| @@ -218,17 +217,17 @@ func getDefaultPodmanSocket(rootless bool) string { | |||||
| 218 | if !rootless { | 217 | if !rootless { | ||
| 219 | return "unix:///run/podman/podman.sock" | 218 | return "unix:///run/podman/podman.sock" | ||
| 220 | } | 219 | } | ||
| 221 | - | 220 | + | ||
| 222 | // Get user runtime directory for rootless Podman | 221 | // Get user runtime directory for rootless Podman | ||
| 223 | if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { | 222 | if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { | ||
| 224 | return fmt.Sprintf("unix://%s/podman/podman.sock", xdgRuntimeDir) | 223 | return fmt.Sprintf("unix://%s/podman/podman.sock", xdgRuntimeDir) | ||
| 225 | } | 224 | } | ||
| 226 | - | 225 | + | ||
| 227 | // Fallback: construct from user ID | 226 | // Fallback: construct from user ID | ||
| 228 | if currentUser, err := user.Current(); err == nil { | 227 | if currentUser, err := user.Current(); err == nil { | ||
| 229 | return fmt.Sprintf("unix:///run/user/%s/podman/podman.sock", currentUser.Uid) | 228 | return fmt.Sprintf("unix:///run/user/%s/podman/podman.sock", currentUser.Uid) | ||
| 230 | } | 229 | } | ||
| 231 | - | 230 | + | ||
| 232 | log.Warn().Msg("Could not determine rootless Podman socket path") | 231 | log.Warn().Msg("Could not determine rootless Podman socket path") | ||
| 233 | return "" | 232 | return "" | ||
| 234 | } | 233 | } | ||
| @@ -239,30 +238,30 @@ func createPodmanRuntimeWithSocket(socketPath string) (runtime.Runtime, error) { | |||||
| 239 | client.WithHost(socketPath), | 238 | client.WithHost(socketPath), | ||
| 240 | client.WithAPIVersionNegotiation(), | 239 | client.WithAPIVersionNegotiation(), | ||
| 241 | } | 240 | } | ||
| 242 | - | 241 | + | ||
| 243 | cli, err := client.NewClientWithOpts(opts...) | 242 | cli, err := client.NewClientWithOpts(opts...) | ||
| 244 | if err != nil { | 243 | if err != nil { | ||
| 245 | return nil, fmt.Errorf("failed to create Podman client: %w", err) | 244 | return nil, fmt.Errorf("failed to create Podman client: %w", err) | ||
| 246 | } | 245 | } | ||
| 247 | - | 246 | + | ||
| 248 | // Test connectivity | 247 | // Test connectivity | ||
| 249 | ctx := context.Background() | 248 | ctx := context.Background() | ||
| 250 | if _, err := cli.Ping(ctx); err != nil { | 249 | if _, err := cli.Ping(ctx); err != nil { | ||
| 251 | return nil, fmt.Errorf("Podman ping failed: %w", err) | 250 | return nil, fmt.Errorf("Podman ping failed: %w", err) | ||
| 252 | } | 251 | } | ||
| 253 | - | 252 | + | ||
| 254 | return &PodmanRuntime{client: cli}, nil | 253 | return &PodmanRuntime{client: cli}, nil | ||
| 255 | } | 254 | } | ||
| 256 | 255 | ||||
| 257 | // GetAvailableRuntimes returns information about all available runtimes | 256 | // GetAvailableRuntimes returns information about all available runtimes | ||
| 258 | func GetAvailableRuntimes() []RuntimeInfo { | 257 | func GetAvailableRuntimes() []RuntimeInfo { | ||
| 259 | var runtimes []RuntimeInfo | 258 | var runtimes []RuntimeInfo | ||
| 260 | - | 259 | + | ||
| 261 | for _, socketPath := range getDefaultSocketPaths() { | 260 | for _, socketPath := range getDefaultSocketPaths() { | ||
| 262 | if _, info, err := tryCreateRuntime(socketPath); err == nil { | 261 | if _, info, err := tryCreateRuntime(socketPath); err == nil { | ||
| 263 | runtimes = append(runtimes, *info) | 262 | runtimes = append(runtimes, *info) | ||
| 264 | } | 263 | } | ||
| 265 | } | 264 | } | ||
| 266 | - | 265 | + | ||
| 267 | return runtimes | 266 | return runtimes | ||
| 268 | - | }⏎̸ | 267 | + | } |