diff --git a/cmd/osbuild-worker/main.go b/cmd/osbuild-worker/main.go index ce9473f52..797c1d6ad 100644 --- a/cmd/osbuild-worker/main.go +++ b/cmd/osbuild-worker/main.go @@ -231,7 +231,7 @@ func RunJob(job worker.Job, store string, kojiServers map[string]koji.GSSAPICred continue } - hash, filesize, err := k.Upload(f, options.UploadDirectory, options.Filename) + hash, filesize, err := k.Upload(f, options.UploadDirectory, options.KojiFilename) if err != nil { r = append(r, err) continue @@ -274,7 +274,7 @@ func RunJob(job worker.Job, store string, kojiServers map[string]koji.GSSAPICred output := []koji.Image{ { BuildRootID: 1, - Filename: options.Filename, + Filename: options.KojiFilename, FileSize: uint64(filesize), Arch: common.CurrentArch(), ChecksumType: "md5", diff --git a/internal/kojiapi/server.go b/internal/kojiapi/server.go index ec3b927d6..8666c3672 100644 --- a/internal/kojiapi/server.go +++ b/internal/kojiapi/server.go @@ -8,9 +8,11 @@ import ( "log" "net/http" "net/url" + "strings" "github.com/google/uuid" "github.com/labstack/echo/v4" + "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/distro" @@ -85,9 +87,10 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error { } type imageRequest struct { - manifest distro.Manifest - arch string - filename string + manifest distro.Manifest + arch string + filename string + kojiFilename string } imageRequests := make([]imageRequest, len(request.ImageRequests)) @@ -131,6 +134,17 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error { imageRequests[i].manifest = manifest imageRequests[i].arch = arch.Name() imageRequests[i].filename = imageType.Filename() + + filename := fmt.Sprintf( + "%s-%s-%s.%s%s", + request.Name, + request.Version, + request.Release, + ir.Architecture, + splitExtension(imageType.Filename()), + ) + + imageRequests[i].kojiFilename = filename } var ir imageRequest @@ -176,6 +190,7 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error { Filename: ir.filename, UploadDirectory: "osbuild-composer-koji-" + uuid.New().String(), Server: request.Koji.Server, + KojiFilename: ir.kojiFilename, }), }) if err != nil { @@ -189,6 +204,25 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error { }) } +// splitExtension returns the extension of the given file. If there's +// a multipart extension (e.g. file.tar.gz), it returns all parts (e.g. +// .tar.gz). If there's no extension in the input, it returns an empty +// string. If the filename starts with dot, the part before the second dot +// is not considered as an extension. +func splitExtension(filename string) string { + filenameParts := strings.Split(filename, ".") + + if len(filenameParts) > 0 && filenameParts[0] == "" { + filenameParts = filenameParts[1:] + } + + if len(filenameParts) <= 1 { + return "" + } + + return "." + strings.Join(filenameParts[1:], ".") +} + func composeStateToStatus(state common.ComposeState) string { switch state { case common.CFailed: diff --git a/internal/kojiapi/server_internal_test.go b/internal/kojiapi/server_internal_test.go new file mode 100644 index 000000000..1dc5f5aa7 --- /dev/null +++ b/internal/kojiapi/server_internal_test.go @@ -0,0 +1,24 @@ +package kojiapi + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestSplitExtension(t *testing.T) { + tests := []struct { + filename string + extension string + }{ + {filename: "image.qcow2", extension: ".qcow2"}, + {filename: "image.tar.gz", extension: ".tar.gz"}, + {filename: "", extension: ""}, + {filename: ".htaccess", extension: ""}, + {filename: ".weirdfile.txt", extension: ".txt"}, + } + for _, tt := range tests { + t.Run(tt.filename, func(t *testing.T) { + require.Equal(t, tt.extension, splitExtension(tt.filename)) + }) + } +} diff --git a/internal/target/koji_target.go b/internal/target/koji_target.go index 6b059e3ab..de93f0d66 100644 --- a/internal/target/koji_target.go +++ b/internal/target/koji_target.go @@ -10,6 +10,7 @@ type KojiTargetOptions struct { Filename string `json:"filename"` UploadDirectory string `json:"upload_directory"` Server string `json:"server"` + KojiFilename string `json:"koji_filename"` } func (KojiTargetOptions) isTargetOptions() {}