add HAKO-VERSION checking

This commit is contained in:
Luna 2025-06-10 21:39:03 -03:00
parent 33f45eae02
commit 30a510cb17
6 changed files with 68 additions and 33 deletions

View file

@ -19,7 +19,8 @@ Hako is a Docker container management tool designed specifically for Claude Code
- Container names follow pattern: `hako-{language}-{project}-{subdirs}` (sanitized, max 60 chars) - Container names follow pattern: `hako-{language}-{project}-{subdirs}` (sanitized, max 60 chars)
- All Docker commands are logged to stderr for transparency - All Docker commands are logged to stderr for transparency
- File syncing respects .gitignore and excludes .git directory for security - File syncing respects .gitignore and excludes .git directory for security
- Images are versioned (HAKO-VERSION=1) for upgrade management - Images are versioned (HAKO-VERSION=1, as a Docker label) for upgrade management
- NOTE: changes to the base Dockerfiles should involve bumping the hako version
## Development Commands ## Development Commands

View file

@ -19,6 +19,9 @@ func initCommand(lang string) error {
if err := buildBaseImage(); err != nil { if err := buildBaseImage(); err != nil {
return err return err
} }
} else {
// Check base image version
checkVersionMismatch("hako-userland")
} }
fmt.Printf("Building %s language image...\n", lang) fmt.Printf("Building %s language image...\n", lang)
@ -36,6 +39,9 @@ func upCommand(lang string) error {
return fmt.Errorf("image %s not found, run 'hako init %s' first", imageName, lang) return fmt.Errorf("image %s not found, run 'hako init %s' first", imageName, lang)
} }
// Check for version mismatch
checkVersionMismatch(imageName)
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return err return err
@ -103,7 +109,24 @@ func downCommand(container string) error {
func psCommand() error { func psCommand() error {
fmt.Println("Hako containers:") fmt.Println("Hako containers:")
return listHakoContainers() if err := listHakoContainers(); err != nil {
return err
}
// Check for version mismatches in running containers
output, err := runCommandOutput("docker", "ps", "-a", "--filter", "name=hako-", "--format", "{{.Image}}")
if err == nil {
images := strings.Split(strings.TrimSpace(output), "\n")
checkedImages := make(map[string]bool)
for _, image := range images {
if image != "" && !checkedImages[image] {
checkVersionMismatch(image)
checkedImages[image] = true
}
}
}
return nil
} }
func syncCommand() error { func syncCommand() error {

View file

@ -28,8 +28,8 @@ func ensureConfigDir() error {
} }
func getBaseDockerfile() string { func getBaseDockerfile() string {
return fmt.Sprintf(`# HAKO-VERSION=%s return fmt.Sprintf(`FROM debian:trixie-20250610
FROM debian:trixie-20250610 LABEL HAKO-VERSION=%s
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
curl \ curl \
@ -57,17 +57,17 @@ CMD ["/usr/bin/fish"]`, hakoVersion)
func getLanguageDockerfile(lang string) string { func getLanguageDockerfile(lang string) string {
switch lang { switch lang {
case "go": case "go":
return fmt.Sprintf(`# HAKO-VERSION=%s return fmt.Sprintf(`FROM hako-userland
FROM hako-userland LABEL HAKO-VERSION=%s
RUN curl -fsSL https://go.dev/dl/go1.21.5.linux-amd64.tar.gz | tar -C /usr/local -xzf - RUN curl -fsSL https://go.dev/dl/go1.21.5.linux-amd64.tar.gz | tar -C /usr/local -xzf -
ENV PATH="/usr/local/go/bin:${PATH}" ENV PATH="/usr/local/go/bin:${PATH}"
WORKDIR /workspace WORKDIR /workspace
CMD ["/bin/bash"]`, hakoVersion) CMD ["/usr/bin/fish"]`, hakoVersion)
case "py", "python": case "py", "python":
return fmt.Sprintf(`# HAKO-VERSION=%s return fmt.Sprintf(`FROM hako-userland
FROM hako-userland LABEL HAKO-VERSION=%s
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
python3 \ python3 \
@ -78,7 +78,7 @@ RUN apt-get update && apt-get install -y \
RUN ln -s /usr/bin/python3 /usr/bin/python RUN ln -s /usr/bin/python3 /usr/bin/python
WORKDIR /workspace WORKDIR /workspace
CMD ["/bin/bash"]`, hakoVersion) CMD ["/usr/bin/fish"]`, hakoVersion)
default: default:
return "" return ""
} }
@ -148,7 +148,6 @@ func createContainer(containerName, imageName, workspaceDir string) error {
// Mount workspace // Mount workspace
args = append(args, "-v", workspaceDir+":/workspace") args = append(args, "-v", workspaceDir+":/workspace")
args = append(args, "-it", imageName) args = append(args, "-it", imageName)
if err := runCommand("docker", args...); err != nil { if err := runCommand("docker", args...); err != nil {
@ -206,3 +205,24 @@ func copyFromContainer(containerName, srcPath, destPath string) error {
func listHakoContainers() error { func listHakoContainers() error {
return runCommand("docker", "ps", "-a", "--filter", "name=hako-", "--format", "table {{.Names}}\\t{{.Status}}\\t{{.Image}}") return runCommand("docker", "ps", "-a", "--filter", "name=hako-", "--format", "table {{.Names}}\\t{{.Status}}\\t{{.Image}}")
} }
func getImageVersion(imageName string) (string, error) {
output, err := runCommandOutput("docker", "image", "inspect", "-f", "{{index .Config.Labels \"HAKO-VERSION\"}}", imageName)
if err != nil {
return "", err
}
return strings.TrimSpace(output), nil
}
func checkVersionMismatch(imageName string) {
imageVersion, err := getImageVersion(imageName)
if err != nil {
// If we can't get the version, don't warn (might be old image without version)
return
}
if imageVersion != "" && imageVersion != hakoVersion {
fmt.Printf("\033[33mWarning: Image %s has version %s but hako executable is version %s\033[0m\n", imageName, imageVersion, hakoVersion)
fmt.Printf("\033[33mConsider running 'hako init' to rebuild with the current version\033[0m\n")
}
}

View file

@ -24,12 +24,3 @@ func runCommandOutput(name string, args ...string) (string, error) {
} }
return strings.TrimSpace(string(output)), nil return strings.TrimSpace(string(output)), nil
} }
func runCommandWithInput(name string, input string, args ...string) error {
cmd := exec.Command(name, args...)
fmt.Fprintf(os.Stderr, "+ %s %s\n", name, strings.Join(args, " "))
cmd.Stdin = strings.NewReader(input)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}