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