diff --git a/Makefile b/Makefile index 1eb378d..1bae5b3 100644 --- a/Makefile +++ b/Makefile @@ -18,3 +18,6 @@ dependencies: version: ./bin/docker-multi-arch-builder-darwin-amd64 --version + +install: build + install -m 755 bin/docker-multi-arch-builder-$(GOOS)-$(GOARCH) /usr/local/bin/docker-multi-arch-builder \ No newline at end of file diff --git a/cmd/build.go b/cmd/build.go index 28db081..5f138a8 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -2,40 +2,67 @@ package cmd import ( . "antoine-roux.tk/docker-multi-arch-builder/internal" + "fmt" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "strings" ) -var buildCmd = &cobra.Command{ - Use: "build", - Short: "Build all multi arch manifest", - Run: func(cmd *cobra.Command, args []string) { - myRegistry := Registry{ - Hostname: "docker.registry", - Port: 5000, - } +type BuildParam struct { + name string + registry string + port int + tag string + folder string + platforms Platforms +} - manifests := []ManifestImage{ - NewManifest( - "registry-ui", - "latest", - "../rasp/registry/ui/", - []Platform{LinuxArmV6}, - "", - ), - NewManifest( - "haproxy-k8s", - "latest", - "../dx30/haproxy-k8s", - []Platform{LinuxArm64, LinuxAmd64}, - "", - ), - } +var ( + buildParam = BuildParam{} + + buildCmd = &cobra.Command{ + Use: "build", + Short: "Build all multi arch manifest", + Run: func(cmd *cobra.Command, args []string) { + myRegistry := Registry{ + Hostname: buildParam.registry, + Port: buildParam.port, + } + + manifest := NewManifest( + buildParam.name, + buildParam.tag, + buildParam.folder, + buildParam.platforms, + strings.Join(args, " "), + ) - for _, manifest := range manifests { log.Infof("-> Deal with manifest %s folder %s\n", manifest.Name, manifest.BuildDir) manifest.CreateLayers(myRegistry) manifest.CreateManifest(myRegistry) - } - }, + }, + } +) + +func init() { + buildCmd.PersistentFlags().StringVarP(&buildParam.registry, "registry", "r", "docker.registry", "oci registry address") + buildCmd.PersistentFlags().IntVarP(&buildParam.port, "port", "p", 5000, "oci registry port") + + buildCmd.PersistentFlags().StringVarP(&buildParam.name, "name", "n", "", "oci target image name") + buildCmd.PersistentFlags().StringVarP(&buildParam.tag, "tag", "t", "latest", "oci target image tag") + + buildCmd.PersistentFlags().StringVarP(&buildParam.folder, "folder", "f", ".", "oci image tag") + buildCmd.PersistentFlags().Var( + newPlatformSliceValue(AllPlatforms, &buildParam.platforms), + "platforms", + fmt.Sprintf("oci target image platforms (default all : %s)", AllPlatforms.Join(", ")), + ) + buildCmd.MarkPersistentFlagRequired("name") +} + +func newPlatformSliceValue(val Platforms, p *Platforms) *PlatformsValue { + ssv := new(PlatformsValue) + ssv.Platforms = p + *ssv.Platforms = val + return ssv } diff --git a/internal/platform.go b/internal/platform.go index 9f36dac..206b7f2 100644 --- a/internal/platform.go +++ b/internal/platform.go @@ -1,5 +1,10 @@ package internal +import ( + "fmt" + "strings" +) + type Platform string const ( @@ -8,3 +13,85 @@ const ( LinuxArm64 Platform = "linux/arm64" LinuxAmd64 Platform = "linux/amd64" ) + +type Platforms []Platform + +var AllPlatforms = Platforms{LinuxArmV7, LinuxArmV6, LinuxArm64, LinuxAmd64} + +type PlatformsValue struct { + *Platforms + changed bool +} + +var isIncluded = func(opts Platforms, val Platform) bool { + for _, opt := range opts { + if val == opt { + return true + } + } + return false +} + +// Append adds the specified value to the end of the flag value list. +func (platforms *PlatformsValue) Append(value string) error { + if !isIncluded(AllPlatforms, Platform(value)) { + return fmt.Errorf("%s is not included in %s", value, AllPlatforms.Join(", ")) + } + *platforms.Platforms = append(*platforms.Platforms, Platform(value)) + return nil +} + +// Replace will fully overwrite any data currently in the flag value list. +func (platforms *PlatformsValue) Replace(values []string) error { + *platforms.Platforms = []Platform{} + for _, value := range values { + if !isIncluded(AllPlatforms, Platform(value)) { + return fmt.Errorf("%s is not included in %s", value, AllPlatforms.Join(", ")) + } + *platforms.Platforms = append(*platforms.Platforms, Platform(value)) + } + return nil +} + +// GetSlice returns the flag value list as an array of strings. +func (platforms *PlatformsValue) GetSlice() []string { + var platformsStr []string + for _, platform := range *platforms.Platforms { + platformsStr = append(platformsStr, string(platform)) + } + return platformsStr +} + +func (platforms PlatformsValue) String() string { + return "[" + platforms.Platforms.Join(",") + "]" +} + +func (platforms *PlatformsValue) Set(values string) error { + var valuesP []Platform + for _, value := range strings.Split(values, ",") { + valueP := Platform(value) + if !isIncluded(AllPlatforms, valueP) { + return fmt.Errorf("%s is not included in %s", value, AllPlatforms.Join(", ")) + } + if !platforms.changed || !isIncluded(*platforms.Platforms, valueP) { + valuesP = append(valuesP, valueP) + } + } + + if !platforms.changed { + *platforms.Platforms = valuesP + platforms.changed = true + } else { + *platforms.Platforms = append(*platforms.Platforms, valuesP...) + } + return nil +} + +func (platforms *PlatformsValue) Type() string { + return "platformSlice" +} + +func (platforms *Platforms) Join(sep string) string { + value := PlatformsValue{Platforms: platforms} + return strings.Join(value.GetSlice(), sep) +}