package pi import ( "bufio" "errors" "fmt" "os" "path/filepath" "regexp" "strings" ) var defaultPiArgPattern = regexp.MustCompile(`^ARG[[:space:]]+PI_VERSION[[:space:]]*=(.*)$`) // ReadPinnedVersion reads the repository's declared Pi runtime version. It deliberately reads // only the default ARG, not the later ARG PI_VERSION declarations used by build stages. func ReadPinnedVersion(projectDirectory string) (string, error) { path := filepath.Join(projectDirectory, "docker", "core.Dockerfile") file, err := os.Open(path) if err != nil { return "", fmt.Errorf("read Pi version pin: %w", err) } defer file.Close() var version string count := 0 scanner := bufio.NewScanner(file) for scanner.Scan() { match := defaultPiArgPattern.FindStringSubmatch(strings.TrimSuffix(scanner.Text(), "\r")) if len(match) != 2 { continue } count++ version = strings.TrimSpace(match[1]) } if err := scanner.Err(); err != nil { return "", fmt.Errorf("read Pi version pin: %w", err) } if count != 1 { return "", errors.New("docker/core.Dockerfile must contain exactly one default PI_VERSION") } if _, err := parseSemanticVersion(version); err != nil { return "", errors.New("docker/core.Dockerfile contains an invalid Pi version") } return version, nil }