11package main
22
33import (
4+ "bytes"
45 "fmt"
6+ "io"
57 "io/fs"
68 "log"
79 "os"
@@ -10,7 +12,19 @@ import (
1012 "strings"
1113)
1214
15+ func buildClean () {
16+ cwd , err := os .Getwd ()
17+ exitIfErr (err )
18+
19+ productOutputFolder := filepath .Join (cwd , defaultGoBuildOutputFolder )
20+
21+ err = os .RemoveAll (productOutputFolder )
22+ exitIfErr (err )
23+ }
24+
1325func build () {
26+ buildClean ()
27+
1428 buildConfig , cwd := genBuildConfig ()
1529
1630 productOutputFolder := filepath .Join (cwd , defaultGoBuildOutputFolder )
@@ -20,65 +34,22 @@ func build() {
2034 log .Printf ("config : %v\n " , buildConfig .Config )
2135 log .Printf ("build : %s @ %s\n " , buildConfig .Binary , buildConfig .Version )
2236
23- err := os .RemoveAll (productOutputFolder )
37+ err := os .MkdirAll (productOutputFolder , os . FileMode ( 0755 ) )
2438 exitIfErr (err )
2539
26- err = os .MkdirAll (productOutputFolder , os .FileMode (0755 ))
27- exitIfErr (err )
28-
29- var debugFlags = ""
30- if false {
31- debugFlags = "-tags debug"
32- }
33-
3440 var ldFlags = fmt .Sprintf ("-s -w -X main.version=\" %s\" " , buildConfig .Version )
3541
3642 // format: $binary_$version-$os.$arch-$details.$ext
3743 for _ , platform := range buildConfig .Config .Platforms {
38- // get OS + ARCH
39- productOSAndArch := strings .Split (platform , "/" )
40-
41- productOS := ""
42- productOSLabel := ""
43- if len (productOSAndArch ) > 0 {
44- productOS = productOSAndArch [0 ]
45- productOSLabel = productOS
46- if _ , hasKey := osToDisplay [productOS ]; hasKey {
47- productOSLabel = osToDisplay [productOS ]
48- }
49- }
50-
51- productArch := ""
52- productArchLabel := ""
53- if len (productOSAndArch ) > 1 {
54- productArch = productOSAndArch [1 ]
55- productArchLabel = productArch
56- if _ , hasKey := archToDisplay [productArch ]; hasKey {
57- productArchLabel = archToDisplay [productArch ]
58- }
59- }
60-
61- productArmVersion := ""
62- if len (productOSAndArch ) > 2 {
63- productArmVersion = productOSAndArch [2 ]
64- }
65-
66- productArchWithDetails := productArchLabel
67- if productArmVersion != "" {
68- productArchWithDetails = fmt .Sprintf ("%s-v%s" , productArchLabel , productArmVersion )
69- }
70-
71- productExt := ""
72- if _ , hasKey := osToExt [productOS ]; hasKey {
73- productExt = osToExt [productOS ]
74- }
44+ target , err := parsePlatform (platform )
45+ exitIfErr (err )
7546
7647 productBinaryName := buildConfig .Binary + "_v" + buildConfig .Version
7748 outputFile := filepath .Join (productOutputFolder , fmt .Sprintf ("%s_%s-%s%s" ,
7849 productBinaryName ,
79- productOSLabel ,
80- productArchWithDetails ,
81- productExt ,
50+ target . productOSLabel ,
51+ target . productArchWithDetails ,
52+ target . productExt ,
8253 ))
8354
8455 log .Printf (" -> %-55s \n " , filepath .Base (outputFile ))
@@ -89,10 +60,15 @@ func build() {
8960 cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("%s=%s" , productEnvK , productEnvV ))
9061 }
9162
92- cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOOS=%s" , productOS ))
93- cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOARCH=%s" , productArch ))
94- if productArmVersion != "" {
95- cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOARM=%s" , productArmVersion ))
63+ cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOOS=%s" , target .productOS ))
64+ cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOARCH=%s" , target .productArch ))
65+ if target .productArmVersion != "" {
66+ cmdToRunEnv = append (cmdToRunEnv , fmt .Sprintf ("GOARM=%s" , target .productArmVersion ))
67+ }
68+
69+ var debugFlags = ""
70+ if false {
71+ debugFlags = "-tags debug"
9672 }
9773
9874 cmdToRun := exec .Command ("go" , "build" )
@@ -106,38 +82,128 @@ func build() {
10682 cmdToRun .Dir = buildConfig .GoModFolder
10783 cmdToRun .Stderr = os .Stderr
10884 cmdToRun .Stdout = os .Stdout
109- err = cmdToRun .Run ()
110- exitIfErr (err )
85+ if err := cmdToRun .Run (); err != nil {
86+ exitIfErr (fmt .Errorf ("build %q: %w" , platform , err ))
87+ }
11188 }
11289
113- // run compressor
114- if buildConfig .Config .Compress {
115- if _ , err := exec .LookPath (buildConfig .Config .Compressor ); err == nil {
116- filepath .WalkDir (productOutputFolder , func (path string , d fs.DirEntry , err error ) error {
117- if ! isFile (path ) {
118- return nil
119- }
90+ exitIfErr (compressOutputs (productOutputFolder , buildConfig .Config ))
91+ }
92+
93+ type buildTarget struct {
94+ productOS string
95+ productOSLabel string
96+
97+ productArch string
98+ productArchLabel string
99+
100+ productArmVersion string
120101
121- preSize := getFileSize (path )
122- preSizeKB := preSize / 1024
123- preSizeMB := preSize / (1024 * 1024 )
102+ productArchWithDetails string
124103
125- cmdToRun := exec .Command (buildConfig .Config .Compressor )
126- if len (buildConfig .Config .CompressorFlags ) > 0 {
127- cmdToRun .Args = append (cmdToRun .Args , buildConfig .Config .CompressorFlags ... )
128- }
129- cmdToRun .Args = append (cmdToRun .Args , path )
104+ productExt string
105+ }
106+
107+ func parsePlatform (platform string ) (buildTarget , error ) {
108+ platform = strings .TrimSpace (platform )
109+
110+ target := buildTarget {}
111+
112+ parts := strings .Split (platform , "/" )
113+ if len (parts ) < 2 || len (parts ) > 3 {
114+ return target , fmt .Errorf ("invalid platform %q: expected GOOS/GOARCH or GOOS/GOARCH/GOARM" , platform )
115+ }
116+
117+ // OS
118+ target .productOS = parts [0 ]
130119
131- _ = cmdToRun .Run ()
120+ target .productOSLabel = target .productOS
121+ if display , ok := osToDisplay [target .productOS ]; ok {
122+ target .productOSLabel = display
123+ }
132124
133- postSize := getFileSize (path )
134- postSizeKB := postSize / 1024
135- postSizeMB := postSize / (1024 * 1024 )
125+ // ARCH
126+ target .productArch = parts [1 ]
127+ if target .productOS == "" || target .productArch == "" {
128+ return target , fmt .Errorf ("invalid platform %q: GOOS and GOARCH are required" , platform )
129+ }
136130
137- log .Printf ("compress : %s %d/%dK/%dMB -> %d/%dK/%dMB \n " , d .Name (), preSize , preSizeKB , preSizeMB , postSize , postSizeKB , postSizeMB )
131+ target .productArchLabel = target .productArch
132+ if display , ok := archToDisplay [target .productArch ]; ok {
133+ target .productArchLabel = display
134+ }
138135
139- return nil
140- })
136+ // ARM
137+ if len (parts ) == 3 {
138+ if parts [2 ] == "" {
139+ return target , fmt .Errorf ("invalid platform %q: GOARM is required when a third segment is provided" , platform )
140+ }
141+ if target .productArch != "arm" {
142+ return target , fmt .Errorf ("invalid platform %q: GOARM can only be set for arm builds" , platform )
141143 }
144+
145+ target .productArmVersion = parts [2 ]
146+ }
147+
148+ // DET
149+ target .productArchWithDetails = target .productArchLabel
150+ if target .productArmVersion != "" {
151+ target .productArchWithDetails = fmt .Sprintf ("%s-v%s" , target .productArchLabel , target .productArmVersion )
152+ }
153+
154+ // EXT
155+ target .productExt = osToExt [target .productOS ]
156+
157+ return target , nil
158+ }
159+
160+ func compressOutputs (productOutputFolder string , config Config ) error {
161+ if ! config .Compress {
162+ return nil
163+ }
164+
165+ compressorPath , err := exec .LookPath (config .Compressor )
166+ if err != nil {
167+ log .Printf ("compress : skipping, %s not found in PATH\n " , config .Compressor )
168+ return nil
142169 }
170+
171+ return filepath .WalkDir (productOutputFolder , func (path string , dirEntry fs.DirEntry , walkErr error ) error {
172+ if walkErr != nil {
173+ return walkErr
174+ }
175+ if dirEntry .IsDir () {
176+ return nil
177+ }
178+
179+ preSize := getFileSize (path )
180+ preSizeKB := preSize / 1024
181+ preSizeMB := preSize / (1024 * 1024 )
182+
183+ var stderrBuffer bytes.Buffer
184+
185+ cmdToRun := exec .Command (compressorPath )
186+ if len (config .CompressorFlags ) > 0 {
187+ cmdToRun .Args = append (cmdToRun .Args , config .CompressorFlags ... )
188+ }
189+ cmdToRun .Args = append (cmdToRun .Args , path )
190+ cmdToRun .Stderr = io .MultiWriter (& stderrBuffer ) //os.Stderr
191+ // cmdToRun.Stdout = os.Stdout
192+ if err := cmdToRun .Run (); err != nil {
193+ subErr := stderrBuffer .String ()
194+ subErrI := strings .Index (strings .ToLower (subErr ), "exception" ) + len ("exception" )
195+ if subErrI < len (subErr ) {
196+ subErr = subErr [subErrI :]
197+ }
198+ return fmt .Errorf ("compress : SKIP %s -> %s -> %s" , dirEntry .Name (), config .Compressor , subErr )
199+ }
200+
201+ postSize := getFileSize (path )
202+ postSizeKB := postSize / 1024
203+ postSizeMB := postSize / (1024 * 1024 )
204+
205+ log .Printf ("compress : %s %d/%dK/%dMB -> %d/%dK/%dMB \n " , dirEntry .Name (), preSize , preSizeKB , preSizeMB , postSize , postSizeKB , postSizeMB )
206+
207+ return nil
208+ })
143209}
0 commit comments