diff --git a/pkg/build/config.go b/pkg/build/config.go index 84e243c34e..1778f25404 100644 --- a/pkg/build/config.go +++ b/pkg/build/config.go @@ -79,6 +79,9 @@ type Config struct { // Env allows setting environment variables for `go build` Env []string `yaml:",omitempty"` + // Binary allows overriding the output binary name (in the image) + Binary string `yaml:",omitempty"` + // Other GoReleaser fields that are not supported or do not make sense // in the context of ko, for reference or for future use: // Goos []string `yaml:",omitempty"` @@ -86,7 +89,6 @@ type Config struct { // Goarm []string `yaml:",omitempty"` // Gomips []string `yaml:",omitempty"` // Targets []string `yaml:",omitempty"` - // Binary string `yaml:",omitempty"` // Lang string `yaml:",omitempty"` // Asmflags StringArray `yaml:",omitempty"` // Gcflags StringArray `yaml:",omitempty"` diff --git a/pkg/build/gobuild.go b/pkg/build/gobuild.go index 884460473d..cd707f7e1e 100644 --- a/pkg/build/gobuild.go +++ b/pkg/build/gobuild.go @@ -496,25 +496,39 @@ func tarBinary(name, binary string, platform *v1.Platform) (*bytes.Buffer, error // For Windows, the layer must contain a Hives/ directory, and the root // of the actual filesystem goes in a Files/ directory. // For Linux, the binary goes into /ko-app/ - dirs := []string{"ko-app"} + appDir := filepath.Dir(name) + dirs := []string{appDir} if platform.OS == "windows" { dirs = []string{ "Hives", - "Files", - "Files/ko-app", + "Files/" + appDir, } name = "Files" + name } for _, dir := range dirs { - if err := tw.WriteHeader(&tar.Header{ - Name: dir, - Typeflag: tar.TypeDir, - // Use a fixed Mode, so that this isn't sensitive to the directory and umask - // under which it was created. Additionally, windows can only set 0222, - // 0444, or 0666, none of which are executable. - Mode: 0555, - }); err != nil { - return nil, fmt.Errorf("writing dir %q to tar: %w", dir, err) + // Create all parent directories also + var parents []string + current := dir + for { + parents = append(parents, current) + current = filepath.Dir(current) + if current == "/" { + break + } + } + + for i := len(parents) - 1; i >= 0; i-- { + parent := parents[i] + if err := tw.WriteHeader(&tar.Header{ + Name: parent, + Typeflag: tar.TypeDir, + // Use a fixed Mode, so that this isn't sensitive to the directory and umask + // under which it was created. Additionally, windows can only set 0222, + // 0444, or 0666, none of which are executable. + Mode: 0555, + }); err != nil { + return nil, fmt.Errorf("writing dir %q to tar: %w", parent, err) + } } } @@ -789,6 +803,14 @@ func (g *gobuild) configForImportPath(ip string) Config { return config } +// pathToWindows converts a unix-style path to a windows-style path. +// For example, /apps/foo => C:\apps\foo +func pathToWindows(s string) string { + pathComponents := []string{"C:"} + pathComponents = append(pathComponents, strings.Split(s, "/")...) + return strings.Join(pathComponents, `\`) +} + func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, platform *v1.Platform) (oci.SignedImage, error) { if err := g.semaphore.Acquire(ctx, 1); err != nil { return nil, err @@ -859,9 +881,13 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl }, }) - appDir := "/ko-app" - appFileName := appFilename(ref.Path()) - appPath := path.Join(appDir, appFileName) + config := g.configForImportPath(ref.Path()) + appPath := config.Binary + if appPath == "" { + appPath = path.Join("/ko-app", appFilename(ref.Path())) + } + appDir := path.Dir(appPath) + appFileName := path.Base(appPath) miss := func() (v1.Layer, error) { return buildLayer(appPath, file, platform, layerMediaType) @@ -900,8 +926,8 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl cfg.Config.Entrypoint = []string{appPath} cfg.Config.Cmd = nil if platform.OS == "windows" { - cfg.Config.Entrypoint = []string{`C:\ko-app\` + appFileName} - updatePath(cfg, `C:\ko-app`) + cfg.Config.Entrypoint = []string{pathToWindows(appPath)} + updatePath(cfg, pathToWindows(filepath.Dir(appPath))) cfg.Config.Env = append(cfg.Config.Env, `KO_DATA_PATH=C:\var\run\ko`) } else { updatePath(cfg, appDir)