mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-03 00:36:56 +00:00
162 lines
3.6 KiB
Go
162 lines
3.6 KiB
Go
package credhelper
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/huh"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func newConfigureDockerCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "configure-docker",
|
|
Short: "Configure Docker to use this credential helper",
|
|
Long: "Adds or updates the credHelpers entry in ~/.docker/config.json\nfor all configured registries.",
|
|
RunE: runConfigureDocker,
|
|
}
|
|
}
|
|
|
|
func runConfigureDocker(cmd *cobra.Command, args []string) error {
|
|
sc, err := loadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("loading config: %w", err)
|
|
}
|
|
|
|
if len(sc.Registries) == 0 {
|
|
fmt.Fprintf(os.Stderr, "No registries configured.\n")
|
|
fmt.Fprintf(os.Stderr, "Run: %s login\n", cfg.BinaryName)
|
|
return nil
|
|
}
|
|
|
|
// Collect registry hosts
|
|
var hosts []string
|
|
for url := range sc.Registries {
|
|
host := strings.TrimPrefix(url, "https://")
|
|
host = strings.TrimPrefix(host, "http://")
|
|
hosts = append(hosts, host)
|
|
}
|
|
|
|
dockerConfigPath := getDockerConfigPath()
|
|
|
|
// Load existing Docker config
|
|
dockerCfg := loadDockerConfig()
|
|
if dockerCfg == nil {
|
|
dockerCfg = make(map[string]any)
|
|
}
|
|
|
|
// Get or create credHelpers
|
|
helpers, ok := dockerCfg["credHelpers"]
|
|
if !ok {
|
|
helpers = make(map[string]any)
|
|
}
|
|
helpersMap, ok := helpers.(map[string]any)
|
|
if !ok {
|
|
helpersMap = make(map[string]any)
|
|
}
|
|
|
|
helper := helperName(cfg)
|
|
|
|
// Check what needs to change
|
|
var toAdd []string
|
|
for _, host := range hosts {
|
|
current, exists := helpersMap[host]
|
|
if !exists || current != helper {
|
|
toAdd = append(toAdd, host)
|
|
}
|
|
}
|
|
|
|
if len(toAdd) == 0 {
|
|
fmt.Printf("Docker is already configured for all registries.\n")
|
|
return nil
|
|
}
|
|
|
|
fmt.Printf("Will update %s:\n", dockerConfigPath)
|
|
for _, host := range toAdd {
|
|
fmt.Printf(" + credHelpers[%q] = %q\n", host, helper)
|
|
}
|
|
fmt.Println()
|
|
|
|
var confirm bool
|
|
err = huh.NewConfirm().
|
|
Title("Apply changes?").
|
|
Value(&confirm).
|
|
Run()
|
|
if err != nil || !confirm {
|
|
fmt.Fprintf(os.Stderr, "Cancelled.\n")
|
|
return nil
|
|
}
|
|
|
|
// Apply changes
|
|
for _, host := range toAdd {
|
|
helpersMap[host] = helper
|
|
}
|
|
dockerCfg["credHelpers"] = helpersMap
|
|
|
|
// Remove conflicting credsStore if it exists and we're adding credHelpers
|
|
if _, hasStore := dockerCfg["credsStore"]; hasStore {
|
|
fmt.Fprintf(os.Stderr, "Note: credsStore is set — credHelpers takes precedence for configured registries.\n")
|
|
}
|
|
|
|
if err := saveDockerConfig(dockerConfigPath, dockerCfg); err != nil {
|
|
return fmt.Errorf("saving Docker config: %w", err)
|
|
}
|
|
|
|
fmt.Printf("Docker configured successfully.\n")
|
|
return nil
|
|
}
|
|
|
|
// getDockerConfigPath returns the path to Docker's config.json
|
|
func getDockerConfigPath() string {
|
|
// Check DOCKER_CONFIG env var first
|
|
if dir := os.Getenv("DOCKER_CONFIG"); dir != "" {
|
|
return filepath.Join(dir, "config.json")
|
|
}
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(homeDir, ".docker", "config.json")
|
|
}
|
|
|
|
// loadDockerConfig loads Docker's config.json as a generic map
|
|
func loadDockerConfig() map[string]any {
|
|
path := getDockerConfigPath()
|
|
if path == "" {
|
|
return nil
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
var config map[string]any
|
|
if err := json.Unmarshal(data, &config); err != nil {
|
|
return nil
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
// saveDockerConfig writes Docker's config.json
|
|
func saveDockerConfig(path string, config map[string]any) error {
|
|
// Ensure directory exists
|
|
dir := filepath.Dir(path)
|
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
|
return err
|
|
}
|
|
|
|
data, err := json.MarshalIndent(config, "", "\t")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data = append(data, '\n')
|
|
|
|
return os.WriteFile(path, data, 0600)
|
|
}
|