Skip to content

Commit 5507ed3

Browse files
committed
create-build: added --build option
uses the given path as the build context forwarded to podman build afterwards it extracts the name of the image and sets it to satisfy other assumption in existing code the test builds a Fedora 39 toolbx and checks if the image is successfully tagged as localhost/fedora-toolbox
1 parent e01c1ef commit 5507ed3

File tree

7 files changed

+113
-8
lines changed

7 files changed

+113
-8
lines changed

src/cmd/create.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var (
5454
distro string
5555
image string
5656
release string
57+
build string
5758
}
5859

5960
createToolboxShMounts = []struct {
@@ -104,6 +105,12 @@ func init() {
104105
"",
105106
"Create a Toolbx container for a different operating system release than the host")
106107

108+
flags.StringVarP(&createFlags.build,
109+
"build",
110+
"b",
111+
"",
112+
"Build a Toolbx container for use of this container")
113+
107114
createCmd.SetHelpFunc(createHelp)
108115

109116
if err := createCmd.RegisterFlagCompletionFunc("distro", completionDistroNames); err != nil {
@@ -150,6 +157,15 @@ func create(cmd *cobra.Command, args []string) error {
150157
return errors.New(errMsg)
151158
}
152159

160+
if cmd.Flag("build").Changed && (cmd.Flag("image").Changed || cmd.Flag("release").Changed || cmd.Flag("distro").Changed) {
161+
var builder strings.Builder
162+
fmt.Fprintf(&builder, "options --build and --release, --image or -- distro cannot be used together\n")
163+
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
164+
165+
errMsg := builder.String()
166+
return errors.New(errMsg)
167+
}
168+
153169
if cmd.Flag("authfile").Changed {
154170
if !utils.PathExists(createFlags.authFile) {
155171
var builder strings.Builder
@@ -177,7 +193,8 @@ func create(cmd *cobra.Command, args []string) error {
177193
containerArg,
178194
createFlags.distro,
179195
createFlags.image,
180-
createFlags.release)
196+
createFlags.release,
197+
createFlags.build)
181198

182199
if err != nil {
183200
return err

src/cmd/enter.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ func enter(cmd *cobra.Command, args []string) error {
111111
containerArg,
112112
enterFlags.distro,
113113
"",
114-
enterFlags.release)
114+
enterFlags.release,
115+
"")
115116

116117
if err != nil {
117118
return err

src/cmd/run.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ func run(cmd *cobra.Command, args []string) error {
130130
"--container",
131131
runFlags.distro,
132132
"",
133-
runFlags.release)
133+
runFlags.release,
134+
"")
134135

135136
if err != nil {
136137
return err

src/cmd/utils.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"strings"
3030
"syscall"
3131

32+
"github.com/containers/toolbox/pkg/podman"
3233
"github.com/containers/toolbox/pkg/utils"
3334
"github.com/sirupsen/logrus"
3435
"golang.org/x/sys/unix"
@@ -392,13 +393,26 @@ func poll(pollFn pollFunc, eventFD int32, fds ...int32) error {
392393
}
393394
}
394395

395-
func resolveContainerAndImageNames(container, containerArg, distroCLI, imageCLI, releaseCLI string) (
396+
func resolveContainerAndImageNames(container, containerArg, distroCLI, imageCLI, releaseCLI, buildCLI string) (
396397
string, string, string, error,
397398
) {
398-
container, image, release, err := utils.ResolveContainerAndImageNames(container,
399-
distroCLI,
400-
imageCLI,
401-
releaseCLI)
399+
var image, release string
400+
var err error
401+
if buildCLI == "" {
402+
container, image, release, err = utils.ResolveContainerAndImageNames(container,
403+
distroCLI,
404+
imageCLI,
405+
releaseCLI)
406+
} else {
407+
image, err = podman.BuildImage(buildCLI)
408+
if err != nil {
409+
return "", "", "", err
410+
}
411+
container, image, release, err = utils.ResolveContainerAndImageNames(container,
412+
distroCLI,
413+
image,
414+
releaseCLI)
415+
}
402416

403417
if err != nil {
404418
var errContainer *utils.ContainerError

src/pkg/podman/podman.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ package podman
1919
import (
2020
"bytes"
2121
"encoding/json"
22+
"errors"
2223
"fmt"
2324
"io"
25+
"os"
26+
"strings"
2427

2528
"github.com/HarryMichal/go-version"
2629
"github.com/containers/toolbox/pkg/shell"
@@ -45,6 +48,12 @@ var (
4548
LogLevel = logrus.ErrorLevel
4649
)
4750

51+
var (
52+
ErrBuildContextDoesNotExist = errors.New("build context does not exist")
53+
54+
ErrBuildContextInvalid = errors.New("build context is not a directory with a Containerfile")
55+
)
56+
4857
func (image *Image) FlattenNames(fillNameWithID bool) []Image {
4958
var ret []Image
5059

@@ -427,3 +436,41 @@ func SystemMigrate(ociRuntimeRequired string) error {
427436

428437
return nil
429438
}
439+
440+
func BuildImage(buildContext string) (string, error) {
441+
if !utils.PathExists(buildContext) {
442+
return "", &utils.BuildError{BuildContext: buildContext, Err: ErrBuildContextDoesNotExist}
443+
}
444+
if stat, err := os.Stat(buildContext); err != nil {
445+
return "", err
446+
} else {
447+
if !stat.Mode().IsDir() {
448+
return "", &utils.BuildError{BuildContext: buildContext, Err: ErrBuildContextInvalid}
449+
}
450+
}
451+
if !utils.PathExists(buildContext+"/Containerfile") && !utils.PathExists(buildContext+"/Dockerfile") {
452+
return "", &utils.BuildError{BuildContext: buildContext, Err: ErrBuildContextInvalid}
453+
}
454+
logLevelString := LogLevel.String()
455+
args := []string{"--log-level", logLevelString, "build", buildContext}
456+
457+
stdout := new(bytes.Buffer)
458+
if err := shell.Run("podman", nil, stdout, nil, args...); err != nil {
459+
return "", err
460+
}
461+
output := strings.TrimRight(stdout.String(), "\n")
462+
imageIdBegin := strings.LastIndex(output, "\n") + 1
463+
imageId := output[imageIdBegin:]
464+
465+
info, err := Inspect("image", imageId)
466+
if err != nil {
467+
return "", err
468+
}
469+
name := "localhost/" + info["Labels"].(map[string]interface{})["name"].(string)
470+
args = []string{"--log-level", logLevelString, "tag", imageId, name}
471+
if err := shell.Run("podman", nil, nil, nil, args...); err != nil {
472+
return "", err
473+
}
474+
475+
return name, nil
476+
}

src/pkg/utils/errors.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ type ParseReleaseError struct {
4040
Hint string
4141
}
4242

43+
type BuildError struct {
44+
BuildContext string
45+
Err error
46+
}
47+
4348
func (err *ContainerError) Error() string {
4449
errMsg := fmt.Sprintf("%s: %s", err.Container, err.Err)
4550
return errMsg
@@ -70,3 +75,8 @@ func (err *ImageError) Unwrap() error {
7075
func (err *ParseReleaseError) Error() string {
7176
return err.Hint
7277
}
78+
79+
func (err *BuildError) Error() string {
80+
errMsg := fmt.Sprintf("%s: %s", err.BuildContext, err.Err)
81+
return errMsg
82+
}

test/system/101-create.bats

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,3 +771,18 @@ teardown() {
771771
assert_line --index 1 "Enter with: toolbox enter fedora-toolbox-34"
772772
assert [ ${#lines[@]} -eq 2 ]
773773
}
774+
775+
@test "create: Build an image before creating the toolbox" {
776+
local build_context="./images/fedora/f39"
777+
778+
run "$TOOLBX" create --build "$build_context"
779+
assert_success
780+
781+
assert_line --index 0 "Created container: fedora-toolbox"
782+
assert_line --index 1 "Enter with: toolbox enter fedora-toolbox"
783+
assert [ ${#lines[@]} -eq 2 ]
784+
785+
run $PODMAN images --filter reference=localhost/fedora-toolbox
786+
assert_success
787+
assert [ $(#lines[@]) -eq 2 ]
788+
}

0 commit comments

Comments
 (0)