|
7 | 7 | "os"
|
8 | 8 | "strings"
|
9 | 9 |
|
| 10 | + nameref "github.com/google/go-containerregistry/pkg/name" |
10 | 11 | "github.com/spf13/cobra"
|
11 | 12 |
|
12 | 13 | "github.com/StacklokLabs/toolhive/pkg/container"
|
@@ -146,14 +147,26 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
|
146 | 147 | logDebug(debugMode, "Server '%s' not found in registry, treating as Docker image", serverOrImage)
|
147 | 148 | config.Image = serverOrImage
|
148 | 149 | }
|
| 150 | + // Check if the image has the "latest" tag |
| 151 | + isLatestTag := hasLatestTag(config.Image) |
149 | 152 |
|
150 |
| - // Check if the image exists locally, and pull it if not |
| 153 | + // Check if the image exists locally |
151 | 154 | imageExists, err := runtime.ImageExists(ctx, config.Image)
|
152 | 155 | if err != nil {
|
153 | 156 | return fmt.Errorf("failed to check if image exists: %v", err)
|
154 | 157 | }
|
155 |
| - if !imageExists { |
156 |
| - logger.Log.Info(fmt.Sprintf("Image %s not found locally, pulling...", config.Image)) |
| 158 | + |
| 159 | + // Always pull if the tag is "latest" or if the image doesn't exist locally |
| 160 | + if isLatestTag || !imageExists { |
| 161 | + var pullMsg string |
| 162 | + if !imageExists { |
| 163 | + pullMsg = "Image %s not found locally, pulling..." |
| 164 | + } |
| 165 | + if isLatestTag && imageExists { |
| 166 | + pullMsg = "Image %s has 'latest' tag, pulling to ensure we have the most recent version..." |
| 167 | + } |
| 168 | + |
| 169 | + logger.Log.Info(fmt.Sprintf(pullMsg, config.Image)) |
157 | 170 | if err := runtime.PullImage(ctx, config.Image); err != nil {
|
158 | 171 | return fmt.Errorf("failed to pull image: %v", err)
|
159 | 172 | }
|
@@ -267,6 +280,27 @@ func isEnvVarProvided(name string, envVars []string, secrets []string) bool {
|
267 | 280 | return findEnvironmentVariableFromSecrets(secrets, name)
|
268 | 281 | }
|
269 | 282 |
|
| 283 | +// hasLatestTag checks if the given image reference has the "latest" tag or no tag (which defaults to "latest") |
| 284 | +func hasLatestTag(imageRef string) bool { |
| 285 | + ref, err := nameref.ParseReference(imageRef) |
| 286 | + if err != nil { |
| 287 | + // If we can't parse the reference, assume it's not "latest" |
| 288 | + logger.Log.Warn(fmt.Sprintf("Warning: Failed to parse image reference: %v", err)) |
| 289 | + return false |
| 290 | + } |
| 291 | + |
| 292 | + // Check if the reference is a tag |
| 293 | + if taggedRef, ok := ref.(nameref.Tag); ok { |
| 294 | + // Check if the tag is "latest" |
| 295 | + return taggedRef.TagStr() == "latest" |
| 296 | + } |
| 297 | + |
| 298 | + // If the reference is not a tag (e.g., it's a digest), it's not "latest" |
| 299 | + // If no tag was specified, it defaults to "latest" |
| 300 | + _, isDigest := ref.(nameref.Digest) |
| 301 | + return !isDigest |
| 302 | +} |
| 303 | + |
270 | 304 | // createPermissionProfileFile creates a temporary file with the permission profile
|
271 | 305 | func createPermissionProfileFile(serverName string, permProfile *permissions.Profile, debugMode bool) (string, error) {
|
272 | 306 | tempFile, err := os.CreateTemp("", fmt.Sprintf("toolhive-%s-permissions-*.json", serverName))
|
|
0 commit comments