From befeef34a57e2ea30fd9cc924c19bcf0156ee04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Budai?= Date: Thu, 22 Oct 2020 14:54:59 +0200 Subject: [PATCH] koji: use nvra as the filename for images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the same thing for AWS. The AWS target also specifies under what name should be the image available in EC2. As requested by Brew maintainers Tomáš Kopeček and Lubomír Sedlář. --- cmd/osbuild-worker/main.go | 4 +-- internal/kojiapi/server.go | 40 ++++++++++++++++++++++-- internal/kojiapi/server_internal_test.go | 24 ++++++++++++++ internal/target/koji_target.go | 1 + 4 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 internal/kojiapi/server_internal_test.go 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() {}