@@ -7,13 +7,9 @@ import (
77 "os"
88 "os/exec"
99 "path/filepath"
10- "sort"
1110 "strings"
1211 "sync"
13- "text/tabwriter"
1412
15- "github.com/gookit/color"
16- "github.com/segmentio/textio"
1713 log "github.com/sirupsen/logrus"
1814 "golang.org/x/xerrors"
1915)
@@ -48,6 +44,7 @@ type packageDuringBuild struct {
4844
4945type buildContext struct {
5046 LocalCache Cache
47+ Reporter Reporter
5148
5249 buildDir string
5350
@@ -75,14 +72,15 @@ const (
7572 dockerImageNamesFiles = "imgnames.txt"
7673)
7774
78- func newBuildContext (localCache Cache ) (ctx * buildContext , err error ) {
75+ func newBuildContext (localCache Cache , reporter Reporter ) (ctx * buildContext , err error ) {
7976 buildDir := os .Getenv (EnvvarBuildDir )
8077 if buildDir == "" {
8178 buildDir = filepath .Join (os .TempDir (), "build" )
8279 }
8380
8481 ctx = & buildContext {
8582 LocalCache : localCache ,
83+ Reporter : reporter ,
8684 buildDir : buildDir ,
8785 newlyBuiltPackages : make (map [string ]* Package ),
8886 pkgLockCond : sync .NewCond (& sync.Mutex {}),
@@ -131,7 +129,6 @@ func (c *buildContext) ReleaseBuildLock(p *Package) {
131129 c .pkgLockCond .L .Lock ()
132130 delete (c .pkgLocks , key )
133131 c .pkgLockCond .Broadcast ()
134- log .WithField ("package" , key ).Info ("package build done" )
135132 c .pkgLockCond .L .Unlock ()
136133}
137134
@@ -162,14 +159,27 @@ func (c *buildContext) GetNewlyBuiltPackages() []*Package {
162159
163160// Build builds the packages in the order they're given. It's the callers responsibility to ensure the dependencies are built
164161// in order.
165- func Build (pkg * Package , localCache Cache , remoteCache RemoteCache ) error {
162+ func Build (pkg * Package , localCache Cache , remoteCache RemoteCache , reporter Reporter ) (err error ) {
163+ ctx , err := newBuildContext (localCache , reporter )
164+
166165 requirements := pkg .GetTransitiveDependencies ()
167166 allpkg := append (requirements , pkg )
168167
169- ctx , err := newBuildContext (localCache )
168+ err = remoteCache .Download (ctx .LocalCache , requirements )
169+ if err != nil {
170+ return err
171+ }
172+
173+ pkgstatus := make (map [* Package ]PackageBuildStatus )
170174 unresolvedArgs := make (map [string ][]string )
171175 for _ , dep := range allpkg {
172176 _ , exists := ctx .LocalCache .Location (dep )
177+ if exists {
178+ pkgstatus [dep ] = PackageBuilt
179+ } else {
180+ pkgstatus [dep ] = PackageNotBuiltYet
181+ }
182+
173183 if exists {
174184 continue
175185 }
@@ -187,6 +197,11 @@ func Build(pkg *Package, localCache Cache, remoteCache RemoteCache) error {
187197 unresolvedArgs [arg ] = pkgs
188198 }
189199 }
200+ reporter .BuildStarted (pkg , pkgstatus )
201+ defer func (err * error ) {
202+ reporter .BuildFinished (pkg , * err )
203+ }(& err )
204+
190205 if len (unresolvedArgs ) != 0 {
191206 var msg string
192207 for arg , pkgs := range unresolvedArgs {
@@ -196,27 +211,6 @@ func Build(pkg *Package, localCache Cache, remoteCache RemoteCache) error {
196211 return xerrors .Errorf (msg )
197212 }
198213
199- err = remoteCache .Download (ctx .LocalCache , requirements )
200- if err != nil {
201- return err
202- }
203-
204- // now that the local cache is warm, we can print the list of work we have to do
205- lines := make ([]string , len (allpkg ))
206- for i , dep := range allpkg {
207- _ , exists := ctx .LocalCache .Location (dep )
208- format := "%s\t %s\n "
209- if exists {
210- lines [i ] = fmt .Sprintf (format , color .Green .Sprint ("📦\t cached" ), dep .FullName ())
211- } else {
212- lines [i ] = fmt .Sprintf (format , color .Yellow .Sprint ("🔧\t build" ), dep .FullName ())
213- }
214- }
215- sort .Slice (lines , func (i , j int ) bool { return lines [i ] < lines [j ] })
216- tw := tabwriter .NewWriter (os .Stdout , 0 , 2 , 2 , ' ' , 0 )
217- fmt .Fprintln (tw , strings .Join (lines , "" ))
218- tw .Flush ()
219-
220214 err = pkg .build (ctx )
221215 if err != nil {
222216 return err
@@ -267,7 +261,13 @@ func (p *Package) build(buildctx *buildContext) (err error) {
267261 if alreadyBuilt {
268262 // some package types still need to do work even if we find their prior build artifact in the cache.
269263 if p .Type == DockerPackage {
270- err = p .rebuildDocker (filepath .Dir (artifact ), artifact )
264+ doBuild := buildctx .ObtainBuildLock (p )
265+ if ! doBuild {
266+ return nil
267+ }
268+ defer buildctx .ReleaseBuildLock (p )
269+
270+ err = p .rebuildDocker (buildctx , filepath .Dir (artifact ), artifact )
271271 if err != nil {
272272 log .WithError (err ).Warn ("cannot re-use prior build artifact - building afresh." )
273273 } else {
@@ -295,15 +295,10 @@ func (p *Package) build(buildctx *buildContext) (err error) {
295295 return err
296296 }
297297
298- log .WithField ("package" , p .FullName ()).Info ("building" )
299- defer func () {
300- if err != nil {
301- log .WithField ("package" , p .FullName ()).WithError (err ).Error ("build failed" )
302- return
303- }
304-
305- log .WithField ("package" , p .FullName ()).WithField ("version" , version ).Info ("build succeded" )
306- }()
298+ buildctx .Reporter .PackageBuildStarted (p )
299+ defer func (err * error ) {
300+ buildctx .Reporter .PackageBuildFinished (p , * err )
301+ }(& err )
307302
308303 pkgdir := p .FilesystemSafeName () + "." + version
309304 builddir := filepath .Join (buildctx .BuildDir (), pkgdir )
@@ -324,7 +319,7 @@ func (p *Package) build(buildctx *buildContext) (err error) {
324319 cpargs = append (cpargs , strings .TrimPrefix (src , p .C .Origin + "/" ))
325320 }
326321 cpargs = append (cpargs , builddir )
327- err = run (getRunPrefix ( p ) , nil , p .C .Origin , "cp" , cpargs ... )
322+ err = run (buildctx . Reporter , p , nil , p .C .Origin , "cp" , cpargs ... )
328323 if err != nil {
329324 return err
330325 }
@@ -457,7 +452,7 @@ func (p *Package) buildTypescript(buildctx *buildContext, wd, result string) (er
457452 // Make sure that all our yarn install calls lock the yarn cache.
458453 yarnMutex := os .Getenv (EnvvarYarnMutex )
459454 if yarnMutex == "" {
460- log .Debug ("%s is not set, defaulting to \" network\" " , EnvvarYarnMutex )
455+ log .Debugf ("%s is not set, defaulting to \" network\" " , EnvvarYarnMutex )
461456 yarnMutex = "network"
462457 }
463458 yarnCache := filepath .Join (buildctx .BuildDir (), "yarn-cache" )
@@ -490,7 +485,7 @@ func (p *Package) buildTypescript(buildctx *buildContext, wd, result string) (er
490485 commands = append (commands , []string {"tar" , "cfz" , result , "." })
491486 }
492487
493- return executeCommandsForPackage (p , wd , commands )
488+ return executeCommandsForPackage (buildctx , p , wd , commands )
494489}
495490
496491func (p * Package ) buildGo (buildctx * buildContext , wd , result string ) (err error ) {
@@ -551,7 +546,7 @@ func (p *Package) buildGo(buildctx *buildContext, wd, result string) (err error)
551546 {"tar" , "cfz" , result , "." },
552547 }... )
553548
554- return executeCommandsForPackage (p , wd , commands )
549+ return executeCommandsForPackage (buildctx , p , wd , commands )
555550}
556551
557552func (p * Package ) buildDocker (buildctx * buildContext , wd , result string ) (err error ) {
@@ -619,7 +614,7 @@ func (p *Package) buildDocker(buildctx *buildContext, wd, result string) (err er
619614 commands = append (commands , []string {"tar" , "cfz" , result , dockerImageNamesFiles })
620615 }
621616
622- return executeCommandsForPackage (p , wd , commands )
617+ return executeCommandsForPackage (buildctx , p , wd , commands )
623618}
624619
625620func (p * Package ) buildGeneric (buildctx * buildContext , wd , result string ) (err error ) {
@@ -631,7 +626,7 @@ func (p *Package) buildGeneric(buildctx *buildContext, wd, result string) (err e
631626 // shortcut: no command == empty package
632627 if len (cfg .Command ) == 0 {
633628 log .WithField ("package" , p .FullName ()).Debug ("package has no commands - creating empty tar" )
634- return run (getRunPrefix ( p ) , nil , wd , "tar" , "cfz" , result , "--files-from" , "/dev/null" )
629+ return run (buildctx . Reporter , p , nil , wd , "tar" , "cfz" , result , "--files-from" , "/dev/null" )
635630 }
636631
637632 var commands [][]string
@@ -651,13 +646,13 @@ func (p *Package) buildGeneric(buildctx *buildContext, wd, result string) (err e
651646 commands = append (commands , cfg .Command )
652647 commands = append (commands , []string {"tar" , "cfz" , result , "." })
653648
654- return executeCommandsForPackage (p , wd , commands )
649+ return executeCommandsForPackage (buildctx , p , wd , commands )
655650}
656651
657652// rebuildDocker is called when we already have the build artifact for this package (and version)
658653// in the build cache. This function makes sure that if the build arguments changed the name of the
659654// Docker image this build time, we just re-tag the image.
660- func (p * Package ) rebuildDocker (wd , prev string ) (err error ) {
655+ func (p * Package ) rebuildDocker (buildctx * buildContext , wd , prev string ) (err error ) {
661656 cfg , ok := p .Config .(DockerPkgConfig )
662657 if ! ok {
663658 return xerrors .Errorf ("package should have Docker config" )
@@ -709,38 +704,30 @@ func (p *Package) rebuildDocker(wd, prev string) (err error) {
709704 return
710705 }
711706
712- err = executeCommandsForPackage (p , wd , commands )
707+ err = executeCommandsForPackage (buildctx , p , wd , commands )
713708 if err != nil {
714709 return err
715710 }
716711 return nil
717712}
718713
719- func getRunPrefix (p * Package ) string {
720- return fmt .Sprintf ("[%s] " , p .FullName ())
721- }
722-
723- func executeCommandsForPackage (p * Package , wd string , commands [][]string ) error {
724- prefix := getRunPrefix (p )
714+ func executeCommandsForPackage (buildctx * buildContext , p * Package , wd string , commands [][]string ) error {
725715 env := append (os .Environ (), p .Environment ... )
726716 for _ , cmd := range commands {
727- err := run (prefix , env , wd , cmd [0 ], cmd [1 :]... )
717+ err := run (buildctx . Reporter , p , env , wd , cmd [0 ], cmd [1 :]... )
728718 if err != nil {
729719 return err
730720 }
731721 }
732722 return nil
733723}
734724
735- func run (prefix string , env []string , cwd , name string , args ... string ) error {
725+ func run (rep Reporter , p * Package , env []string , cwd , name string , args ... string ) error {
736726 log .WithField ("command" , strings .Join (append ([]string {name }, args ... ), " " )).Debug ("running" )
737727
738- stdout := textio .NewPrefixWriter (os .Stdout , prefix )
739- stderr := textio .NewPrefixWriter (os .Stderr , prefix )
740-
741728 cmd := exec .Command (name , args ... )
742- cmd .Stdout = stdout
743- cmd .Stderr = stderr
729+ cmd .Stdout = & reporterStream { R : rep , P : p , IsErr : false }
730+ cmd .Stderr = & reporterStream { R : rep , P : p , IsErr : true }
744731 cmd .Dir = cwd
745732 cmd .Env = env
746733 err := cmd .Run ()
@@ -751,3 +738,14 @@ func run(prefix string, env []string, cwd, name string, args ...string) error {
751738
752739 return nil
753740}
741+
742+ type reporterStream struct {
743+ R Reporter
744+ P * Package
745+ IsErr bool
746+ }
747+
748+ func (s * reporterStream ) Write (buf []byte ) (n int , err error ) {
749+ s .R .PackageBuildLog (s .P , s .IsErr , buf )
750+ return len (buf ), nil
751+ }
0 commit comments