Skip to content

Commit e5c2707

Browse files
committed
Unify pull with image create
1 parent b6783ad commit e5c2707

4 files changed

Lines changed: 59 additions & 62 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ go run cmd/hypeman/main.go
3131
## Usage
3232

3333
```sh
34-
# Pull an image
35-
hypeman pull nginx:alpine
34+
# Create an image (or use `hypeman pull` as an alias)
35+
hypeman image create nginx:alpine
3636

3737
# Boot a new VM (auto-pulls image if needed)
3838
hypeman run --name my-app nginx:alpine

pkg/cmd/imagecmd.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,10 @@ var imageCmd = cli.Command{
2525
}
2626

2727
var imageCreateCmd = cli.Command{
28-
Name: "create",
29-
Usage: "Pull and convert an OCI image",
30-
ArgsUsage: "<name>",
31-
Flags: []cli.Flag{
32-
&cli.StringSliceFlag{
33-
Name: "tag",
34-
Usage: "Set image tag key-value pair (KEY=VALUE, can be repeated)",
35-
},
36-
},
28+
Name: "create",
29+
Usage: "Pull and convert an OCI image",
30+
ArgsUsage: "<name>",
31+
Flags: imageCreateFlags(),
3732
Action: handleImageCreate,
3833
HideHelpCommand: true,
3934
}
@@ -149,24 +144,21 @@ func handleImageList(ctx context.Context, cmd *cli.Command) error {
149144
}
150145

151146
func handleImageCreate(ctx context.Context, cmd *cli.Command) error {
147+
return handleImageCreateLike(ctx, cmd, "hypeman image create <name>", "image create")
148+
}
149+
150+
func handleImageCreateLike(ctx context.Context, cmd *cli.Command, usageLine, outputLabel string) error {
152151
args := cmd.Args().Slice()
153152
if len(args) < 1 {
154-
return fmt.Errorf("image name required\nUsage: hypeman image create <name>")
153+
return fmt.Errorf("image name required\nUsage: %s", usageLine)
155154
}
156155

157156
client := hypeman.NewClient(getDefaultRequestOptions(cmd)...)
158157

159-
params := hypeman.ImageNewParams{
160-
Name: args[0],
161-
}
162-
163-
tags, malformedTags := parseKeyValueSpecs(cmd.StringSlice("tag"))
158+
params, malformedTags := buildImageNewParams(args[0], cmd.StringSlice("tag"))
164159
for _, malformed := range malformedTags {
165160
fmt.Fprintf(os.Stderr, "Warning: ignoring malformed tag: %s\n", malformed)
166161
}
167-
if len(tags) > 0 {
168-
params.Tags = tags
169-
}
170162

171163
var opts []option.RequestOption
172164
if cmd.Root().Bool("debug") {
@@ -184,7 +176,7 @@ func handleImageCreate(ctx context.Context, cmd *cli.Command) error {
184176
return err
185177
}
186178
obj := gjson.ParseBytes(res)
187-
return ShowJSON(os.Stdout, "image create", obj, format, transform)
179+
return ShowJSON(os.Stdout, outputLabel, obj, format, transform)
188180
}
189181

190182
result, err := client.Images.New(ctx, params, opts...)
@@ -195,6 +187,26 @@ func handleImageCreate(ctx context.Context, cmd *cli.Command) error {
195187
return nil
196188
}
197189

190+
func imageCreateFlags() []cli.Flag {
191+
return []cli.Flag{
192+
&cli.StringSliceFlag{
193+
Name: "tag",
194+
Usage: "Set image tag key-value pair (KEY=VALUE, can be repeated)",
195+
},
196+
}
197+
}
198+
199+
func buildImageNewParams(name string, tagSpecs []string) (hypeman.ImageNewParams, []string) {
200+
params := hypeman.ImageNewParams{Name: name}
201+
202+
tags, malformedTags := parseKeyValueSpecs(tagSpecs)
203+
if len(tags) > 0 {
204+
params.Tags = tags
205+
}
206+
207+
return params, malformedTags
208+
}
209+
198210
func handleImageGet(ctx context.Context, cmd *cli.Command) error {
199211
args := cmd.Args().Slice()
200212
if len(args) < 1 {

pkg/cmd/imagecmd_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package cmd
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestBuildImageNewParams(t *testing.T) {
11+
params, malformed := buildImageNewParams("docker.io/library/alpine:latest", []string{
12+
"env=staging",
13+
"team=cli",
14+
"missing-delimiter",
15+
})
16+
17+
require.Equal(t, "docker.io/library/alpine:latest", params.Name)
18+
assert.Equal(t, map[string]string{
19+
"env": "staging",
20+
"team": "cli",
21+
}, params.Tags)
22+
assert.Equal(t, []string{"missing-delimiter"}, malformed)
23+
}

pkg/cmd/pull.go

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,19 @@ package cmd
22

33
import (
44
"context"
5-
"fmt"
6-
"os"
75

8-
"github.com/kernel/hypeman-go"
9-
"github.com/kernel/hypeman-go/option"
106
"github.com/urfave/cli/v3"
117
)
128

139
var pullCmd = cli.Command{
1410
Name: "pull",
15-
Usage: "Pull an image from a registry",
11+
Usage: "Alias for `image create`",
1612
ArgsUsage: "<image>",
13+
Flags: imageCreateFlags(),
1714
Action: handlePull,
1815
HideHelpCommand: true,
1916
}
2017

2118
func handlePull(ctx context.Context, cmd *cli.Command) error {
22-
args := cmd.Args().Slice()
23-
if len(args) < 1 {
24-
return fmt.Errorf("image reference required\nUsage: hypeman pull <image>")
25-
}
26-
27-
image := args[0]
28-
29-
fmt.Fprintf(os.Stderr, "Pulling %s...\n", image)
30-
31-
client := hypeman.NewClient(getDefaultRequestOptions(cmd)...)
32-
33-
params := hypeman.ImageNewParams{
34-
Name: image,
35-
}
36-
37-
var opts []option.RequestOption
38-
if cmd.Root().Bool("debug") {
39-
opts = append(opts, debugMiddlewareOption)
40-
}
41-
42-
result, err := client.Images.New(
43-
ctx,
44-
params,
45-
opts...,
46-
)
47-
if err != nil {
48-
return err
49-
}
50-
51-
fmt.Fprintf(os.Stderr, "Status: %s\n", result.Status)
52-
if result.Digest != "" {
53-
fmt.Fprintf(os.Stderr, "Digest: %s\n", result.Digest)
54-
}
55-
fmt.Fprintf(os.Stderr, "Image: %s\n", result.Name)
56-
57-
return nil
19+
return handleImageCreateLike(ctx, cmd, "hypeman pull <image>", "pull")
5820
}

0 commit comments

Comments
 (0)