Repository: moby/moby
File: testutil/fakestorage/fixtures.go (Go)

Code before:
	defer testEnv.ProtectImage(t, "httpserver:latest")

	tmp := t.TempDir()

	goos := testEnv.DaemonInfo.OSType
	if goos == "" {
		goos = "linux"
	}
	goarch := testEnv.DaemonVersion.Arch
	if goarch == "" {
		goarch = "amd64"
	}

	cpCmd, lookErr := exec.LookPath("cp")
	if lookErr != nil {
		t.Fatalf("could not build http server: %v", lookErr)
	}

	if _, err := os.Stat("../contrib/httpserver/httpserver"); os.IsNotExist(err) {
		goCmd, lookErr := exec.LookPath("go")
		if lookErr != nil {
			t.Fatalf("could not build http server: %v", lookErr)
		}

		cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/moby/moby/v2/contrib/httpserver")
		cmd.Env = append(os.Environ(), []string{
			"CGO_ENABLED=0",
			"GOOS=" + goos,
			"GOARCH=" + goarch,
		}...)
		var out []byte
		if out, err = cmd.CombinedOutput(); err != nil {
			t.Fatalf("could not build http server: %s", string(out))
		}
	} else {
		if out, err := exec.Command(cpCmd, "../contrib/httpserver/httpserver", filepath.Join(tmp, "httpserver")).CombinedOutput(); err != nil {
			t.Fatalf("could not copy http server: %v", string(out))
		}
	}

	if out, err := exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
		t.Fatalf("could not build http server: %v", string(out))
	}

	c := testEnv.APIClient()
	reader, err := archive.TarWithOptions(tmp, &archive.TarOptions{})
	assert.NilError(t, err)
	resp, err := c.ImageBuild(context.Background(), reader, build.ImageBuildOptions{
		Remove:      true,
		ForceRemove: true,
		Tags:        []string{"httpserver"},

Review comment (suggestion):
It's slightly ugly to put this in a const, but with the current handling of "create a temporary build-context _somewhere_, add some other files, then do a build", it was easier to do a `os.WriteFile()` with the source then to move or copy files around.

We should probably have another look at this package and logic used in future.

Code after:
	goos := testEnv.DaemonInfo.OSType
	if goos == "" {
		goos = "linux"
	}
	goarch := testEnv.DaemonVersion.Arch
	if goarch == "" {
		goarch = "amd64"
	}

	goCmd, err := exec.LookPath("go")
	assert.NilError(t, err, "could not find go executable to build http server")

	tmp := t.TempDir()
	const httpServer = `package main

import (
	"log"
	"net/http"
)

func main() {
	fs := http.FileServer(http.Dir("/static"))
	http.Handle("/", fs)
	log.Panic(http.ListenAndServe(":80", nil)) // #nosec G114 -- Ignoring for test-code: G114: Use of net/http serve function that has no support for setting timeouts (gosec)
}
`
	src := filepath.Join(tmp, "main.go")
	err = os.WriteFile(filepath.Join(tmp, "main.go"), []byte(httpServer), 0o0644)
	assert.NilError(t, err)

	cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), src)
	cmd.Env = append(os.Environ(), []string{
		"CGO_ENABLED=0",
		"GOOS=" + goos,
		"GOARCH=" + goarch,
	}...)
	out, err := cmd.CombinedOutput()
	assert.NilError(t, err, "could not build http server: %s", string(out))
	const dockerfile = `FROM scratch
EXPOSE 80/tcp
COPY httpserver .
CMD ["./httpserver"]
`
	err = os.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte(dockerfile), 0o644)
	assert.NilError(t, err, "could not write Dockerfile")
	reader, err := archive.TarWithOptions(tmp, &archive.TarOptions{})
	assert.NilError(t, err)

	apiClient := testEnv.APIClient()
	resp, err := apiClient.ImageBuild(context.Background(), reader, build.ImageBuildOptions{
		Remove:      true,