git.wit.org/jcarr/packr@v1.10.8/builder/builder.go (about) 1 package builder 2 3 import ( 4 "context" 5 "os" 6 "path/filepath" 7 "regexp" 8 "sync" 9 "text/template" 10 11 "github.com/pkg/errors" 12 "golang.org/x/sync/errgroup" 13 ) 14 15 var invalidFilePattern = regexp.MustCompile(`(_test|-packr).go$`) 16 17 // Builder scans folders/files looking for `packr.NewBox` and then compiling 18 // the required static files into `<package-name>-packr.go` files so they can 19 // be built into Go binaries. 20 type Builder struct { 21 context.Context 22 RootPath string 23 IgnoredBoxes []string 24 pkgs map[string]pkg 25 moot *sync.Mutex 26 Compress bool 27 } 28 29 // Run the builder. 30 func (b *Builder) Run() error { 31 wg := &errgroup.Group{} 32 root, err := filepath.EvalSymlinks(b.RootPath) 33 if err != nil { 34 return errors.WithStack(err) 35 } 36 err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 37 if info == nil { 38 return filepath.SkipDir 39 } 40 41 base := filepath.Base(path) 42 if base == ".git" || base == "vendor" || base == "node_modules" || base == ".idea" { 43 return filepath.SkipDir 44 } 45 46 if !info.IsDir() { 47 wg.Go(func() error { 48 return b.process(path) 49 }) 50 } 51 return nil 52 }) 53 if err != nil { 54 return errors.WithStack(err) 55 } 56 if err := wg.Wait(); err != nil { 57 return errors.WithStack(err) 58 } 59 return b.dump() 60 } 61 62 func (b *Builder) dump() error { 63 for _, p := range b.pkgs { 64 name := filepath.Join(p.Dir, p.Name+"-packr.go") 65 f, err := os.Create(name) 66 defer f.Close() 67 if err != nil { 68 return errors.WithStack(err) 69 } 70 t, err := template.New("").Parse(tmpl) 71 72 if err != nil { 73 return errors.WithStack(err) 74 } 75 err = t.Execute(f, p) 76 if err != nil { 77 return errors.WithStack(err) 78 } 79 } 80 return nil 81 } 82 83 func (b *Builder) process(path string) error { 84 ext := filepath.Ext(path) 85 if ext != ".go" || invalidFilePattern.MatchString(path) { 86 return nil 87 } 88 89 v := newVisitor(path) 90 if err := v.Run(); err != nil { 91 return errors.WithStack(err) 92 } 93 94 pk := pkg{ 95 Dir: filepath.Dir(path), 96 Boxes: []box{}, 97 Name: v.Package, 98 } 99 100 for _, n := range v.Boxes { 101 var ignored bool 102 for _, i := range b.IgnoredBoxes { 103 if n == i { 104 // this is an ignored box 105 ignored = true 106 break 107 } 108 } 109 if ignored { 110 continue 111 } 112 bx := &box{ 113 Name: n, 114 Files: []file{}, 115 compress: b.Compress, 116 } 117 p := filepath.Join(pk.Dir, bx.Name) 118 if err := bx.Walk(p); err != nil { 119 return errors.WithStack(err) 120 } 121 if len(bx.Files) > 0 { 122 pk.Boxes = append(pk.Boxes, *bx) 123 } 124 } 125 126 if len(pk.Boxes) > 0 { 127 b.addPkg(pk) 128 } 129 return nil 130 } 131 132 func (b *Builder) addPkg(p pkg) { 133 b.moot.Lock() 134 defer b.moot.Unlock() 135 if _, ok := b.pkgs[p.Name]; !ok { 136 b.pkgs[p.Name] = p 137 return 138 } 139 pp := b.pkgs[p.Name] 140 pp.Boxes = append(pp.Boxes, p.Boxes...) 141 b.pkgs[p.Name] = pp 142 } 143 144 // New Builder with a given context and path 145 func New(ctx context.Context, path string) *Builder { 146 return &Builder{ 147 Context: ctx, 148 RootPath: path, 149 IgnoredBoxes: []string{}, 150 pkgs: map[string]pkg{}, 151 moot: &sync.Mutex{}, 152 } 153 }