github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/builders/buildtarget/targets.go (about) 1 // Package buildtarget can generate a list of targets based on a matrix of 2 // goos, goarch, goarm, gomips and go version. 3 package buildtarget 4 5 import ( 6 "fmt" 7 "os" 8 "os/exec" 9 "regexp" 10 "strings" 11 12 "github.com/apex/log" 13 "github.com/fatih/color" 14 "github.com/goreleaser/goreleaser/pkg/config" 15 ) 16 17 type target struct { 18 os, arch, arm, mips string 19 } 20 21 func (t target) String() string { 22 if t.arm != "" { 23 return fmt.Sprintf("%s_%s_%s", t.os, t.arch, t.arm) 24 } 25 if t.mips != "" { 26 return fmt.Sprintf("%s_%s_%s", t.os, t.arch, t.mips) 27 } 28 return fmt.Sprintf("%s_%s", t.os, t.arch) 29 } 30 31 // List compiles the list of targets for the given builds. 32 func List(build config.Build) ([]string, error) { 33 version, err := goVersion(build) 34 if err != nil { 35 return nil, err 36 } 37 return matrix(build, version) 38 } 39 40 func matrix(build config.Build, version []byte) ([]string, error) { 41 // nolint:prealloc 42 var targets []target 43 // nolint:prealloc 44 var result []string 45 for _, target := range allBuildTargets(build) { 46 if !contains(target.os, validGoos) { 47 return result, fmt.Errorf("invalid goos: %s", target.os) 48 } 49 if !contains(target.arch, validGoarch) { 50 return result, fmt.Errorf("invalid goarch: %s", target.arch) 51 } 52 if target.arm != "" && !contains(target.arm, validGoarm) { 53 return result, fmt.Errorf("invalid goarm: %s", target.arm) 54 } 55 if target.mips != "" && !contains(target.mips, validGomips) { 56 return result, fmt.Errorf("invalid gomips: %s", target.mips) 57 } 58 if target.os == "darwin" && target.arch == "arm64" && !go116re.Match(version) { 59 log.Warn(color.New(color.Bold, color.FgHiYellow).Sprintf( 60 "DEPRECATED: skipped darwin/arm64 build on Go < 1.16 for compatibility, check %s for more info.", 61 "https://goreleaser.com/deprecations/#builds-for-darwinarm64", 62 )) 63 continue 64 } 65 if target.os == "windows" && target.arch == "arm64" && !go117re.Match(version) { 66 log.Warn(color.New(color.Bold, color.FgHiYellow).Sprintf( 67 "DEPRECATED: skipped windows/arm64 build on Go < 1.17 for compatibility, check %s for more info.", 68 "https://goreleaser.com/deprecations/#builds-for-windowsarm64", 69 )) 70 continue 71 } 72 if !valid(target) { 73 log.WithField("target", target).Debug("skipped invalid build") 74 continue 75 } 76 if ignored(build, target) { 77 log.WithField("target", target).Debug("skipped ignored build") 78 continue 79 } 80 targets = append(targets, target) 81 } 82 for _, target := range targets { 83 result = append(result, target.String()) 84 } 85 return result, nil 86 } 87 88 func allBuildTargets(build config.Build) (targets []target) { 89 for _, goos := range build.Goos { 90 for _, goarch := range build.Goarch { 91 if goarch == "arm" { 92 for _, goarm := range build.Goarm { 93 targets = append(targets, target{ 94 os: goos, 95 arch: goarch, 96 arm: goarm, 97 }) 98 } 99 continue 100 } 101 if strings.HasPrefix(goarch, "mips") { 102 for _, gomips := range build.Gomips { 103 targets = append(targets, target{ 104 os: goos, 105 arch: goarch, 106 mips: gomips, 107 }) 108 } 109 continue 110 } 111 targets = append(targets, target{ 112 os: goos, 113 arch: goarch, 114 }) 115 } 116 } 117 return 118 } 119 120 // TODO: this could be improved by using a map. 121 // https://github.com/goreleaser/goreleaser/pull/522#discussion_r164245014 122 func ignored(build config.Build, target target) bool { 123 for _, ig := range build.Ignore { 124 if ig.Goos != "" && ig.Goos != target.os { 125 continue 126 } 127 if ig.Goarch != "" && ig.Goarch != target.arch { 128 continue 129 } 130 if ig.Goarm != "" && ig.Goarm != target.arm { 131 continue 132 } 133 if ig.Gomips != "" && ig.Gomips != target.mips { 134 continue 135 } 136 return true 137 } 138 return false 139 } 140 141 var ( 142 go116re = regexp.MustCompile(`go version go1.1[6-9]`) 143 go117re = regexp.MustCompile(`go version go1.1[7-9]`) 144 ) 145 146 func goVersion(build config.Build) ([]byte, error) { 147 cmd := exec.Command(build.GoBinary, "version") 148 // If the build.Dir is acessible, set the cmd dir to it in case 149 // of reletive path to GoBinary 150 if _, err := os.Stat(build.Dir); err == nil { 151 cmd.Dir = build.Dir 152 } 153 bts, err := cmd.CombinedOutput() 154 if err != nil { 155 return nil, fmt.Errorf("unable to determine version of go binary (%s): %w", build.GoBinary, err) 156 } 157 return bts, nil 158 } 159 160 func valid(target target) bool { 161 return contains(target.os+target.arch, validTargets) 162 } 163 164 func contains(s string, ss []string) bool { 165 for _, z := range ss { 166 if z == s { 167 return true 168 } 169 } 170 return false 171 } 172 173 // lists from https://golang.org/doc/install/source#environment 174 // nolint: gochecknoglobals 175 var ( 176 validTargets = []string{ 177 "aixppc64", 178 "android386", 179 "androidamd64", 180 "androidarm", 181 "androidarm64", 182 "darwinamd64", 183 "darwinarm64", 184 "dragonflyamd64", 185 "freebsd386", 186 "freebsdamd64", 187 "freebsdarm", 188 "freebsdarm64", // not on the official list for some reason, yet its supported on go 1.14+ 189 "illumosamd64", 190 "jswasm", 191 "linux386", 192 "linuxamd64", 193 "linuxarm", 194 "linuxarm64", 195 "linuxppc64", 196 "linuxppc64le", 197 "linuxmips", 198 "linuxmipsle", 199 "linuxmips64", 200 "linuxmips64le", 201 "linuxs390x", 202 "linuxriscv64", 203 "netbsd386", 204 "netbsdamd64", 205 "netbsdarm", 206 "openbsd386", 207 "openbsdamd64", 208 "openbsdarm", 209 "openbsdarm64", 210 "plan9386", 211 "plan9amd64", 212 "plan9arm", 213 "solarisamd64", 214 "windowsarm", 215 "windowsarm64", 216 "windows386", 217 "windowsamd64", 218 } 219 220 validGoos = []string{ 221 "aix", 222 "android", 223 "darwin", 224 "dragonfly", 225 "freebsd", 226 "illumos", 227 "js", 228 "linux", 229 "netbsd", 230 "openbsd", 231 "plan9", 232 "solaris", 233 "windows", 234 } 235 236 validGoarch = []string{ 237 "386", 238 "amd64", 239 "arm", 240 "arm64", 241 "mips", 242 "mips64", 243 "mips64le", 244 "mipsle", 245 "ppc64", 246 "ppc64le", 247 "s390x", 248 "wasm", 249 "riscv64", 250 } 251 252 validGoarm = []string{"5", "6", "7"} 253 validGomips = []string{"hardfloat", "softfloat"} 254 )