├── .codeclimate.yml
├── .github
├── CODEOWNERS
├── FUNDING.yml
└── workflows
│ └── tests.yml
├── .gitignore
├── .gometalinter.json
├── .goreleaser.yml
├── .goreleaser.yml.plush
├── LICENSE.txt
├── Makefile
├── README.md
├── SHOULDERS.md
├── _fixtures
├── http_test
│ ├── css
│ │ └── main.css
│ ├── footer.html
│ ├── index.html
│ └── sub
│ │ └── index.html
├── import_pkg
│ ├── import_pkg.go
│ ├── import_pkg_test.go
│ └── pkg_test
│ │ ├── 1.txt
│ │ └── 2.txt
├── list_test
│ ├── a.txt
│ ├── b
│ │ ├── b.txt
│ │ └── b2.txt
│ └── c
│ │ └── c.txt
└── templates
│ └── foo.txt
├── box.go
├── box_import_test.go
├── box_map.go
├── box_map_test.go
├── box_test.go
├── deprecated.go
├── deprecated_test.go
├── dirs_map.go
├── file
├── file.go
├── info.go
└── resolver
│ ├── _fixtures
│ └── templates
│ │ └── foo.txt
│ ├── disk.go
│ ├── disk_test.go
│ ├── encoding
│ └── hex
│ │ └── hex.go
│ ├── hex_gzip.go
│ ├── hex_gzip_test.go
│ ├── ident.go
│ ├── ident_test.go
│ ├── in_memory.go
│ ├── in_memory_test.go
│ ├── packable.go
│ ├── resolver.go
│ └── resolver_test.go
├── go.mod
├── go.sum
├── helpers.go
├── http_box_test.go
├── jam
├── pack.go
├── parser
│ ├── _fixtures
│ │ └── new_from_roots
│ │ │ ├── _r
│ │ │ └── r.go
│ │ │ ├── e
│ │ │ └── e.go
│ │ │ ├── q.go
│ │ │ └── w
│ │ │ └── w.go
│ ├── args.go
│ ├── box.go
│ ├── file.go
│ ├── finder.go
│ ├── gogen.go
│ ├── parser.go
│ ├── parser_test.go
│ ├── prospect.go
│ ├── prospect_test.go
│ ├── roots.go
│ ├── visitor.go
│ └── visitor_test.go
└── store
│ ├── _fixtures
│ ├── disk-pack
│ │ ├── a
│ │ │ └── a.go
│ │ ├── b
│ │ │ └── b.go
│ │ ├── c
│ │ │ ├── d.txt
│ │ │ ├── e.txt
│ │ │ └── f.txt
│ │ ├── go.mod
│ │ └── go.sum
│ └── disk
│ │ ├── _r
│ │ └── r.go
│ │ ├── e
│ │ ├── e.go
│ │ ├── heartbreakers
│ │ │ └── refugee.txt
│ │ └── petty
│ │ │ └── fallin.txt
│ │ ├── franklin
│ │ ├── aretha.txt
│ │ └── think.txt
│ │ ├── q.go
│ │ └── w
│ │ └── w.go
│ ├── clean.go
│ ├── disk.go
│ ├── disk_packed_test.go
│ ├── disk_test.go
│ ├── disk_tmpl.go
│ ├── env.go
│ ├── fn.go
│ ├── legacy.go
│ ├── legacy_test.go
│ ├── store.go
│ └── store_test.go
├── packr.go
├── packr2
├── LICENSE
├── cmd
│ ├── build.go
│ ├── clean.go
│ ├── fix.go
│ ├── fix
│ │ ├── fix.go
│ │ ├── imports.go
│ │ └── runner.go
│ ├── gocmd.go
│ ├── install.go
│ ├── pack.go
│ ├── root.go
│ └── version.go
└── main.go
├── packr_test.go
├── plog
└── plog.go
├── pointer.go
├── pointer_test.go
├── resolvers_map.go
├── version.go
├── walk.go
└── walk_test.go
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | golint:
4 | enabled: true
5 | checks:
6 | GoLint/Naming/MixedCaps:
7 | enabled: false
8 | govet:
9 | enabled: true
10 | gofmt:
11 | enabled: true
12 | fixme:
13 | enabled: true
14 | ratings:
15 | paths:
16 | - "**.go"
17 | exclude_paths:
18 | - "**/*_test.go"
19 | - "*_test.go"
20 | - "fixtures/"
21 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Default owner
2 | * @gobuffalo/core-managers
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: markbates
4 | patreon: buffalo
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on: [push, pull_request]
3 | jobs:
4 | tests:
5 | name: ${{matrix.go-version}} ${{matrix.os}}
6 | runs-on: ${{ matrix.os }}
7 | strategy:
8 | matrix:
9 | go-version: [1.16.x, 1.17.x]
10 | os: [macos-latest, windows-latest, ubuntu-latest]
11 | steps:
12 | - name: Checkout Code
13 | uses: actions/checkout@v2
14 | with:
15 | fetch-depth: 1
16 | - name: Setup Go ${{ matrix.go-version }}
17 | uses: actions/setup-go@v2
18 | with:
19 | go-version: ${{ matrix.go-version }}
20 | - name: Test
21 | run: |
22 | go test -race -cover -v ./...
23 | go install -v ./packr2
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | ./packr2
3 | .DS_Store
4 | doc
5 | tmp
6 | pkg
7 | *.gem
8 | *.pid
9 | coverage
10 | coverage.data
11 | build/*
12 | *.pbxuser
13 | *.mode1v3
14 | .svn
15 | profile
16 | .console_history
17 | .sass-cache/*
18 | .rake_tasks~
19 | *.log.lck
20 | solr/
21 | .jhw-cache/
22 | jhw.*
23 | *.sublime*
24 | node_modules/
25 | dist/
26 | generated/
27 | .vendor/
28 | bin/*
29 | gin-bin
30 | /packr_darwin_amd64
31 | /packr_linux_amd64
32 | .vscode/
33 | debug.test
34 | .grifter/
35 | *-packr.go
36 | .idea/
37 |
38 |
--------------------------------------------------------------------------------
/.gometalinter.json:
--------------------------------------------------------------------------------
1 | {
2 | "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"]
3 | }
4 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | # Code generated by github.com/gobuffalo/release. DO NOT EDIT.
2 | # Edit .goreleaser.yml.plush instead
3 |
4 | builds:
5 | -
6 | goos:
7 | - darwin
8 | - linux
9 | - windows
10 | goarch:
11 | - ppc64le
12 | - 386
13 | - amd64
14 | env:
15 | - CGO_ENABLED=0
16 | ignore:
17 | - goos: darwin
18 | goarch: ppc64le
19 | - goos: windows
20 | goarch: ppc64le
21 | main: ./packr2/main.go
22 | binary: packr2
23 |
24 | checksum:
25 | name_template: 'checksums.txt'
26 |
27 | snapshot:
28 | name_template: "{{ .Tag }}-next"
29 |
30 | changelog:
31 | sort: asc
32 | filters:
33 | exclude:
34 | - '^docs:'
35 | - '^test:'
36 |
37 | brews:
38 | -
39 | github:
40 | owner: gobuffalo
41 | name: homebrew-tap
42 |
43 |
--------------------------------------------------------------------------------
/.goreleaser.yml.plush:
--------------------------------------------------------------------------------
1 | builds:
2 | -
3 | goos:
4 | - darwin
5 | - linux
6 | - windows
7 | goarch:
8 | - ppc64le
9 | - 386
10 | - amd64
11 | env:
12 | - CGO_ENABLED=0
13 | ignore:
14 | - goos: darwin
15 | goarch: ppc64le
16 | - goos: windows
17 | goarch: ppc64le
18 | main: ./packr2/main.go
19 | binary: packr2
20 |
21 | checksum:
22 | name_template: 'checksums.txt'
23 |
24 | snapshot:
25 | name_template: "{{ .Tag }}-next"
26 |
27 | changelog:
28 | sort: asc
29 | filters:
30 | exclude:
31 | - '^docs:'
32 | - '^test:'
33 | <%= if (brew) { %>
34 | brews:
35 | -
36 | github:
37 | owner: gobuffalo
38 | name: homebrew-tap
39 | <% } %>
40 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Mark Bates
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | TAGS ?= "sqlite"
2 | GO_BIN ?= go
3 |
4 | install: deps
5 | echo "installing packr v2"
6 | packr2
7 | $(GO_BIN) install -v ./packr2
8 |
9 | tidy:
10 | ifeq ($(GO111MODULE),on)
11 | $(GO_BIN) mod tidy
12 | else
13 | echo skipping go mod tidy
14 | endif
15 |
16 | deps:
17 | $(GO_BIN) get -tags ${TAGS} -t ./...
18 | $(GO_BIN) install -v ./packr2
19 | make tidy
20 |
21 | build: deps
22 | packr2
23 | $(GO_BIN) build -v ./packr2
24 | make tidy
25 |
26 | test:
27 | packr2
28 | $(GO_BIN) test -tags ${TAGS} ./...
29 | make tidy
30 |
31 | lint:
32 | gometalinter --vendor ./... --deadline=1m --skip=internal
33 |
34 | update:
35 | $(GO_BIN) get -u -tags ${TAGS} ./...
36 | make tidy
37 | make install
38 | make test
39 | make tidy
40 |
41 | release-test:
42 | $(GO_BIN) test -tags ${TAGS} -race ./...
43 |
44 | release:
45 | release -y -f version.go
46 | make tidy
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **NOTICE: Please consider migrating your projects to
2 | [embed](https://pkg.go.dev/embed) which is native file embedding feature of Go,
3 | or github.com/markbates/pkger. It has an idiomatic API, minimal dependencies, a stronger test suite (tested directly against the std lib counterparts), transparent tooling, and more.**
4 |
5 | https://blog.gobuffalo.io/introducing-pkger-static-file-embedding-in-go-1ce76dc79c65
6 |
7 | # Packr (v2)
8 |
9 | [](https://godoc.org/github.com/gobuffalo/packr/v2)
10 | [](https://github.com/gobuffalo/packr/actions)
11 |
12 | Packr is a simple solution for bundling static assets inside of Go binaries. Most importantly it does it in a way that is friendly to developers while they are developing.
13 |
14 | At this moment, supported go versions are:
15 |
16 | * 1.16.x
17 | * 1.17.x
18 |
19 | even though it may (or may not) working well with older versions.
20 |
21 | ## Intro Video
22 |
23 | To get an idea of the what and why of Packr, please enjoy this short video: [https://vimeo.com/219863271](https://vimeo.com/219863271).
24 |
25 | ## Library Installation
26 |
27 | ### Go 1.16 and above
28 |
29 | ```console
30 | $ go install github.com/gobuffalo/packr/v2@v2.8.3
31 | ```
32 |
33 | or
34 |
35 | ```console
36 | $ go install github.com/gobuffalo/packr/v2@latest
37 | ```
38 |
39 | ### Go 1.15 and below
40 |
41 | ```console
42 | $ go get -u github.com/gobuffalo/packr/...
43 | ```
44 |
45 | ## Binary Installation
46 |
47 | ### Go 1.16 and above
48 |
49 | ```console
50 | $ go install github.com/gobuffalo/packr/v2/packr2@v2.8.3
51 | ```
52 |
53 | or
54 |
55 | ```console
56 | $ go install github.com/gobuffalo/packr/v2/packr2@latest
57 | ```
58 |
59 | ### Go 1.15 and below
60 |
61 | ```console
62 | $ go get -u github.com/gobuffalo/packr/packr2
63 | ```
64 |
65 | ## New File Format FAQs
66 |
67 | In version `v2.0.0` the file format changed and is not backward compatible with the `packr-v1.x` library.
68 |
69 | #### Can `packr-v1.x` read the new format?
70 |
71 | No, it can not. Because of the way the new file format works porting it to `packr-v1.x` would be difficult. PRs are welcome though. :)
72 |
73 | #### Can `packr-v2.x` read `packr-v1.x` files?
74 |
75 | Yes it can, but that ability will eventually be phased out. Because of that we recommend moving to the new format.
76 |
77 | #### Can `packr-v2.x` generate `packr-v1.x` files?
78 |
79 | Yes it can, but that ability will eventually be phased out. Because of that we recommend moving to the new format.
80 |
81 | The `--legacy` command is available on all commands that generate `-packr.go` files.
82 |
83 | ```bash
84 | $ packr2 --legacy
85 | ```
86 |
87 | ## Usage
88 |
89 | ### In Code
90 |
91 | The first step in using Packr is to create a new box. A box represents a folder on disk. Once you have a box you can get `string` or `[]byte` representations of the file.
92 |
93 | ```go
94 | // set up a new box by giving it a name and an optional (relative) path to a folder on disk:
95 | box := packr.New("My Box", "./templates")
96 |
97 | // Get the string representation of a file, or an error if it doesn't exist:
98 | html, err := box.FindString("index.html")
99 |
100 | // Get the []byte representation of a file, or an error if it doesn't exist:
101 | html, err := box.Find("index.html")
102 | ```
103 |
104 | ### What is a Box?
105 |
106 | A box represents a folder, and any sub-folders, on disk that you want to have access to in your binary. When compiling a binary using the `packr2` CLI the contents of the folder will be converted into Go files that can be compiled inside of a "standard" go binary. Inside of the compiled binary the files will be read from memory. When working locally the files will be read directly off of disk. This is a seamless switch that doesn't require any special attention on your part.
107 |
108 | #### Example
109 |
110 | Assume the follow directory structure:
111 |
112 | ```
113 | ├── main.go
114 | └── templates
115 | ├── admin
116 | │ └── index.html
117 | └── index.html
118 | ```
119 |
120 | The following program will read the `./templates/admin/index.html` file and print it out.
121 |
122 | ```go
123 | package main
124 |
125 | import (
126 | "fmt"
127 |
128 | "github.com/gobuffalo/packr/v2"
129 | )
130 |
131 | func main() {
132 | box := packr.New("myBox", "./templates")
133 |
134 | s, err := box.FindString("admin/index.html")
135 | if err != nil {
136 | log.Fatal(err)
137 | }
138 | fmt.Println(s)
139 | }
140 | ```
141 |
142 | ### Development Made Easy
143 |
144 | In order to get static files into a Go binary, those files must first be converted to Go code. To do that, Packr, ships with a few tools to help build binaries. See below.
145 |
146 | During development, however, it is painful to have to keep running a tool to compile those files.
147 |
148 | Packr uses the following resolution rules when looking for a file:
149 |
150 | 1. Look for the file in-memory (inside a Go binary)
151 | 1. Look for the file on disk (during development)
152 |
153 | Because Packr knows how to fall through to the file system, developers don't need to worry about constantly compiling their static files into a binary. They can work unimpeded.
154 |
155 | Packr takes file resolution a step further. When declaring a new box you use a relative path, `./templates`. When Packr receives this call it calculates out the absolute path to that directory. By doing this it means you can be guaranteed that Packr can find your files correctly, even if you're not running in the directory that the box was created in. This helps with the problem of testing, where Go changes the `pwd` for each package, making relative paths difficult to work with. This is not a problem when using Packr.
156 |
157 | ---
158 |
159 | ## Usage with HTTP
160 |
161 | A box implements the [`http.FileSystem`](https://golang.org/pkg/net/http/#FileSystem) interface, meaning it can be used to serve static files.
162 |
163 | ```go
164 | package main
165 |
166 | import (
167 | "net/http"
168 |
169 | "github.com/gobuffalo/packr/v2"
170 | )
171 |
172 | func main() {
173 | box := packr.New("someBoxName", "./templates")
174 |
175 | http.Handle("/", http.FileServer(box))
176 | http.ListenAndServe(":3000", nil)
177 | }
178 | ```
179 |
180 | ---
181 |
182 | ## Building a Binary
183 |
184 | Before you build your Go binary, run the `packr2` command first. It will look for all the boxes in your code and then generate `.go` files that pack the static files into bytes that can be bundled into the Go binary.
185 |
186 | ```
187 | $ packr2
188 | ```
189 |
190 | Then run your `go build command` like normal.
191 |
192 | *NOTE*: It is not recommended to check-in these generated `-packr.go` files. They can be large, and can easily become out of date if not careful. It is recommended that you always run `packr2 clean` after running the `packr2` tool.
193 |
194 | #### Cleaning Up
195 |
196 | When you're done it is recommended that you run the `packr2 clean` command. This will remove all of the generated files that Packr created for you.
197 |
198 | ```
199 | $ packr2 clean
200 | ```
201 |
202 | Why do you want to do this? Packr first looks to the information stored in these generated files, if the information isn't there it looks to disk. This makes it easy to work with in development.
203 |
204 | ---
205 |
206 | ## Debugging
207 |
208 | The `packr2` command passes all arguments down to the underlying `go` command, this includes the `-v` flag to print out `go build` information. Packr looks for the `-v` flag, and will turn on its own verbose logging. This is very useful for trying to understand what the `packr` command is doing when it is run.
209 |
210 | ---
211 |
212 | ## FAQ
213 |
214 | ### Compilation Errors with Go Templates
215 |
216 | Q: I have a program with Go template files, those files are named `foo.go` and look like the following:
217 |
218 | ```
219 | // Copyright {{.Year}} {{.Author}}. All rights reserved.
220 | // Use of this source code is governed by a BSD-style
221 | // license that can be found in the LICENSE file.
222 |
223 | package {{.Project}}
224 | ```
225 |
226 | When I run `packr2` I get errors like:
227 |
228 | ```
229 | expected 'IDENT', found '{'
230 | ```
231 |
232 | A: Packr works by searching your `.go` files for [`github.com/gobuffalo/packr/v2#New`](https://godoc.org/github.com/gobuffalo/packr/v2#New) or [`github.com/gobuffalo/packr/v2#NewBox`](https://godoc.org/github.com/gobuffalo/packr/v2#NewBox) calls. Because those files aren't "proper" Go files, Packr can't parse them to find the box declarations. To fix this you need to tell Packr to ignore those files when searching for boxes. A couple solutions to this problem are:
233 |
234 | * Name the files something else. The `.tmpl` extension is the idiomatic way of naming these types of files.
235 | * Rename the folder containing these files to start with an `_`, for example `_templates`. Packr, like Go, will ignore folders starting with the `_` character when searching for boxes.
236 |
237 | ### Dynamic Box Paths
238 |
239 | Q: I need to set the path of a box using a variable, but `packr.New("foo", myVar)` doesn't work correctly.
240 |
241 | A: Packr attempts to "automagically" set it's resolution directory when using [`github.com/gobuffalo/packr/v2#New`](https://godoc.org/github.com/gobuffalo/packr/v2#New), however, for dynamic paths you need to set it manually:
242 |
243 | ```go
244 | box := packr.New("foo", "|")
245 | box.ResolutionDir = myVar
246 | ```
247 |
248 | ### I don't want to pack files, but still use the Packr interface.
249 |
250 | Q: I want to write code that using the Packr tools, but doesn't actually pack the files into my binary. How can I do that?
251 |
252 | A: Using [`github.com/gobuffalo/packr/v2#Folder`](https://godoc.org/github.com/gobuffalo/packr/v2#Folder) gives you back a `*packr.Box` that can be used as normal, but is excluded by the Packr tool when compiling.
253 |
254 | ### Packr Finds No Boxes
255 |
256 | Q: I run `packr2 -v` but it doesn't find my boxes:
257 |
258 | ```
259 | DEBU[2019-03-18T18:48:52+01:00] *parser.Parser#NewFromRoots found prospects=0
260 | DEBU[2019-03-18T18:48:52+01:00] found 0 boxes
261 | ```
262 |
263 | A: Packr works by parsing `.go` files to find [`github.com/gobuffalo/packr/v2#Box`](https://godoc.org/github.com/gobuffalo/packr/v2#Box) and [`github.com/gobuffalo/packr/v2#NewBox`](https://godoc.org/github.com/gobuffalo/packr/v2#NewBox) declarations. If there aren't any `.go` in the folder that `packr2` is run in it can not find those declarations. To fix this problem run the `packr2` command in the directory containing your `.go` files.
264 |
265 | ### Box Interfaces
266 |
267 | Q: I want to be able to easily test my applications by passing in mock boxes. How do I do that?
268 |
269 | A: Packr boxes and files conform to the interfaces found at [`github.com/gobuffalo/packd`](https://godoc.org/github.com/gobuffalo/packd). Change your application to use those interfaces instead of the concrete Packr types.
270 |
271 | ```go
272 | // using concrete type
273 | func myFunc(box *packr.Box) {}
274 |
275 | // using interfaces
276 | func myFunc(box packd.Box) {}
277 | ```
278 |
--------------------------------------------------------------------------------
/SHOULDERS.md:
--------------------------------------------------------------------------------
1 | # github.com/gobuffalo/packr/v2 Stands on the Shoulders of Giants
2 |
3 | github.com/gobuffalo/packr/v2 does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
4 |
5 | Thank you to the following **GIANTS**:
6 |
7 |
8 | * [github.com/gobuffalo/logger](https://godoc.org/github.com/gobuffalo/logger)
9 |
10 | * [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
11 |
12 | * [github.com/karrick/godirwalk](https://godoc.org/github.com/karrick/godirwalk)
13 |
14 | * [github.com/konsorten/go-windows-terminal-sequences](https://godoc.org/github.com/konsorten/go-windows-terminal-sequences)
15 |
16 | * [github.com/markbates/errx](https://godoc.org/github.com/markbates/errx)
17 |
18 | * [github.com/markbates/oncer](https://godoc.org/github.com/markbates/oncer)
19 |
20 | * [github.com/markbates/safe](https://godoc.org/github.com/markbates/safe)
21 |
22 | * [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
23 |
24 | * [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus)
25 |
26 | * [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra)
27 |
28 | * [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
29 |
30 | * [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
31 |
32 | * [golang.org/x/tools](https://godoc.org/golang.org/x/tools)
33 |
--------------------------------------------------------------------------------
/_fixtures/http_test/css/main.css:
--------------------------------------------------------------------------------
1 | Css
2 |
--------------------------------------------------------------------------------
/_fixtures/http_test/footer.html:
--------------------------------------------------------------------------------
1 | Footer
2 |
--------------------------------------------------------------------------------
/_fixtures/http_test/index.html:
--------------------------------------------------------------------------------
1 | Index
2 |
--------------------------------------------------------------------------------
/_fixtures/http_test/sub/index.html:
--------------------------------------------------------------------------------
1 | Sub
2 |
--------------------------------------------------------------------------------
/_fixtures/import_pkg/import_pkg.go:
--------------------------------------------------------------------------------
1 | package import_pkg
2 |
3 | import (
4 | "github.com/gobuffalo/packr/v2"
5 | )
6 |
7 | var BoxTestNew = packr.New("pkg_test", "./pkg_test")
8 | var BoxTestNewBox = packr.NewBox("./pkg_test")
9 |
--------------------------------------------------------------------------------
/_fixtures/import_pkg/import_pkg_test.go:
--------------------------------------------------------------------------------
1 | package import_pkg
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/gobuffalo/packr/v2"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_NewBox(t *testing.T) {
11 | r := require.New(t)
12 |
13 | box := packr.NewBox("./pkg_test")
14 | r.Len(box.List(), 2)
15 | }
16 |
17 | func Test_New(t *testing.T) {
18 | r := require.New(t)
19 |
20 | box := packr.New("pkg_test", "./pkg_test")
21 | r.Len(box.List(), 2)
22 | }
23 |
--------------------------------------------------------------------------------
/_fixtures/import_pkg/pkg_test/1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/import_pkg/pkg_test/1.txt
--------------------------------------------------------------------------------
/_fixtures/import_pkg/pkg_test/2.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/import_pkg/pkg_test/2.txt
--------------------------------------------------------------------------------
/_fixtures/list_test/a.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/list_test/a.txt
--------------------------------------------------------------------------------
/_fixtures/list_test/b/b.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/list_test/b/b.txt
--------------------------------------------------------------------------------
/_fixtures/list_test/b/b2.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/list_test/b/b2.txt
--------------------------------------------------------------------------------
/_fixtures/list_test/c/c.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gobuffalo/packr/c4f590022d777e2d8e7906bb913019c1f6992d15/_fixtures/list_test/c/c.txt
--------------------------------------------------------------------------------
/_fixtures/templates/foo.txt:
--------------------------------------------------------------------------------
1 | FOO!!!
2 |
--------------------------------------------------------------------------------
/box.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io"
7 | "io/ioutil"
8 | "net/http"
9 | "os"
10 | "path"
11 | "path/filepath"
12 | "sort"
13 | "strings"
14 |
15 | "github.com/gobuffalo/packd"
16 | "github.com/gobuffalo/packr/v2/file"
17 | "github.com/gobuffalo/packr/v2/file/resolver"
18 | "github.com/gobuffalo/packr/v2/plog"
19 | "github.com/markbates/oncer"
20 | )
21 |
22 | var _ packd.Box = &Box{}
23 | var _ packd.HTTPBox = &Box{}
24 | var _ packd.Addable = &Box{}
25 | var _ packd.Walkable = &Box{}
26 | var _ packd.Finder = &Box{}
27 |
28 | // Box represent a folder on a disk you want to
29 | // have access to in the built Go binary.
30 | type Box struct {
31 | Path string `json:"path"`
32 | Name string `json:"name"`
33 | ResolutionDir string `json:"resolution_dir"`
34 | DefaultResolver resolver.Resolver `json:"default_resolver"`
35 | resolvers resolversMap
36 | dirs dirsMap
37 | }
38 |
39 | // NewBox returns a Box that can be used to
40 | // retrieve files from either disk or the embedded
41 | // binary.
42 | // Deprecated: Use New instead.
43 | func NewBox(path string) *Box {
44 | oncer.Deprecate(0, "packr.NewBox", "Use packr.New instead.")
45 | return New(path, path)
46 | }
47 |
48 | // New returns a new Box with the name of the box
49 | // and the path of the box.
50 | func New(name string, path string) *Box {
51 | plog.Debug("packr", "New", "name", name, "path", path)
52 | b, _ := findBox(name)
53 | if b != nil {
54 | return b
55 | }
56 |
57 | b = construct(name, path)
58 | plog.Debug(b, "New", "Box", b, "ResolutionDir", b.ResolutionDir)
59 | b, err := placeBox(b)
60 | if err != nil {
61 | panic(err)
62 | }
63 |
64 | return b
65 | }
66 |
67 | // Folder returns a Box that will NOT be packed.
68 | // This is useful for writing tests or tools that
69 | // need to work with a folder at runtime.
70 | func Folder(path string) *Box {
71 | return New(path, path)
72 | }
73 |
74 | // SetResolver allows for the use of a custom resolver for
75 | // the specified file
76 | func (b *Box) SetResolver(file string, res resolver.Resolver) {
77 | d := filepath.Dir(file)
78 | b.dirs.Store(d, true)
79 | plog.Debug(b, "SetResolver", "file", file, "resolver", fmt.Sprintf("%T", res))
80 | b.resolvers.Store(resolver.Key(file), res)
81 | }
82 |
83 | // AddString converts t to a byteslice and delegates to AddBytes to add to b.data
84 | func (b *Box) AddString(path string, t string) error {
85 | return b.AddBytes(path, []byte(t))
86 | }
87 |
88 | // AddBytes sets t in b.data by the given path
89 | func (b *Box) AddBytes(path string, t []byte) error {
90 | m := map[string]file.File{}
91 | f, err := file.NewFile(path, t)
92 | if err != nil {
93 | return err
94 | }
95 | m[resolver.Key(path)] = f
96 | res := resolver.NewInMemory(m)
97 | b.SetResolver(path, res)
98 | return nil
99 | }
100 |
101 | // FindString returns either the string of the requested
102 | // file or an error if it can not be found.
103 | func (b *Box) FindString(name string) (string, error) {
104 | bb, err := b.Find(name)
105 | return string(bb), err
106 | }
107 |
108 | // Find returns either the byte slice of the requested
109 | // file or an error if it can not be found.
110 | func (b *Box) Find(name string) ([]byte, error) {
111 | f, err := b.Resolve(name)
112 | if err != nil {
113 | return []byte(""), err
114 | }
115 | bb := &bytes.Buffer{}
116 | io.Copy(bb, f)
117 | return bb.Bytes(), nil
118 | }
119 |
120 | // Has returns true if the resource exists in the box
121 | func (b *Box) Has(name string) bool {
122 | _, err := b.Find(name)
123 | return err == nil
124 | }
125 |
126 | // HasDir returns true if the directory exists in the box
127 | func (b *Box) HasDir(name string) bool {
128 | oncer.Do("packr2/box/HasDir"+b.Name, func() {
129 | for _, f := range b.List() {
130 | for d := filepath.Dir(f); d != "."; d = filepath.Dir(d) {
131 | b.dirs.Store(d, true)
132 | }
133 | }
134 | })
135 | if name == "/" {
136 | return b.Has("index.html")
137 | }
138 | _, ok := b.dirs.Load(name)
139 | return ok
140 | }
141 |
142 | // Open returns a File using the http.File interface
143 | func (b *Box) Open(name string) (http.File, error) {
144 | plog.Debug(b, "Open", "name", name)
145 | f, err := b.Resolve(name)
146 | if err != nil {
147 | if len(filepath.Ext(name)) == 0 {
148 | return b.openWoExt(name)
149 | }
150 | return f, err
151 | }
152 | f, err = file.NewFileR(name, f)
153 | plog.Debug(b, "Open", "name", f.Name(), "file", f.Name())
154 | return f, err
155 | }
156 |
157 | func (b *Box) openWoExt(name string) (http.File, error) {
158 | if !b.HasDir(name) {
159 | id := path.Join(name, "index.html")
160 | if b.Has(id) {
161 | return b.Open(id)
162 | }
163 | return nil, os.ErrNotExist
164 | }
165 | d, err := file.NewDir(name)
166 | plog.Debug(b, "Open", "name", name, "dir", d)
167 | return d, err
168 | }
169 |
170 | // List shows "What's in the box?"
171 | func (b *Box) List() []string {
172 | var keys []string
173 |
174 | b.Walk(func(path string, info File) error {
175 | if info == nil {
176 | return nil
177 | }
178 | finfo, _ := info.FileInfo()
179 | if !finfo.IsDir() {
180 | keys = append(keys, path)
181 | }
182 | return nil
183 | })
184 | sort.Strings(keys)
185 | return keys
186 | }
187 |
188 | // Resolve will attempt to find the file in the box,
189 | // returning an error if the find can not be found.
190 | func (b *Box) Resolve(key string) (file.File, error) {
191 | key = strings.TrimPrefix(key, "/")
192 |
193 | var r resolver.Resolver
194 |
195 | b.resolvers.Range(func(k string, vr resolver.Resolver) bool {
196 | lk := strings.ToLower(resolver.Key(k))
197 | lkey := strings.ToLower(resolver.Key(key))
198 | if lk == lkey {
199 | r = vr
200 | return false
201 | }
202 | return true
203 | })
204 |
205 | if r == nil {
206 | r = b.DefaultResolver
207 | if r == nil {
208 | r = resolver.DefaultResolver
209 | if r == nil {
210 | return nil, fmt.Errorf("resolver.DefaultResolver is nil")
211 | }
212 | }
213 | }
214 | plog.Debug(r, "Resolve", "box", b.Name, "key", key)
215 |
216 | f, err := r.Resolve(b.Name, key)
217 | if err != nil {
218 | z, err := resolver.ResolvePathInBase(resolver.OsPath(b.ResolutionDir), filepath.FromSlash(path.Clean("/"+resolver.OsPath(key))))
219 | if err != nil {
220 | plog.Debug(r, "Resolve", "box", b.Name, "key", key, "err", err)
221 | return f, err
222 | }
223 |
224 | f, err = r.Resolve(b.Name, z)
225 | if err != nil {
226 | plog.Debug(r, "Resolve", "box", b.Name, "key", z, "err", err)
227 | return f, err
228 | }
229 | b, err := ioutil.ReadAll(f)
230 | if err != nil {
231 | return f, err
232 | }
233 | f, err = file.NewFile(key, b)
234 | if err != nil {
235 | return f, err
236 | }
237 | }
238 | plog.Debug(r, "Resolve", "box", b.Name, "key", key, "file", f.Name())
239 | return f, nil
240 | }
241 |
--------------------------------------------------------------------------------
/box_import_test.go:
--------------------------------------------------------------------------------
1 | package packr_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/gobuffalo/packr/v2/_fixtures/import_pkg"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_ImportWithBox(t *testing.T) {
11 | r := require.New(t)
12 |
13 | r.Len(import_pkg.BoxTestNew.List(), 2)
14 |
15 | r.Len(import_pkg.BoxTestNewBox.List(), 2)
16 | }
17 |
--------------------------------------------------------------------------------
/box_map.go:
--------------------------------------------------------------------------------
1 | //go:generate mapgen -name "box" -zero "nil" -go-type "*Box" -pkg "" -a "New(`test-a`, ``)" -b "New(`test-b`, ``)" -c "New(`test-c`, ``)" -bb "New(`test-bb`, ``)" -destination "packr"
2 | // Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
3 |
4 | package packr
5 |
6 | import (
7 | "sort"
8 | "sync"
9 | )
10 |
11 | // boxMap wraps sync.Map and uses the following types:
12 | // key: string
13 | // value: *Box
14 | type boxMap struct {
15 | data sync.Map
16 | }
17 |
18 | // Delete the key from the map
19 | func (m *boxMap) Delete(key string) {
20 | m.data.Delete(key)
21 | }
22 |
23 | // Load the key from the map.
24 | // Returns *Box or bool.
25 | // A false return indicates either the key was not found
26 | // or the value is not of type *Box
27 | func (m *boxMap) Load(key string) (*Box, bool) {
28 | i, ok := m.data.Load(key)
29 | if !ok {
30 | return nil, false
31 | }
32 | s, ok := i.(*Box)
33 | return s, ok
34 | }
35 |
36 | // LoadOrStore will return an existing key or
37 | // store the value if not already in the map
38 | func (m *boxMap) LoadOrStore(key string, value *Box) (*Box, bool) {
39 | i, _ := m.data.LoadOrStore(key, value)
40 | s, ok := i.(*Box)
41 | return s, ok
42 | }
43 |
44 | // Range over the *Box values in the map
45 | func (m *boxMap) Range(f func(key string, value *Box) bool) {
46 | m.data.Range(func(k, v interface{}) bool {
47 | key, ok := k.(string)
48 | if !ok {
49 | return false
50 | }
51 | value, ok := v.(*Box)
52 | if !ok {
53 | return false
54 | }
55 | return f(key, value)
56 | })
57 | }
58 |
59 | // Store a *Box in the map
60 | func (m *boxMap) Store(key string, value *Box) {
61 | m.data.Store(key, value)
62 | }
63 |
64 | // Keys returns a list of keys in the map
65 | func (m *boxMap) Keys() []string {
66 | var keys []string
67 | m.Range(func(key string, value *Box) bool {
68 | keys = append(keys, key)
69 | return true
70 | })
71 | sort.Strings(keys)
72 | return keys
73 | }
74 |
--------------------------------------------------------------------------------
/box_map_test.go:
--------------------------------------------------------------------------------
1 | // Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
2 |
3 | package packr
4 |
5 | import (
6 | "sort"
7 | "testing"
8 |
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func Test_boxMap(t *testing.T) {
13 | r := require.New(t)
14 |
15 | sm := &boxMap{}
16 |
17 | sm.Store("a", New(`test-a`, ``))
18 |
19 | s, ok := sm.Load("a")
20 | r.True(ok)
21 | r.Equal(New(`test-a`, ``), s)
22 |
23 | s, ok = sm.LoadOrStore("b", New(`test-b`, ``))
24 | r.True(ok)
25 | r.Equal(New(`test-b`, ``), s)
26 |
27 | s, ok = sm.LoadOrStore("b", New(`test-bb`, ``))
28 | r.True(ok)
29 | r.Equal(New(`test-b`, ``), s)
30 |
31 | var keys []string
32 |
33 | sm.Range(func(key string, value *Box) bool {
34 | keys = append(keys, key)
35 | return true
36 | })
37 |
38 | sort.Strings(keys)
39 |
40 | r.Equal(sm.Keys(), keys)
41 |
42 | sm.Delete("b")
43 | r.Equal([]string{"a", "b"}, keys)
44 |
45 | sm.Delete("b")
46 | _, ok = sm.Load("b")
47 | r.False(ok)
48 |
49 | func(m *boxMap) {
50 | m.Store("c", New(`test-c`, ``))
51 | }(sm)
52 | s, ok = sm.Load("c")
53 | r.True(ok)
54 | r.Equal(New(`test-c`, ``), s)
55 | }
56 |
--------------------------------------------------------------------------------
/box_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "bytes"
5 | "path/filepath"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/gobuffalo/packr/v2/file"
10 | "github.com/gobuffalo/packr/v2/file/resolver"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | func Test_New(t *testing.T) {
15 | r := require.New(t)
16 |
17 | box := New("Test_NewBox", filepath.Join("_fixtures", "list_test"))
18 | r.Len(box.List(), 4)
19 |
20 | }
21 | func Test_Box_AddString(t *testing.T) {
22 | r := require.New(t)
23 |
24 | box := New("Test_Box_AddString", "./templates")
25 | s, err := box.FindString("foo.txt")
26 | r.Error(err)
27 | r.Equal("", s)
28 |
29 | r.NoError(box.AddString("foo.txt", "foo!!"))
30 | s, err = box.FindString("foo.txt")
31 | r.NoError(err)
32 | r.Equal("foo!!", s)
33 | }
34 |
35 | func Test_Box_AddBytes(t *testing.T) {
36 | r := require.New(t)
37 |
38 | box := New("Test_Box_AddBytes", "")
39 | s, err := box.FindString("foo.txt")
40 | r.Error(err)
41 | r.Equal("", s)
42 |
43 | r.NoError(box.AddBytes("foo.txt", []byte("foo!!")))
44 | s, err = box.FindString("foo.txt")
45 | r.NoError(err)
46 | r.Equal("foo!!", s)
47 | }
48 |
49 | func Test_Box_String(t *testing.T) {
50 | r := require.New(t)
51 |
52 | box := New("Test_Box_String", "./templates")
53 | d := resolver.NewInMemory(map[string]file.File{
54 | "foo.txt": qfile("foo.txt", "foo!"),
55 | })
56 | box.SetResolver("foo.txt", d)
57 |
58 | s := box.String("foo.txt")
59 | r.Equal("foo!", s)
60 |
61 | s = box.String("idontexist")
62 | r.Equal("", s)
63 | }
64 |
65 | func Test_Box_String_Miss(t *testing.T) {
66 | r := require.New(t)
67 |
68 | box := New("Test_Box_String_Miss", filepath.Join("_fixtures", "templates"))
69 |
70 | s := box.String("foo.txt")
71 | r.Equal("FOO!!!", strings.TrimSpace(s))
72 |
73 | s = box.String("idontexist")
74 | r.Equal("", s)
75 | }
76 |
77 | func Test_Box_FindString(t *testing.T) {
78 | r := require.New(t)
79 |
80 | box := New("Test_Box_FindString", "./templates")
81 | d := resolver.NewInMemory(map[string]file.File{
82 | "foo.txt": qfile("foo.txt", "foo!"),
83 | })
84 | box.SetResolver("foo.txt", d)
85 |
86 | s, err := box.FindString("foo.txt")
87 | r.NoError(err)
88 | r.Equal("foo!", s)
89 |
90 | s, err = box.FindString("idontexist")
91 | r.Error(err)
92 | r.Equal("", s)
93 | }
94 |
95 | func Test_Box_FindString_Miss(t *testing.T) {
96 | r := require.New(t)
97 |
98 | box := New("Test_Box_FindString_Miss", filepath.Join("_fixtures", "templates"))
99 |
100 | s, err := box.FindString("foo.txt")
101 | r.NoError(err)
102 | r.Equal("FOO!!!", strings.TrimSpace(s))
103 |
104 | s, err = box.FindString("idontexist")
105 | r.Error(err)
106 | r.Equal("", s)
107 | }
108 |
109 | func Test_Box_Bytes(t *testing.T) {
110 | r := require.New(t)
111 |
112 | box := New("Test_Box_Bytes", "./templates")
113 | d := resolver.NewInMemory(map[string]file.File{
114 | "foo.txt": qfile("foo.txt", "foo!"),
115 | })
116 | box.SetResolver("foo.txt", d)
117 |
118 | s := box.Bytes("foo.txt")
119 | r.Equal([]byte("foo!"), s)
120 |
121 | s = box.Bytes("idontexist")
122 | r.Equal([]byte(""), s)
123 | }
124 |
125 | func Test_Box_Bytes_Miss(t *testing.T) {
126 | r := require.New(t)
127 |
128 | box := New("Test_Box_Bytes_Miss", filepath.Join("_fixtures", "templates"))
129 |
130 | s := box.Bytes("foo.txt")
131 | r.Equal([]byte("FOO!!!"), bytes.TrimSpace(s))
132 |
133 | s = box.Bytes("idontexist")
134 | r.Equal([]byte(""), s)
135 | }
136 |
137 | func Test_Box_Find(t *testing.T) {
138 | r := require.New(t)
139 |
140 | box := New("Test_Box_Find", "./templates")
141 | d := resolver.NewInMemory(map[string]file.File{
142 | "foo.txt": qfile("foo.txt", "foo!"),
143 | })
144 | box.SetResolver("foo.txt", d)
145 |
146 | s, err := box.Find("foo.txt")
147 | r.NoError(err)
148 | r.Equal("foo!", string(s))
149 |
150 | s, err = box.Find("idontexist")
151 | r.Error(err)
152 | r.Equal("", string(s))
153 | }
154 |
155 | func Test_Box_Find_Miss(t *testing.T) {
156 | r := require.New(t)
157 |
158 | box := New("Test_Box_Find_Miss", "./_fixtures/templates")
159 | s, err := box.Find("foo.txt")
160 | r.NoError(err)
161 | r.Equal("FOO!!!", strings.TrimSpace(string(s)))
162 |
163 | s, err = box.Find("idontexist")
164 | r.Error(err)
165 | r.Equal("", string(s))
166 | }
167 |
168 | func Test_Box_Has(t *testing.T) {
169 | r := require.New(t)
170 |
171 | box := New("Test_Box_Has", "./templates")
172 | d := resolver.NewInMemory(map[string]file.File{
173 | "foo.txt": qfile("foo.txt", "foo!"),
174 | })
175 | box.SetResolver("foo.txt", d)
176 |
177 | r.True(box.Has("foo.txt"))
178 | r.False(box.Has("idontexist"))
179 | }
180 |
181 | func Test_Box_Open(t *testing.T) {
182 | r := require.New(t)
183 |
184 | d := resolver.NewInMemory(map[string]file.File{
185 | "foo.txt": qfile("foo.txt", "foo!"),
186 | "bar": qfile("bar", "bar!"),
187 | "baz/index.html": qfile("baz", "baz!"),
188 | })
189 | box := New("Test_Box_Open", "./templates")
190 |
191 | box.DefaultResolver = d
192 |
193 | for _, x := range []string{"foo.txt", "/foo.txt", "bar", "/bar", "baz", "/baz"} {
194 | f, err := box.Open(x)
195 | r.NoError(err)
196 | r.NotZero(f)
197 | }
198 |
199 | f, err := box.Open("idontexist.txt")
200 | r.Error(err)
201 | r.Zero(f)
202 | }
203 |
204 | func Test_Box_List(t *testing.T) {
205 | r := require.New(t)
206 |
207 | box := New("Test_Box_List", filepath.Join("_fixtures", "list_test"))
208 | r.NoError(box.AddString(filepath.Join("d", "d.txt"), "D"))
209 |
210 | act := box.List()
211 | exp := []string{"a.txt", filepath.Join("b", "b.txt"), filepath.Join("b", "b2.txt"), filepath.Join("c", "c.txt"), filepath.Join("d", "d.txt")}
212 | r.Equal(exp, act)
213 | }
214 |
215 | func Test_Box_HasDir(t *testing.T) {
216 | r := require.New(t)
217 |
218 | box := New("Test_Box_HasDir", filepath.Join("_fixtures", "list_test"))
219 | r.NoError(box.AddString("d/e/f.txt", "D"))
220 |
221 | r.True(box.HasDir("d/e"))
222 | r.True(box.HasDir("d"))
223 | r.True(box.HasDir("c"))
224 | r.False(box.HasDir("a"))
225 | }
226 |
227 | func Test_Box_Traversal_Standard(t *testing.T) {
228 | r := require.New(t)
229 | box := New("Test_Box_Traversal_Standard", "")
230 | _, err := box.FindString("../fixtures/hello.txt")
231 | r.Error(err)
232 | }
233 |
234 | func Test_Box_Traversal_Standard_Depth2(t *testing.T) {
235 | r := require.New(t)
236 | box := New("Test_Box_Traversal_Standard_Depth2", "")
237 | _, err := box.FindString("../../packr/fixtures/hello.txt")
238 | r.Error(err)
239 | }
240 |
241 | func Test_Box_Traversal_Backslash(t *testing.T) {
242 | r := require.New(t)
243 | box := New("Test_Box_Traversal_Backslash", "")
244 | _, err := box.FindString("..\\fixtures\\hello.txt")
245 | r.Error(err)
246 | }
247 |
248 | func Test_Box_Traversal_Backslash_Depth2(t *testing.T) {
249 | r := require.New(t)
250 | box := New("Test_Box_Traversal_Backslash_Depth2", "")
251 | _, err := box.FindString("..\\..\\packr2\\fixtures\\hello.txt")
252 | r.Error(err)
253 | }
254 |
--------------------------------------------------------------------------------
/deprecated.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/gobuffalo/packr/v2/file"
8 | "github.com/gobuffalo/packr/v2/file/resolver"
9 | "github.com/markbates/oncer"
10 | )
11 |
12 | // File has been deprecated and file.File should be used instead
13 | type File = file.File
14 |
15 | var (
16 | // ErrResOutsideBox gets returned in case of the requested resources being outside the box
17 | // Deprecated
18 | ErrResOutsideBox = fmt.Errorf("can't find a resource outside the box")
19 | )
20 |
21 | // PackBytes packs bytes for a file into a box.
22 | // Deprecated
23 | func PackBytes(box string, name string, bb []byte) {
24 | b := NewBox(box)
25 | d := resolver.NewInMemory(map[string]file.File{})
26 | f, err := file.NewFile(name, bb)
27 | if err != nil {
28 | panic(err)
29 | }
30 | if err := d.Pack(name, f); err != nil {
31 | panic(err)
32 | }
33 | b.SetResolver(name, d)
34 | }
35 |
36 | // PackBytesGzip packets the gzipped compressed bytes into a box.
37 | // Deprecated
38 | func PackBytesGzip(box string, name string, bb []byte) error {
39 | // TODO: this function never did what it was supposed to do!
40 | PackBytes(box, name, bb)
41 | return nil
42 | }
43 |
44 | // PackJSONBytes packs JSON encoded bytes for a file into a box.
45 | // Deprecated
46 | func PackJSONBytes(box string, name string, jbb string) error {
47 | var bb []byte
48 | err := json.Unmarshal([]byte(jbb), &bb)
49 | if err != nil {
50 | return err
51 | }
52 | PackBytes(box, name, bb)
53 | return nil
54 | }
55 |
56 | // Bytes is deprecated. Use Find instead
57 | func (b *Box) Bytes(name string) []byte {
58 | bb, _ := b.Find(name)
59 | oncer.Deprecate(0, "github.com/gobuffalo/packr/v2#Box.Bytes", "Use github.com/gobuffalo/packr/v2#Box.Find instead.")
60 | return bb
61 | }
62 |
63 | // MustBytes is deprecated. Use Find instead.
64 | func (b *Box) MustBytes(name string) ([]byte, error) {
65 | oncer.Deprecate(0, "github.com/gobuffalo/packr/v2#Box.MustBytes", "Use github.com/gobuffalo/packr/v2#Box.Find instead.")
66 | return b.Find(name)
67 | }
68 |
69 | // String is deprecated. Use FindString instead
70 | func (b *Box) String(name string) string {
71 | oncer.Deprecate(0, "github.com/gobuffalo/packr/v2#Box.String", "Use github.com/gobuffalo/packr/v2#Box.FindString instead.")
72 | return string(b.Bytes(name))
73 | }
74 |
75 | // MustString is deprecated. Use FindString instead
76 | func (b *Box) MustString(name string) (string, error) {
77 | oncer.Deprecate(0, "github.com/gobuffalo/packr/v2#Box.MustString", "Use github.com/gobuffalo/packr/v2#Box.FindString instead.")
78 | return b.FindString(name)
79 | }
80 |
--------------------------------------------------------------------------------
/deprecated_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func Test_PackBytes(t *testing.T) {
10 | r := require.New(t)
11 |
12 | box := NewBox("my/box")
13 | name := "foo.txt"
14 | body := []byte("foo!!")
15 | PackBytes(box.Name, name, body)
16 |
17 | f, err := box.FindString(name)
18 | r.NoError(err)
19 | r.Equal(string(body), f)
20 | }
21 |
22 | func Test_PackBytesGzip(t *testing.T) {
23 | r := require.New(t)
24 |
25 | box := NewBox("my/box")
26 | name := "foo.txt"
27 | body := []byte("foo!!")
28 | PackBytesGzip(box.Name, name, body)
29 |
30 | f, err := box.FindString(name)
31 | r.NoError(err)
32 | r.Equal(string(body), f)
33 | }
34 |
35 | func Test_PackJSONBytes(t *testing.T) {
36 | r := require.New(t)
37 |
38 | box := NewBox("my/box")
39 | name := "foo.txt"
40 | body := "\"PGgxPnRlbXBsYXRlcy9tYWlsZXJzL2xheW91dC5odG1sPC9oMT4KCjwlPSB5aWVsZCAlPgo=\""
41 | PackJSONBytes(box.Name, name, body)
42 |
43 | f, err := box.FindString(name)
44 | r.NoError(err)
45 | r.Equal("
templates/mailers/layout.html
\n\n<%= yield %>\n", f)
46 | }
47 |
--------------------------------------------------------------------------------
/dirs_map.go:
--------------------------------------------------------------------------------
1 | //go:generate mapgen -name "dirs" -zero "false" -go-type "bool" -pkg "" -a "nil" -b "nil" -c "nil" -bb "nil" -destination "packr"
2 | // Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
3 |
4 | package packr
5 |
6 | import (
7 | "sort"
8 | "strings"
9 | "sync"
10 | )
11 |
12 | // dirsMap wraps sync.Map and uses the following types:
13 | // key: string
14 | // value: bool
15 | type dirsMap struct {
16 | data sync.Map
17 | }
18 |
19 | // Delete the key from the map
20 | func (m *dirsMap) Delete(key string) {
21 | m.data.Delete(m.normalizeKey(key))
22 | }
23 |
24 | // Load the key from the map.
25 | // Returns bool or bool.
26 | // A false return indicates either the key was not found
27 | // or the value is not of type bool
28 | func (m *dirsMap) Load(key string) (bool, bool) {
29 | i, ok := m.data.Load(m.normalizeKey(key))
30 | if !ok {
31 | return false, false
32 | }
33 | s, ok := i.(bool)
34 | return s, ok
35 | }
36 |
37 | // LoadOrStore will return an existing key or
38 | // store the value if not already in the map
39 | func (m *dirsMap) LoadOrStore(key string, value bool) (bool, bool) {
40 | i, _ := m.data.LoadOrStore(m.normalizeKey(key), value)
41 | s, ok := i.(bool)
42 | return s, ok
43 | }
44 |
45 | // Range over the bool values in the map
46 | func (m *dirsMap) Range(f func(key string, value bool) bool) {
47 | m.data.Range(func(k, v interface{}) bool {
48 | key, ok := k.(string)
49 | if !ok {
50 | return false
51 | }
52 | value, ok := v.(bool)
53 | if !ok {
54 | return false
55 | }
56 | return f(key, value)
57 | })
58 | }
59 |
60 | // Store a bool in the map
61 | func (m *dirsMap) Store(key string, value bool) {
62 | d := m.normalizeKey(key)
63 | m.data.Store(d, value)
64 | m.data.Store(strings.TrimPrefix(d, "/"), value)
65 | }
66 |
67 | // Keys returns a list of keys in the map
68 | func (m *dirsMap) Keys() []string {
69 | var keys []string
70 | m.Range(func(key string, value bool) bool {
71 | keys = append(keys, key)
72 | return true
73 | })
74 | sort.Strings(keys)
75 | return keys
76 | }
77 |
78 | func (m *dirsMap) normalizeKey(key string) string {
79 | key = strings.Replace(key, "\\", "/", -1)
80 |
81 | return key
82 | }
83 |
--------------------------------------------------------------------------------
/file/file.go:
--------------------------------------------------------------------------------
1 | package file
2 |
3 | import (
4 | "bytes"
5 | "io"
6 |
7 | "github.com/gobuffalo/packd"
8 | )
9 |
10 | // File represents a virtual, or physical, backing of
11 | // a file object in a Box
12 | type File = packd.File
13 |
14 | // FileMappable types are capable of returning a map of
15 | // path => File
16 | type FileMappable interface {
17 | FileMap() map[string]File
18 | }
19 |
20 | // NewFile returns a virtual File implementation
21 | func NewFile(name string, b []byte) (File, error) {
22 | return packd.NewFile(name, bytes.NewReader(b))
23 | }
24 |
25 | // NewDir returns a virtual dir implementation
26 | func NewDir(name string) (File, error) {
27 | return packd.NewDir(name)
28 | }
29 |
30 | func NewFileR(name string, r io.Reader) (File, error) {
31 | return packd.NewFile(name, r)
32 | }
33 |
--------------------------------------------------------------------------------
/file/info.go:
--------------------------------------------------------------------------------
1 | package file
2 |
3 | import (
4 | "os"
5 | "time"
6 | )
7 |
8 | type info struct {
9 | Path string
10 | Contents []byte
11 | size int64
12 | modTime time.Time
13 | isDir bool
14 | }
15 |
16 | func (f info) Name() string {
17 | return f.Path
18 | }
19 |
20 | func (f info) Size() int64 {
21 | return f.size
22 | }
23 |
24 | func (f info) Mode() os.FileMode {
25 | return 0444
26 | }
27 |
28 | func (f info) ModTime() time.Time {
29 | return f.modTime
30 | }
31 |
32 | func (f info) IsDir() bool {
33 | return f.isDir
34 | }
35 |
36 | func (f info) Sys() interface{} {
37 | return nil
38 | }
39 |
--------------------------------------------------------------------------------
/file/resolver/_fixtures/templates/foo.txt:
--------------------------------------------------------------------------------
1 | foo!
2 |
--------------------------------------------------------------------------------
/file/resolver/disk.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | "sync"
9 |
10 | "github.com/gobuffalo/packr/v2/file"
11 | "github.com/gobuffalo/packr/v2/plog"
12 | "github.com/karrick/godirwalk"
13 | )
14 |
15 | var _ Resolver = &Disk{}
16 |
17 | type Disk struct {
18 | Root string
19 | }
20 |
21 | func (d Disk) String() string {
22 | return String(&d)
23 | }
24 |
25 | func (d *Disk) Resolve(box string, name string) (file.File, error) {
26 | var err error
27 | path := OsPath(name)
28 | if !filepath.IsAbs(path) {
29 | path, err = ResolvePathInBase(OsPath(d.Root), path)
30 | if err != nil {
31 | return nil, err
32 | }
33 | }
34 |
35 | fi, err := os.Stat(path)
36 | if err != nil {
37 | return nil, err
38 | }
39 | if fi.IsDir() {
40 | return nil, os.ErrNotExist
41 | }
42 | if bb, err := ioutil.ReadFile(path); err == nil {
43 | return file.NewFile(OsPath(name), bb)
44 | }
45 | return nil, os.ErrNotExist
46 | }
47 |
48 | // ResolvePathInBase returns a path that is guaranteed to be inside of the base directory or an error
49 | func ResolvePathInBase(base, path string) (string, error) {
50 | // Determine the absolute file path of the base directory
51 | d, err := filepath.Abs(base)
52 | if err != nil {
53 | return "", err
54 | }
55 |
56 | // Return the base directory if no file was requested
57 | if path == "/" || path == "\\" {
58 | return d, nil
59 | }
60 |
61 | // Resolve the absolute file path after combining the key with base
62 | p, err := filepath.Abs(filepath.Join(d, path))
63 | if err != nil {
64 | return "", err
65 | }
66 |
67 | // Verify that the resolved path is inside of the base directory
68 | if !strings.HasPrefix(p, d+string(filepath.Separator)) {
69 | return "", os.ErrNotExist
70 | }
71 | return p, nil
72 | }
73 |
74 | var _ file.FileMappable = &Disk{}
75 |
76 | func (d *Disk) FileMap() map[string]file.File {
77 | moot := &sync.Mutex{}
78 | m := map[string]file.File{}
79 | root := OsPath(d.Root)
80 | if _, err := os.Stat(root); err != nil {
81 | return m
82 | }
83 | callback := func(path string, de *godirwalk.Dirent) error {
84 | if _, err := os.Stat(root); err != nil {
85 | return nil
86 | }
87 | if !de.IsRegular() {
88 | return nil
89 | }
90 | moot.Lock()
91 | name := strings.TrimPrefix(path, root+string(filepath.Separator))
92 | b, err := ioutil.ReadFile(path)
93 | if err != nil {
94 | return err
95 | }
96 | m[name], err = file.NewFile(name, b)
97 | if err != nil {
98 | return err
99 | }
100 | moot.Unlock()
101 | return nil
102 | }
103 | err := godirwalk.Walk(root, &godirwalk.Options{
104 | FollowSymbolicLinks: true,
105 | Callback: callback,
106 | })
107 | if err != nil {
108 | plog.Logger.Errorf("[%s] error walking %v", root, err)
109 | }
110 | return m
111 | }
112 |
--------------------------------------------------------------------------------
/file/resolver/disk_test.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "io/ioutil"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_Disk_Find(t *testing.T) {
12 | r := require.New(t)
13 |
14 | d := &Disk{
15 | Root: "_fixtures\\templates",
16 | }
17 |
18 | f, err := d.Resolve("", "foo.txt")
19 | r.NoError(err)
20 |
21 | fi, err := f.FileInfo()
22 | r.NoError(err)
23 | r.Equal("foo.txt", fi.Name())
24 |
25 | b, err := ioutil.ReadAll(f)
26 | r.NoError(err)
27 | r.Equal("foo!", strings.TrimSpace(string(b)))
28 | }
29 |
--------------------------------------------------------------------------------
/file/resolver/encoding/hex/hex.go:
--------------------------------------------------------------------------------
1 | // Copyright 2009 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package hex implements hexadecimal encoding and decoding.
6 | package hex
7 |
8 | import (
9 | "bytes"
10 | "fmt"
11 | "io"
12 | )
13 |
14 | const hextable = "0123456789abcdef"
15 |
16 | // EncodedLen returns the length of an encoding of n source bytes.
17 | // Specifically, it returns n * 2.
18 | func EncodedLen(n int) int { return n * 2 }
19 |
20 | // Encode encodes src into EncodedLen(len(src))
21 | // bytes of dst. As a convenience, it returns the number
22 | // of bytes written to dst, but this value is always EncodedLen(len(src)).
23 | // Encode implements hexadecimal encoding.
24 | func Encode(dst, src []byte) int {
25 | for i, v := range src {
26 | dst[i*2] = hextable[v>>4]
27 | dst[i*2+1] = hextable[v&0x0f]
28 | }
29 |
30 | return len(src) * 2
31 | }
32 |
33 | // ErrLength reports an attempt to decode an odd-length input
34 | // using Decode or DecodeString.
35 | // The stream-based Decoder returns io.ErrUnexpectedEOF instead of ErrLength.
36 | var ErrLength = fmt.Errorf("encoding/hex: odd length hex string")
37 |
38 | // InvalidByteError values describe errors resulting from an invalid byte in a hex string.
39 | type InvalidByteError byte
40 |
41 | func (e InvalidByteError) Error() string {
42 | return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
43 | }
44 |
45 | // DecodedLen returns the length of a decoding of x source bytes.
46 | // Specifically, it returns x / 2.
47 | func DecodedLen(x int) int { return x / 2 }
48 |
49 | // Decode decodes src into DecodedLen(len(src)) bytes,
50 | // returning the actual number of bytes written to dst.
51 | //
52 | // Decode expects that src contains only hexadecimal
53 | // characters and that src has even length.
54 | // If the input is malformed, Decode returns the number
55 | // of bytes decoded before the error.
56 | func Decode(dst, src []byte) (int, error) {
57 | var i int
58 | for i = 0; i < len(src)/2; i++ {
59 | a, ok := fromHexChar(src[i*2])
60 | if !ok {
61 | return i, InvalidByteError(src[i*2])
62 | }
63 | b, ok := fromHexChar(src[i*2+1])
64 | if !ok {
65 | return i, InvalidByteError(src[i*2+1])
66 | }
67 | dst[i] = (a << 4) | b
68 | }
69 | if len(src)%2 == 1 {
70 | // Check for invalid char before reporting bad length,
71 | // since the invalid char (if present) is an earlier problem.
72 | if _, ok := fromHexChar(src[i*2]); !ok {
73 | return i, InvalidByteError(src[i*2])
74 | }
75 | return i, ErrLength
76 | }
77 | return i, nil
78 | }
79 |
80 | // fromHexChar converts a hex character into its value and a success flag.
81 | func fromHexChar(c byte) (byte, bool) {
82 | switch {
83 | case '0' <= c && c <= '9':
84 | return c - '0', true
85 | case 'a' <= c && c <= 'f':
86 | return c - 'a' + 10, true
87 | case 'A' <= c && c <= 'F':
88 | return c - 'A' + 10, true
89 | }
90 |
91 | return 0, false
92 | }
93 |
94 | // EncodeToString returns the hexadecimal encoding of src.
95 | func EncodeToString(src []byte) string {
96 | dst := make([]byte, EncodedLen(len(src)))
97 | Encode(dst, src)
98 | return string(dst)
99 | }
100 |
101 | // DecodeString returns the bytes represented by the hexadecimal string s.
102 | //
103 | // DecodeString expects that src contains only hexadecimal
104 | // characters and that src has even length.
105 | // If the input is malformed, DecodeString returns
106 | // the bytes decoded before the error.
107 | func DecodeString(s string) ([]byte, error) {
108 | src := []byte(s)
109 | // We can use the source slice itself as the destination
110 | // because the decode loop increments by one and then the 'seen' byte is not used anymore.
111 | n, err := Decode(src, src)
112 | return src[:n], err
113 | }
114 |
115 | // Dump returns a string that contains a hex dump of the given data. The format
116 | // of the hex dump matches the output of `hexdump -C` on the command line.
117 | func Dump(data []byte) string {
118 | var buf bytes.Buffer
119 | dumper := Dumper(&buf)
120 | dumper.Write(data)
121 | dumper.Close()
122 | return buf.String()
123 | }
124 |
125 | // bufferSize is the number of hexadecimal characters to buffer in encoder and decoder.
126 | const bufferSize = 1024
127 |
128 | type encoder struct {
129 | w io.Writer
130 | err error
131 | out [bufferSize]byte // output buffer
132 | }
133 |
134 | // NewEncoder returns an io.Writer that writes lowercase hexadecimal characters to w.
135 | func NewEncoder(w io.Writer) io.Writer {
136 | return &encoder{w: w}
137 | }
138 |
139 | func (e *encoder) Write(p []byte) (n int, err error) {
140 | for len(p) > 0 && e.err == nil {
141 | chunkSize := bufferSize / 2
142 | if len(p) < chunkSize {
143 | chunkSize = len(p)
144 | }
145 |
146 | var written int
147 | encoded := Encode(e.out[:], p[:chunkSize])
148 | written, e.err = e.w.Write(e.out[:encoded])
149 | n += written / 2
150 | p = p[chunkSize:]
151 | }
152 | return n, e.err
153 | }
154 |
155 | type decoder struct {
156 | r io.Reader
157 | err error
158 | in []byte // input buffer (encoded form)
159 | arr [bufferSize]byte // backing array for in
160 | }
161 |
162 | // NewDecoder returns an io.Reader that decodes hexadecimal characters from r.
163 | // NewDecoder expects that r contain only an even number of hexadecimal characters.
164 | func NewDecoder(r io.Reader) io.Reader {
165 | return &decoder{r: r}
166 | }
167 |
168 | func (d *decoder) Read(p []byte) (n int, err error) {
169 | // Fill internal buffer with sufficient bytes to decode
170 | if len(d.in) < 2 && d.err == nil {
171 | var numCopy, numRead int
172 | numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes
173 | numRead, d.err = d.r.Read(d.arr[numCopy:])
174 | d.in = d.arr[:numCopy+numRead]
175 | if d.err == io.EOF && len(d.in)%2 != 0 {
176 | if _, ok := fromHexChar(d.in[len(d.in)-1]); !ok {
177 | d.err = InvalidByteError(d.in[len(d.in)-1])
178 | } else {
179 | d.err = io.ErrUnexpectedEOF
180 | }
181 | }
182 | }
183 |
184 | // Decode internal buffer into output buffer
185 | if numAvail := len(d.in) / 2; len(p) > numAvail {
186 | p = p[:numAvail]
187 | }
188 | numDec, err := Decode(p, d.in[:len(p)*2])
189 | d.in = d.in[2*numDec:]
190 | if err != nil {
191 | d.in, d.err = nil, err // Decode error; discard input remainder
192 | }
193 |
194 | if len(d.in) < 2 {
195 | return numDec, d.err // Only expose errors when buffer fully consumed
196 | }
197 | return numDec, nil
198 | }
199 |
200 | // Dumper returns a WriteCloser that writes a hex dump of all written data to
201 | // w. The format of the dump matches the output of `hexdump -C` on the command
202 | // line.
203 | func Dumper(w io.Writer) io.WriteCloser {
204 | return &dumper{w: w}
205 | }
206 |
207 | type dumper struct {
208 | w io.Writer
209 | rightChars [18]byte
210 | buf [14]byte
211 | used int // number of bytes in the current line
212 | n uint // number of bytes, total
213 | closed bool
214 | }
215 |
216 | func toChar(b byte) byte {
217 | if b < 32 || b > 126 {
218 | return '.'
219 | }
220 | return b
221 | }
222 |
223 | func (h *dumper) Write(data []byte) (n int, err error) {
224 | if h.closed {
225 | return 0, fmt.Errorf("encoding/hex: dumper closed")
226 | }
227 |
228 | // Output lines look like:
229 | // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
230 | // ^ offset ^ extra space ^ ASCII of line.
231 | for i := range data {
232 | if h.used == 0 {
233 | // At the beginning of a line we print the current
234 | // offset in hex.
235 | h.buf[0] = byte(h.n >> 24)
236 | h.buf[1] = byte(h.n >> 16)
237 | h.buf[2] = byte(h.n >> 8)
238 | h.buf[3] = byte(h.n)
239 | Encode(h.buf[4:], h.buf[:4])
240 | h.buf[12] = ' '
241 | h.buf[13] = ' '
242 | _, err = h.w.Write(h.buf[4:])
243 | if err != nil {
244 | return
245 | }
246 | }
247 | Encode(h.buf[:], data[i:i+1])
248 | h.buf[2] = ' '
249 | l := 3
250 | if h.used == 7 {
251 | // There's an additional space after the 8th byte.
252 | h.buf[3] = ' '
253 | l = 4
254 | } else if h.used == 15 {
255 | // At the end of the line there's an extra space and
256 | // the bar for the right column.
257 | h.buf[3] = ' '
258 | h.buf[4] = '|'
259 | l = 5
260 | }
261 | _, err = h.w.Write(h.buf[:l])
262 | if err != nil {
263 | return
264 | }
265 | n++
266 | h.rightChars[h.used] = toChar(data[i])
267 | h.used++
268 | h.n++
269 | if h.used == 16 {
270 | h.rightChars[16] = '|'
271 | h.rightChars[17] = '\n'
272 | _, err = h.w.Write(h.rightChars[:])
273 | if err != nil {
274 | return
275 | }
276 | h.used = 0
277 | }
278 | }
279 | return
280 | }
281 |
282 | func (h *dumper) Close() (err error) {
283 | // See the comments in Write() for the details of this format.
284 | if h.closed {
285 | return
286 | }
287 | h.closed = true
288 | if h.used == 0 {
289 | return
290 | }
291 | h.buf[0] = ' '
292 | h.buf[1] = ' '
293 | h.buf[2] = ' '
294 | h.buf[3] = ' '
295 | h.buf[4] = '|'
296 | nBytes := h.used
297 | for h.used < 16 {
298 | l := 3
299 | if h.used == 7 {
300 | l = 4
301 | } else if h.used == 15 {
302 | l = 5
303 | }
304 | _, err = h.w.Write(h.buf[:l])
305 | if err != nil {
306 | return
307 | }
308 | h.used++
309 | }
310 | h.rightChars[nBytes] = '|'
311 | h.rightChars[nBytes+1] = '\n'
312 | _, err = h.w.Write(h.rightChars[:nBytes+2])
313 | return
314 | }
315 |
--------------------------------------------------------------------------------
/file/resolver/hex_gzip.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "bytes"
5 | "compress/gzip"
6 | "io"
7 | "io/ioutil"
8 | "os"
9 | "strings"
10 | "sync"
11 |
12 | "github.com/gobuffalo/packr/v2/file/resolver/encoding/hex"
13 | "github.com/gobuffalo/packr/v2/plog"
14 |
15 | "github.com/gobuffalo/packr/v2/file"
16 | )
17 |
18 | var _ Resolver = &HexGzip{}
19 |
20 | type HexGzip struct {
21 | packed map[string]string
22 | unpacked map[string]string
23 | moot *sync.RWMutex
24 | }
25 |
26 | func (hg HexGzip) String() string {
27 | return String(&hg)
28 | }
29 |
30 | var _ file.FileMappable = &HexGzip{}
31 |
32 | func (hg *HexGzip) FileMap() map[string]file.File {
33 | hg.moot.RLock()
34 | var names []string
35 | for k := range hg.packed {
36 | names = append(names, k)
37 | }
38 | hg.moot.RUnlock()
39 | m := map[string]file.File{}
40 | for _, n := range names {
41 | if f, err := hg.Resolve("", n); err == nil {
42 | m[n] = f
43 | }
44 | }
45 | return m
46 | }
47 |
48 | func (hg *HexGzip) Resolve(box string, name string) (file.File, error) {
49 | plog.Debug(hg, "Resolve", "box", box, "name", name)
50 | hg.moot.Lock()
51 | defer hg.moot.Unlock()
52 |
53 | if s, ok := hg.unpacked[name]; ok {
54 | return file.NewFile(name, []byte(s))
55 | }
56 | packed, ok := hg.packed[name]
57 | if !ok {
58 | return nil, os.ErrNotExist
59 | }
60 |
61 | unpacked, err := UnHexGzipString(packed)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | f, err := file.NewFile(OsPath(name), []byte(unpacked))
67 | if err != nil {
68 | return nil, err
69 | }
70 | hg.unpacked[name] = f.String()
71 | return f, nil
72 | }
73 |
74 | func NewHexGzip(files map[string]string) (*HexGzip, error) {
75 | if files == nil {
76 | files = map[string]string{}
77 | }
78 |
79 | hg := &HexGzip{
80 | packed: files,
81 | unpacked: map[string]string{},
82 | moot: &sync.RWMutex{},
83 | }
84 |
85 | return hg, nil
86 | }
87 |
88 | func HexGzipString(s string) (string, error) {
89 | bb := &bytes.Buffer{}
90 | enc := hex.NewEncoder(bb)
91 | zw := gzip.NewWriter(enc)
92 | io.Copy(zw, strings.NewReader(s))
93 | zw.Close()
94 |
95 | return bb.String(), nil
96 | }
97 |
98 | func UnHexGzipString(packed string) (string, error) {
99 | br := bytes.NewBufferString(packed)
100 | dec := hex.NewDecoder(br)
101 | zr, err := gzip.NewReader(dec)
102 | if err != nil {
103 | return "", err
104 | }
105 | defer zr.Close()
106 |
107 | b, err := ioutil.ReadAll(zr)
108 | if err != nil {
109 | return "", err
110 | }
111 | return string(b), nil
112 | }
113 |
--------------------------------------------------------------------------------
/file/resolver/hex_gzip_test.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "io/ioutil"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_HexGzip_Find(t *testing.T) {
12 | r := require.New(t)
13 |
14 | x, err := HexGzipString("foo!")
15 | r.NoError(err)
16 | files := map[string]string{
17 | "foo.txt": x,
18 | }
19 | d, err := NewHexGzip(files)
20 | r.NoError(err)
21 |
22 | f, err := d.Resolve("", "foo.txt")
23 | r.NoError(err)
24 |
25 | fi, err := f.FileInfo()
26 | r.NoError(err)
27 | r.Equal("foo.txt", fi.Name())
28 |
29 | b, err := ioutil.ReadAll(f)
30 | r.NoError(err)
31 | r.Equal("foo!", strings.TrimSpace(string(b)))
32 | }
33 |
34 | func Test_fo(t *testing.T) {
35 | r := require.New(t)
36 | x := "1f8b08000000000000ff9c575f6fe3b8117fd7a798ea490e6c0a7d2b5ce4806c76b3b9c29718916f53e0b04818696cb34b715892b2e306feeec5905262a7ebddb6010249e4f037bff9c399b195f537b942907550647c96a9d6920b506400f94a8575f7246a6acb153d75cba5d454a2d9ecf293bbfd930596e46af45e9f906cb7934182a5ad74b2d5b45aa13b7de040e83d85ce38d21a9bd263dd39ccb30ce0e505d41204d9e0c5bd0aeb3959d8eff9e0cb4b5afd8d1ad47efe6db5dfffd4a689255bf6ffed364ff8681a98ecf7efb55df87b7c8a1b00b577cbd326f12e63a93fffc59c96e2ddd3043988ee67842ee6bff6840e419c2f6b72fe34f673e9d17bce0d96a9c9043421ec2cfec0a437a177a446595696f0e9e60b280f9dc70602c11ab505bf55a15e83c7109459797892bc4b06b66b7408618d7c525aab552d395519e109955981eb8c808fb8949d0ebc9a37b8414db6451372916da48b1acf8133577cc650e49f6f1f3edd7cc9c7c7b2a3282bad85b3de1a71616df6fdb8b2e802ce383062e1a4f15a0672596f2c07a02ce1c25a66946c905a83a32ea007691a6855d368dc4a877c53a0d7c8a7fc9a3addc01342834b65b011b0582bcf48618d60d06d106a34011dd01276d4b977ce115959f2d21d75eccef181b231ac1c75d68f01432d840026d060ada5c30616b77398fc021f6fef6f1823e96d511acf3ed85107b269401e920f048fd2da473893cb80eeac07e3c8488688eac610d632a477d82aade1e676016bb9c1b461707b80c9f62278d9c6a0b3d9ae4336d5a1a7ced503e168ab07e9618b5a0f46ff1a406a4f3ded083fb8dd21d46bacbf6103ca4467926bd0f1dbeec811d1f8c78a3d7da534fa476621e1f26271793db998cd12e2183c810a43c0a4deca1d67251fb65ad6d880963e0cbae29923ea63e6ae42f28875b8413390658cd7b044cfb2602030b841c7c9514bae77225b76a6e64c2b4647790b2f5c5596319fcfcfc1281d57202d0cf9266e705b0cefb736b24a62009fcc66ca5767dc7f9faa27fc57a5225105723885a164889b4eeb97fd003077782f1dfa29fcf175d0d9af0d3ab9c4382ffaeb5c8cc4b5348d463740ec0fc80c55e588c18d6c710af9c350e1f95b700cf7fb879e569e30f6a32c3ef99e76815a1914bb74070e1be5b08edeaeaad9e034f1bbc722b6acaa9a15a3b7d3335a81c37f76e8436a6318d07928964ac717be98bb9138c239e864623e9c99c5ef1ef8b4b7cb122a0c29a57ab57dc985589803c1dfaadb9b237d073559545c020faa45f90f4f261f8db203bfa60e72baa94516734781fd245752191fe0b2babb021982acbf7901eb10ac9f96e576bb15b495de0a72ab5299069f855ddbf2d291f7934a057cb84b663c5c915ba1db3d148c341ad4dc614b9b6856a3bc7cd25c33943ff627b751cee59f1a71340744f87b27ad0794f5fad59dca8084c0553dcd456290855a7c91bac3220fcff948146796acb8246330cafd4f94e318917a47d252b4711a111f3ffc1fb1a83074363696ce63e2ae5391991e693ddc29beaf87453f7f5a1479998fe19a5aecefe07713f390061f7cab99e9bcf41e83ff40cf2366e963ef5af2362c1db531896df7a4550de9d291db65ff71bf233187a173869564fbec44572ecb23d35361d5241bd0544bddab1ef39c019d8ddac36bf386c77e0a168bc771eca8a6490883ea777d2f7a9a123e43d5e462dd1874918b69c5507d66c5bec2eb2d39046596e4da4875fa7a5d5e4729a178d82e1baa7d1911d5bfa2682af8c7717c2de7bfbd12bc62292eab3ca9a08bffe4524f588ce3ca799c3a630b882324bf7da0e722172269449f8fc690a399fc5ee5a3bfc6437f7ad74b4415c816e8dc2806ea354e8b032ec528dbbf1b8d8642fa030773e7ee77fb822c0d2853531bc7bee4d138212cb9372a0f86025c2f16f34a40cefe9c96253ecbd66ae4293587f35fd2ba7fb77130ebbce96f083d9c9d190a67678026dee2aa9a89183f1eba8e262e581034144933d8966b734d6d8bf146c66908aca3e7dd4f221d65fe8b2c39f9cba74cf9f1d6a87e941bbddf871f6287214b68c7334155cdeefa584cd388c083f539e4d651d3c5cbd337d7aa9acdd9926b940d3a3f8556da3f7ce0b1f06b7abce47f9f5c91db4ad76033e15642f9b40f4f1edbfc9eb3e6df010000ffffa0d4ca87a10e0000"
37 | y, err := UnHexGzipString(x)
38 | r.NoError(err)
39 | r.NotEqual("", y)
40 | }
41 |
--------------------------------------------------------------------------------
/file/resolver/ident.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "path/filepath"
5 | "runtime"
6 | "strings"
7 | )
8 |
9 | func Key(s string) string {
10 | s = strings.Replace(s, "\\", "/", -1)
11 | return s
12 | }
13 |
14 | func OsPath(s string) string {
15 | if runtime.GOOS == "windows" {
16 | s = strings.Replace(s, "/", string(filepath.Separator), -1)
17 | } else {
18 | s = strings.Replace(s, "\\", string(filepath.Separator), -1)
19 | }
20 | return s
21 | }
22 |
--------------------------------------------------------------------------------
/file/resolver/ident_test.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "runtime"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_Ident_OsPath(t *testing.T) {
11 | table := map[string]string{
12 | "foo/bar/baz": "foo/bar/baz",
13 | "foo\\bar\\baz": "foo/bar/baz",
14 | }
15 |
16 | if runtime.GOOS == "windows" {
17 | table = ident_OsPath_Windows_Table()
18 | }
19 |
20 | for in, out := range table {
21 | t.Run(in, func(st *testing.T) {
22 | r := require.New(st)
23 | r.Equal(out, OsPath(in))
24 | })
25 | }
26 | }
27 |
28 | func ident_OsPath_Windows_Table() map[string]string {
29 | return map[string]string{
30 | "foo/bar/baz": "foo\\bar\\baz",
31 | "foo\\bar\\baz": "foo\\bar\\baz",
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/file/resolver/in_memory.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "io/ioutil"
5 |
6 | "github.com/gobuffalo/packd"
7 | "github.com/gobuffalo/packr/v2/file"
8 | "github.com/gobuffalo/packr/v2/plog"
9 | )
10 |
11 | var _ Resolver = &InMemory{}
12 |
13 | type InMemory struct {
14 | *packd.MemoryBox
15 | }
16 |
17 | func (d InMemory) String() string {
18 | return String(&d)
19 | }
20 |
21 | func (d *InMemory) Resolve(box string, name string) (file.File, error) {
22 | b, err := d.MemoryBox.Find(name)
23 | if err != nil {
24 | return nil, err
25 | }
26 | return file.NewFile(name, b)
27 | }
28 |
29 | func (d *InMemory) Pack(name string, f file.File) error {
30 | plog.Debug(d, "Pack", "name", name)
31 | b, err := ioutil.ReadAll(f)
32 | if err != nil {
33 | return err
34 | }
35 | d.AddBytes(name, b)
36 | return nil
37 | }
38 |
39 | func (d *InMemory) FileMap() map[string]file.File {
40 | m := map[string]file.File{}
41 | d.Walk(func(path string, file file.File) error {
42 | m[path] = file
43 | return nil
44 | })
45 | return m
46 | }
47 |
48 | func NewInMemory(files map[string]file.File) *InMemory {
49 | if files == nil {
50 | files = map[string]file.File{}
51 | }
52 | box := packd.NewMemoryBox()
53 |
54 | for p, f := range files {
55 | if b, err := ioutil.ReadAll(f); err == nil {
56 | box.AddBytes(p, b)
57 | }
58 | }
59 |
60 | return &InMemory{
61 | MemoryBox: box,
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/file/resolver/in_memory_test.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "io/ioutil"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/gobuffalo/packr/v2/file"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func Test_inMemory_Find(t *testing.T) {
13 | r := require.New(t)
14 |
15 | files := map[string]file.File{
16 | "foo.txt": qfile("foo.txt", "foo!"),
17 | }
18 | d := NewInMemory(files)
19 |
20 | f, err := d.Resolve("", "foo.txt")
21 | r.NoError(err)
22 |
23 | fi, err := f.FileInfo()
24 | r.NoError(err)
25 | r.Equal("foo.txt", fi.Name())
26 |
27 | b, err := ioutil.ReadAll(f)
28 | r.NoError(err)
29 | r.Equal("foo!", strings.TrimSpace(string(b)))
30 | }
31 |
--------------------------------------------------------------------------------
/file/resolver/packable.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import "github.com/gobuffalo/packr/v2/file"
4 |
5 | type Packable interface {
6 | Pack(name string, f file.File) error
7 | }
8 |
--------------------------------------------------------------------------------
/file/resolver/resolver.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "os"
7 |
8 | "github.com/gobuffalo/packr/v2/file"
9 | )
10 |
11 | type Resolver interface {
12 | Resolve(string, string) (file.File, error)
13 | }
14 |
15 | func defaultResolver() Resolver {
16 | pwd, _ := os.Getwd()
17 | return &Disk{
18 | Root: pwd,
19 | }
20 | }
21 |
22 | var DefaultResolver = defaultResolver()
23 |
24 | func String(r Resolver) string {
25 | m := map[string]interface{}{
26 | "name": fmt.Sprintf("%T", r),
27 | }
28 | if fm, ok := r.(file.FileMappable); ok {
29 | m["files"] = fm
30 | }
31 | b, _ := json.Marshal(m)
32 | return string(b)
33 | }
34 |
--------------------------------------------------------------------------------
/file/resolver/resolver_test.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import "github.com/gobuffalo/packr/v2/file"
4 |
5 | func qfile(name string, body string) file.File {
6 | f, err := file.NewFile(name, []byte(body))
7 | if err != nil {
8 | panic(err)
9 | }
10 | return f
11 | }
12 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/gobuffalo/packr/v2
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/gobuffalo/logger v1.0.6
7 | github.com/gobuffalo/packd v1.0.1
8 | github.com/karrick/godirwalk v1.16.1
9 | github.com/markbates/errx v1.1.0
10 | github.com/markbates/oncer v1.0.0
11 | github.com/markbates/safe v1.0.1
12 | github.com/rogpeppe/go-internal v1.8.0
13 | github.com/sirupsen/logrus v1.8.1
14 | github.com/spf13/cobra v1.2.1
15 | github.com/stretchr/testify v1.7.0
16 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
17 | golang.org/x/tools v0.1.7
18 | )
19 |
--------------------------------------------------------------------------------
/helpers.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "runtime"
7 | "strings"
8 |
9 | "github.com/gobuffalo/packr/v2/plog"
10 | )
11 |
12 | func construct(name string, path string) *Box {
13 | return &Box{
14 | Path: path,
15 | Name: name,
16 | ResolutionDir: resolutionDir(path),
17 | resolvers: resolversMap{},
18 | dirs: dirsMap{},
19 | }
20 | }
21 |
22 | func resolutionDirTestFilename(filename, og string) (string, bool) {
23 | ng := filepath.Join(filepath.Dir(filename), og)
24 |
25 | // // this little hack courtesy of the `-cover` flag!!
26 | cov := filepath.Join("_test", "_obj_test")
27 | ng = strings.Replace(ng, string(filepath.Separator)+cov, "", 1)
28 |
29 | if resolutionDirExists(ng, og) {
30 | return ng, true
31 | }
32 |
33 | ng = filepath.Join(os.Getenv("GOPATH"), "src", ng)
34 | if resolutionDirExists(ng, og) {
35 | return ng, true
36 | }
37 |
38 | return og, false
39 | }
40 |
41 | func resolutionDirExists(s, og string) bool {
42 | _, err := os.Stat(s)
43 | if err != nil {
44 | return false
45 | }
46 | plog.Debug("packr", "resolutionDir", "original", og, "resolved", s)
47 | return true
48 | }
49 |
50 | func resolutionDir(og string) string {
51 | ng, _ := filepath.Abs(og)
52 |
53 | if resolutionDirExists(ng, og) {
54 | return ng
55 | }
56 |
57 | // packr.New
58 | _, filename, _, _ := runtime.Caller(3)
59 | ng, ok := resolutionDirTestFilename(filename, og)
60 | if ok {
61 | return ng
62 | }
63 |
64 | // packr.NewBox (deprecated)
65 | _, filename, _, _ = runtime.Caller(4)
66 | ng, ok = resolutionDirTestFilename(filename, og)
67 | if ok {
68 | return ng
69 | }
70 |
71 | return og
72 | }
73 |
--------------------------------------------------------------------------------
/http_box_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/gobuffalo/packd"
10 | "github.com/gobuffalo/packr/v2/file/resolver"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | var httpBox = func() packd.Box {
15 | box := New("http box", "")
16 |
17 | ind, err := resolver.HexGzipString("Index!
")
18 | if err != nil {
19 | panic(err)
20 | }
21 |
22 | hello, err := resolver.HexGzipString("hello world!")
23 | if err != nil {
24 | panic(err)
25 | }
26 |
27 | hg, err := resolver.NewHexGzip(map[string]string{
28 | "index.html": ind,
29 | "hello.txt": hello,
30 | })
31 | if err != nil {
32 | panic(err)
33 | }
34 |
35 | box.DefaultResolver = hg
36 | return box
37 | }()
38 |
39 | func Test_HTTPBox(t *testing.T) {
40 | r := require.New(t)
41 |
42 | mux := http.NewServeMux()
43 | mux.Handle("/", http.FileServer(httpBox))
44 |
45 | req, err := http.NewRequest("GET", "/hello.txt", nil)
46 | r.NoError(err)
47 |
48 | res := httptest.NewRecorder()
49 |
50 | mux.ServeHTTP(res, req)
51 |
52 | r.Equal(200, res.Code)
53 | r.Equal("hello world!", strings.TrimSpace(res.Body.String()))
54 | }
55 |
56 | func Test_HTTPBox_NotFound(t *testing.T) {
57 | r := require.New(t)
58 |
59 | mux := http.NewServeMux()
60 | mux.Handle("/", http.FileServer(httpBox))
61 |
62 | req, err := http.NewRequest("GET", "/notInBox.txt", nil)
63 | r.NoError(err)
64 |
65 | res := httptest.NewRecorder()
66 |
67 | mux.ServeHTTP(res, req)
68 |
69 | r.Equal(404, res.Code)
70 | }
71 |
72 | func Test_HTTPBox_Handles_IndexHTML_Nested(t *testing.T) {
73 | r := require.New(t)
74 |
75 | box := New("Test_HTTPBox_Handles_IndexHTML_Nested", "!")
76 | box.AddString("foo/index.html", "foo")
77 |
78 | mux := http.NewServeMux()
79 | mux.Handle("/", http.FileServer(box))
80 |
81 | req, err := http.NewRequest("GET", "/foo", nil)
82 | r.NoError(err)
83 |
84 | res := httptest.NewRecorder()
85 |
86 | mux.ServeHTTP(res, req)
87 |
88 | r.Equal(200, res.Code)
89 |
90 | r.Equal("foo", strings.TrimSpace(res.Body.String()))
91 | }
92 |
93 | func Test_HTTPBox_Handles_IndexHTML(t *testing.T) {
94 | r := require.New(t)
95 |
96 | mux := http.NewServeMux()
97 | mux.Handle("/", http.FileServer(httpBox))
98 |
99 | req, err := http.NewRequest("GET", "/", nil)
100 | r.NoError(err)
101 |
102 | res := httptest.NewRecorder()
103 |
104 | mux.ServeHTTP(res, req)
105 |
106 | r.Equal(200, res.Code)
107 |
108 | r.Equal("Index!
", strings.TrimSpace(res.Body.String()))
109 | }
110 |
111 | func Test_HTTPBox_CaseInsensitive(t *testing.T) {
112 | mux := http.NewServeMux()
113 | httpBox.AddString("myfile.txt", "this is my file")
114 | mux.Handle("/", http.FileServer(httpBox))
115 |
116 | for _, path := range []string{"/MyFile.txt", "/myfile.txt", "/Myfile.txt"} {
117 | t.Run(path, func(st *testing.T) {
118 | r := require.New(st)
119 |
120 | req, err := http.NewRequest("GET", path, nil)
121 | r.NoError(err)
122 |
123 | res := httptest.NewRecorder()
124 |
125 | mux.ServeHTTP(res, req)
126 |
127 | r.Equal(200, res.Code)
128 | r.Equal("this is my file", strings.TrimSpace(res.Body.String()))
129 | })
130 | }
131 | }
132 |
133 | func Test_HTTPBox_Disk(t *testing.T) {
134 | r := require.New(t)
135 |
136 | box := New("http disk box", "./_fixtures/http_test")
137 | mux := http.NewServeMux()
138 | mux.Handle("/", http.FileServer(box))
139 |
140 | type testcase struct {
141 | URL, Content, Location string
142 | Code int
143 | }
144 |
145 | testcases := []testcase{
146 | {"/", "Index", "", 200},
147 | {"/sub", "Sub", "", 200},
148 | {"/index.html", "", "./", 301},
149 | {"/sub/index.html", "", "./", 301},
150 | {"/sub/", "", "../sub", 301},
151 | {"/footer.html", "Footer", "", 200},
152 | {"/css/main.css", "Css", "", 200},
153 | {"/css", "404 page not found", "", 404},
154 | {"/css/", "404 page not found", "", 404},
155 | }
156 |
157 | for _, tc := range testcases {
158 | t.Run("path"+tc.URL, func(t *testing.T) {
159 | req, err := http.NewRequest("GET", tc.URL, nil)
160 | r.NoError(err)
161 | res := httptest.NewRecorder()
162 | mux.ServeHTTP(res, req)
163 |
164 | r.Equal(tc.Code, res.Code)
165 | r.Equal(tc.Location, res.Header().Get("location"))
166 | r.Equal(tc.Content, strings.TrimSpace(res.Body.String()))
167 | })
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/jam/pack.go:
--------------------------------------------------------------------------------
1 | package jam
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "io"
7 | "os"
8 | "os/exec"
9 | "time"
10 |
11 | "github.com/gobuffalo/packr/v2/jam/parser"
12 | "github.com/gobuffalo/packr/v2/jam/store"
13 | "github.com/gobuffalo/packr/v2/plog"
14 | )
15 |
16 | // PackOptions ...
17 | type PackOptions struct {
18 | IgnoreImports bool
19 | Legacy bool
20 | StoreCmd string
21 | Roots []string
22 | RootsOptions *parser.RootsOptions
23 | }
24 |
25 | // Pack the roots given + PWD
26 | func Pack(opts PackOptions) error {
27 | pwd, err := os.Getwd()
28 | if err != nil {
29 | return err
30 | }
31 |
32 | opts.Roots = append(opts.Roots, pwd)
33 | if err := Clean(opts.Roots...); err != nil {
34 | return err
35 | }
36 |
37 | if opts.RootsOptions == nil {
38 | opts.RootsOptions = &parser.RootsOptions{}
39 | }
40 |
41 | if opts.IgnoreImports {
42 | opts.RootsOptions.IgnoreImports = true
43 | }
44 |
45 | p, err := parser.NewFromRoots(opts.Roots, opts.RootsOptions)
46 | if err != nil {
47 | return err
48 | }
49 | boxes, err := p.Run()
50 | if err != nil {
51 | return err
52 | }
53 |
54 | // reduce boxes - remove ones we don't want
55 | // MB: current assumption is we want all these
56 | // boxes, just adding a comment suggesting they're
57 | // might be a reason to exclude some
58 |
59 | plog.Logger.Debugf("found %d boxes", len(boxes))
60 |
61 | if len(opts.StoreCmd) != 0 {
62 | return ShellPack(opts, boxes)
63 | }
64 |
65 | var st store.Store = store.NewDisk("", "")
66 |
67 | if opts.Legacy {
68 | st = store.NewLegacy()
69 | }
70 |
71 | for _, b := range boxes {
72 | if b.Name == store.DISK_GLOBAL_KEY {
73 | continue
74 | }
75 | if err := st.Pack(b); err != nil {
76 | return err
77 | }
78 | }
79 | if cl, ok := st.(io.Closer); ok {
80 | return cl.Close()
81 | }
82 | return nil
83 | }
84 |
85 | // ShellPack ...
86 | func ShellPack(opts PackOptions, boxes parser.Boxes) error {
87 | b, err := json.Marshal(boxes)
88 | if err != nil {
89 | return err
90 | }
91 | ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
92 | defer cancel()
93 | c := exec.CommandContext(ctx, opts.StoreCmd, string(b))
94 | c.Stdout = os.Stdout
95 | c.Stderr = os.Stderr
96 | return c.Run()
97 |
98 | }
99 |
100 | // Clean ...
101 | func Clean(args ...string) error {
102 | pwd, err := os.Getwd()
103 | if err != nil {
104 | return err
105 | }
106 | args = append(args, pwd)
107 | for _, root := range args {
108 | if err := store.Clean(root); err != nil {
109 | return err
110 | }
111 | }
112 | return nil
113 | }
114 |
--------------------------------------------------------------------------------
/jam/parser/_fixtures/new_from_roots/_r/r.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("bob", "dylan")
7 | }
8 |
--------------------------------------------------------------------------------
/jam/parser/_fixtures/new_from_roots/e/e.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("tom", "petty")
7 | packr.NewBox("./heartbreakers")
8 | }
9 |
--------------------------------------------------------------------------------
/jam/parser/_fixtures/new_from_roots/q.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("aretha", "franklin")
7 | }
8 |
--------------------------------------------------------------------------------
/jam/parser/_fixtures/new_from_roots/w/w.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | func main() {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/jam/parser/args.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | )
7 |
8 | // FromArgs is useful when writing packr store-cmd binaries.
9 | /*
10 | package main
11 |
12 | import (
13 | "log"
14 | "os"
15 |
16 | "github.com/gobuffalo/packr/v2/jam/parser"
17 | "github.com/markbates/s3packr/s3packr"
18 | )
19 |
20 | func main() {
21 | err := parser.FromArgs(os.Args[1:], func(boxes parser.Boxes) error {
22 | for _, box := range boxes {
23 | s3 := s3packr.New(box)
24 | if err := s3.Pack(box); err != nil {
25 | return err
26 | }
27 | }
28 | return nil
29 | })
30 |
31 | if err != nil {
32 | log.Fatal(err)
33 | }
34 | }
35 | */
36 | func FromArgs(args []string, fn func(Boxes) error) error {
37 | if len(args) == 0 {
38 | return fmt.Errorf("you must supply a payload")
39 | }
40 | payload := args[0]
41 | if len(payload) == 0 {
42 | return fmt.Errorf("you must supply a payload")
43 | }
44 |
45 | var boxes Boxes
46 | err := json.Unmarshal([]byte(payload), &boxes)
47 | if err != nil {
48 | return err
49 | }
50 |
51 | return fn(boxes)
52 | }
53 |
--------------------------------------------------------------------------------
/jam/parser/box.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "strings"
7 | )
8 |
9 | // Box found while parsing a file
10 | type Box struct {
11 | Name string // name of the box
12 | Path string // relative path of folder NewBox("./templates")
13 | AbsPath string // absolute path of Path
14 | Package string // the package name the box was found in
15 | PWD string // the PWD when the parser was run
16 | PackageDir string // the absolute path of the package where the box was found
17 | }
18 |
19 | type Boxes []*Box
20 |
21 | // String - json returned
22 | func (b Box) String() string {
23 | x, _ := json.Marshal(b)
24 | return string(x)
25 | }
26 |
27 | // NewBox stub from the name and the path provided
28 | func NewBox(name string, path string) *Box {
29 | if len(name) == 0 {
30 | name = path
31 | }
32 | name = strings.Replace(name, "\"", "", -1)
33 | pwd, _ := os.Getwd()
34 | box := &Box{
35 | Name: name,
36 | Path: path,
37 | PWD: pwd,
38 | }
39 | return box
40 | }
41 |
--------------------------------------------------------------------------------
/jam/parser/file.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "io/ioutil"
7 | "path/filepath"
8 | )
9 |
10 | // File that is to be parsed
11 | type File struct {
12 | io.Reader
13 | Path string
14 | AbsPath string
15 | }
16 |
17 | // Name of the file "app.go"
18 | func (f File) Name() string {
19 | return f.Path
20 | }
21 |
22 | // String returns the contents of the reader
23 | func (f *File) String() string {
24 | src, _ := ioutil.ReadAll(f)
25 | f.Reader = bytes.NewReader(src)
26 | return string(src)
27 | }
28 |
29 | func (s *File) Write(p []byte) (int, error) {
30 | bb := &bytes.Buffer{}
31 | i, err := bb.Write(p)
32 | s.Reader = bb
33 | return i, err
34 | }
35 |
36 | // NewFile takes the name of the file you want to
37 | // write to and a reader to reader from
38 | func NewFile(path string, r io.Reader) *File {
39 | if r == nil {
40 | r = &bytes.Buffer{}
41 | }
42 | if seek, ok := r.(io.Seeker); ok {
43 | seek.Seek(0, 0)
44 | }
45 | abs := path
46 | if !filepath.IsAbs(path) {
47 | abs, _ = filepath.Abs(path)
48 | }
49 | return &File{
50 | Reader: r,
51 | Path: path,
52 | AbsPath: abs,
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/jam/parser/finder.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "go/build"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 | "time"
10 |
11 | "github.com/gobuffalo/packr/v2/plog"
12 | "github.com/karrick/godirwalk"
13 | "github.com/markbates/errx"
14 | "github.com/markbates/oncer"
15 | )
16 |
17 | type finder struct {
18 | id time.Time
19 | }
20 |
21 | func (fd *finder) key(m, dir string) string {
22 | return fmt.Sprintf("%s-*parser.finder#%s-%s", fd.id, m, dir)
23 | }
24 |
25 | // findAllGoFiles *.go files for a given diretory
26 | func (fd *finder) findAllGoFiles(dir string) ([]string, error) {
27 | var err error
28 | var names []string
29 | oncer.Do(fd.key("findAllGoFiles", dir), func() {
30 | plog.Debug(fd, "findAllGoFiles", "dir", dir)
31 |
32 | callback := func(path string, do *godirwalk.Dirent) error {
33 | ext := filepath.Ext(path)
34 | if ext != ".go" {
35 | return nil
36 | }
37 | //check if path is a dir
38 | fi, err := os.Stat(path)
39 | if err != nil {
40 | return nil
41 | }
42 |
43 | if fi.IsDir() {
44 | return nil
45 | }
46 |
47 | names = append(names, path)
48 | return nil
49 | }
50 | err = godirwalk.Walk(dir, &godirwalk.Options{
51 | FollowSymbolicLinks: true,
52 | Callback: callback,
53 | })
54 | })
55 |
56 | return names, err
57 | }
58 |
59 | func (fd *finder) findAllGoFilesImports(dir string) ([]string, error) {
60 | var err error
61 | var names []string
62 | oncer.Do(fd.key("findAllGoFilesImports", dir), func() {
63 | ctx := build.Default
64 |
65 | if len(ctx.SrcDirs()) == 0 {
66 | err = fmt.Errorf("no src directories found")
67 | return
68 | }
69 |
70 | pkg, err := ctx.ImportDir(dir, 0)
71 | if strings.HasPrefix(pkg.ImportPath, "github.com/gobuffalo/packr") {
72 | return
73 | }
74 |
75 | if err != nil {
76 | if !strings.Contains(err.Error(), "cannot find package") {
77 | if _, ok := errx.Unwrap(err).(*build.NoGoError); !ok {
78 | err = err
79 | return
80 | }
81 | }
82 | }
83 |
84 | if pkg.Goroot {
85 | return
86 | }
87 | if len(pkg.GoFiles) <= 0 {
88 | return
89 | }
90 |
91 | plog.Debug(fd, "findAllGoFilesImports", "dir", dir)
92 |
93 | names, _ = fd.findAllGoFiles(dir)
94 | for _, n := range pkg.GoFiles {
95 | names = append(names, filepath.Join(pkg.Dir, n))
96 | }
97 | for _, imp := range pkg.Imports {
98 | if len(ctx.SrcDirs()) == 0 {
99 | continue
100 | }
101 | d := ctx.SrcDirs()[len(ctx.SrcDirs())-1]
102 | ip := filepath.Join(d, imp)
103 | n, err := fd.findAllGoFilesImports(ip)
104 | if err != nil && len(n) != 0 {
105 | names = n
106 | return
107 | }
108 | names = append(names, n...)
109 | }
110 | })
111 | return names, err
112 | }
113 |
--------------------------------------------------------------------------------
/jam/parser/gogen.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "go/ast"
5 | "go/parser"
6 | "go/token"
7 | "io"
8 | "strings"
9 |
10 | "github.com/gobuffalo/packd"
11 | "github.com/markbates/errx"
12 | )
13 |
14 | // ParsedFile ...
15 | type ParsedFile struct {
16 | File packd.SimpleFile
17 | FileSet *token.FileSet
18 | Ast *ast.File
19 | Lines []string
20 | }
21 |
22 | // ParseFileMode ...
23 | func ParseFileMode(gf packd.SimpleFile, mode parser.Mode) (ParsedFile, error) {
24 | pf := ParsedFile{
25 | FileSet: token.NewFileSet(),
26 | File: gf,
27 | }
28 |
29 | src := gf.String()
30 | f, err := parser.ParseFile(pf.FileSet, gf.Name(), src, mode)
31 | if err != nil && errx.Unwrap(err) != io.EOF {
32 | return pf, err
33 | }
34 | pf.Ast = f
35 |
36 | pf.Lines = strings.Split(src, "\n")
37 | return pf, nil
38 | }
39 |
40 | // ParseFile ...
41 | func ParseFile(gf packd.SimpleFile) (ParsedFile, error) {
42 | return ParseFileMode(gf, 0)
43 | }
44 |
--------------------------------------------------------------------------------
/jam/parser/parser.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "os"
5 | "sort"
6 | "strings"
7 |
8 | "github.com/gobuffalo/packr/v2/plog"
9 | )
10 |
11 | // Parser to find boxes
12 | type Parser struct {
13 | Prospects []*File // a list of files to check for boxes
14 | IgnoreImports bool
15 | }
16 |
17 | // Run the parser and run any boxes found
18 | func (p *Parser) Run() (Boxes, error) {
19 | var boxes Boxes
20 | for _, pros := range p.Prospects {
21 | plog.Debug(p, "Run", "parsing", pros.Name())
22 | v := NewVisitor(pros)
23 | pbr, err := v.Run()
24 | if err != nil {
25 | return boxes, err
26 | }
27 | for _, b := range pbr {
28 | plog.Debug(p, "Run", "file", pros.Name(), "box", b.Name)
29 | boxes = append(boxes, b)
30 | }
31 | }
32 |
33 | pwd, _ := os.Getwd()
34 | sort.Slice(boxes, func(a, b int) bool {
35 | b1 := boxes[a]
36 | return !strings.HasPrefix(b1.AbsPath, pwd)
37 | })
38 | return boxes, nil
39 | }
40 |
41 | // New Parser from a list of File
42 | func New(prospects ...*File) *Parser {
43 | return &Parser{
44 | Prospects: prospects,
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/jam/parser/parser_test.go:
--------------------------------------------------------------------------------
1 | package parser_test
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | "testing"
7 |
8 | "github.com/gobuffalo/packr/v2/jam/parser"
9 | "github.com/gobuffalo/packr/v2/jam/store"
10 | "github.com/markbates/oncer"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | func init() {
15 | parser.DefaultIgnoredFolders = []string{"vendor", ".git", "node_modules", ".idea"}
16 | }
17 |
18 | func Test_Parser_Run(t *testing.T) {
19 | r := require.New(t)
20 |
21 | f1 := parser.NewFile("a/a.x", strings.NewReader(fmt.Sprintf(basicGoTmpl, "a")))
22 | f2 := parser.NewFile("b/b.x", strings.NewReader(fmt.Sprintf(basicGoTmpl, "b")))
23 |
24 | p := parser.New(f1, f2)
25 | boxes, err := p.Run()
26 | r.NoError(err)
27 |
28 | r.Len(boxes, 4)
29 | }
30 |
31 | func Test_NewFrom_Roots_Imports(t *testing.T) {
32 | r := require.New(t)
33 | store.Clean("./_fixtures")
34 | p, err := parser.NewFromRoots([]string{"./_fixtures/new_from_roots"}, &parser.RootsOptions{})
35 | r.NoError(err)
36 |
37 | boxes, err := p.Run()
38 | r.NoError(err)
39 | r.Len(boxes, 3)
40 | }
41 |
42 | func Test_NewFrom_Roots_Disk(t *testing.T) {
43 | r := require.New(t)
44 | oncer.Reset()
45 | store.Clean("./_fixtures")
46 | p, err := parser.NewFromRoots([]string{"./_fixtures/new_from_roots"}, &parser.RootsOptions{
47 | IgnoreImports: true,
48 | })
49 | r.NoError(err)
50 |
51 | boxes, err := p.Run()
52 | r.NoError(err)
53 | r.Len(boxes, 3)
54 | }
55 |
56 | const basicGoTmpl = `package %s
57 |
58 | import "github.com/gobuffalo/packr/v2"
59 |
60 | func init() {
61 | packr.New("elvis", "./presley")
62 | packr.NewBox("./buddy-holly")
63 | }
64 | `
65 |
--------------------------------------------------------------------------------
/jam/parser/prospect.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "strings"
7 |
8 | "github.com/gobuffalo/packr/v2/file/resolver"
9 | "github.com/gobuffalo/packr/v2/plog"
10 | )
11 |
12 | var DefaultIgnoredFolders = []string{".", "_", "vendor", "node_modules", "_fixtures", "testdata"}
13 |
14 | func IsProspect(path string, ignore ...string) (status bool) {
15 | // plog.Debug("parser", "IsProspect", "path", path, "ignore", ignore)
16 | defer func() {
17 | if status {
18 | plog.Debug("parser", "IsProspect (TRUE)", "path", path, "status", status)
19 | }
20 | }()
21 | if path == "." {
22 | return true
23 | }
24 |
25 | ext := filepath.Ext(path)
26 | dir := filepath.Dir(path)
27 |
28 | fi, _ := os.Stat(path)
29 | if fi != nil {
30 | if fi.IsDir() {
31 | dir = filepath.Base(path)
32 | } else {
33 | if len(ext) > 0 {
34 | dir = filepath.Base(filepath.Dir(path))
35 | }
36 | }
37 | }
38 |
39 | path = strings.ToLower(path)
40 | dir = strings.ToLower(dir)
41 |
42 | if strings.HasSuffix(path, "-packr.go") {
43 | return false
44 | }
45 |
46 | if strings.HasSuffix(path, "_test.go") {
47 | return false
48 | }
49 |
50 | ignore = append(ignore, DefaultIgnoredFolders...)
51 | for i, x := range ignore {
52 | ignore[i] = strings.TrimSpace(strings.ToLower(x))
53 | }
54 |
55 | parts := strings.Split(resolver.OsPath(path), string(filepath.Separator))
56 | if len(parts) == 0 {
57 | return false
58 | }
59 |
60 | for _, i := range ignore {
61 | for _, p := range parts {
62 | if strings.HasPrefix(p, i) {
63 | return false
64 | }
65 | }
66 | }
67 |
68 | un := filepath.Base(path)
69 | if len(ext) != 0 {
70 | un = filepath.Base(filepath.Dir(path))
71 | }
72 | if strings.HasPrefix(un, "_") {
73 | return false
74 | }
75 |
76 | return ext == ".go"
77 | }
78 |
--------------------------------------------------------------------------------
/jam/parser/prospect_test.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func Test_IsProspect(t *testing.T) {
10 | table := []struct {
11 | path string
12 | pass bool
13 | }{
14 | {"foo/.git/config", false},
15 | {"foo/.git/baz.go", false},
16 | {"a.go", true},
17 | {".", true},
18 | {"a/b.go", true},
19 | {"a/b_test.go", false},
20 | {"a/b-packr.go", false},
21 | {"a/vendor/b.go", false},
22 | {"a/_c/c.go", false},
23 | {"a/_c/e/fe/f/c.go", false},
24 | {"a/d/_d.go", false},
25 | {"a/d/", false},
26 | }
27 |
28 | for _, tt := range table {
29 | t.Run(tt.path, func(st *testing.T) {
30 | r := require.New(st)
31 | if tt.pass {
32 | r.True(IsProspect(tt.path, ".", "_"))
33 | } else {
34 | r.False(IsProspect(tt.path, ".", "_"))
35 | }
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/jam/parser/roots.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "time"
10 |
11 | "github.com/gobuffalo/packr/v2/plog"
12 | "github.com/karrick/godirwalk"
13 | )
14 |
15 | type RootsOptions struct {
16 | IgnoreImports bool
17 | Ignores []string
18 | }
19 |
20 | func (r RootsOptions) String() string {
21 | x, _ := json.Marshal(r)
22 | return string(x)
23 | }
24 |
25 | // NewFromRoots scans the file roots provided and returns a
26 | // new Parser containing the prospects
27 | func NewFromRoots(roots []string, opts *RootsOptions) (*Parser, error) {
28 | if opts == nil {
29 | opts = &RootsOptions{}
30 | }
31 |
32 | if len(roots) == 0 {
33 | pwd, _ := os.Getwd()
34 | roots = append(roots, pwd)
35 | }
36 | p := New()
37 | plog.Debug(p, "NewFromRoots", "roots", roots, "options", opts)
38 | callback := func(path string, de *godirwalk.Dirent) error {
39 | if IsProspect(path, opts.Ignores...) {
40 | if de.IsDir() {
41 | return nil
42 | }
43 | roots = append(roots, path)
44 | return nil
45 | }
46 | if de.IsDir() {
47 | return filepath.SkipDir
48 | }
49 | return nil
50 | }
51 | wopts := &godirwalk.Options{
52 | FollowSymbolicLinks: true,
53 | Callback: callback,
54 | }
55 | for _, root := range roots {
56 | plog.Debug(p, "NewFromRoots", "walking", root)
57 | err := godirwalk.Walk(root, wopts)
58 | if err != nil {
59 | return p, err
60 | }
61 | }
62 |
63 | dd := map[string]string{}
64 | fd := &finder{id: time.Now()}
65 | for _, r := range roots {
66 | var names []string
67 | if opts.IgnoreImports {
68 | names, _ = fd.findAllGoFiles(r)
69 | } else {
70 | names, _ = fd.findAllGoFilesImports(r)
71 | }
72 | for _, n := range names {
73 | if IsProspect(n) {
74 | plog.Debug(p, "NewFromRoots", "mapping", n)
75 | dd[n] = n
76 | }
77 | }
78 | }
79 | for path := range dd {
80 | plog.Debug(p, "NewFromRoots", "reading file", path)
81 | b, err := ioutil.ReadFile(path)
82 | if err != nil {
83 | return nil, err
84 | }
85 | p.Prospects = append(p.Prospects, NewFile(path, bytes.NewReader(b)))
86 | }
87 | plog.Debug(p, "NewFromRoots", "found prospects", len(p.Prospects))
88 | return p, nil
89 | }
90 |
--------------------------------------------------------------------------------
/jam/parser/visitor.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "go/ast"
6 | "os"
7 | "path/filepath"
8 | "sort"
9 | "strings"
10 |
11 | "github.com/gobuffalo/packd"
12 | )
13 |
14 | type Visitor struct {
15 | File packd.SimpleFile
16 | Package string
17 | boxes map[string]*Box
18 | errors []error
19 | }
20 |
21 | func NewVisitor(f *File) *Visitor {
22 | return &Visitor{
23 | File: f,
24 | boxes: map[string]*Box{},
25 | errors: []error{},
26 | }
27 | }
28 |
29 | func (v *Visitor) Run() (Boxes, error) {
30 | var boxes Boxes
31 | pf, err := ParseFile(v.File)
32 | if err != nil {
33 | return boxes, err
34 | }
35 |
36 | v.Package = pf.Ast.Name.Name
37 | ast.Walk(v, pf.Ast)
38 |
39 | for _, vb := range v.boxes {
40 | boxes = append(boxes, vb)
41 | }
42 |
43 | sort.Slice(boxes, func(i, j int) bool {
44 | return boxes[i].Name < boxes[j].Name
45 | })
46 |
47 | if len(v.errors) > 0 {
48 | s := make([]string, len(v.errors))
49 | for i, e := range v.errors {
50 | s[i] = e.Error()
51 | }
52 | return boxes, err
53 | }
54 | return boxes, nil
55 | }
56 |
57 | func (v *Visitor) Visit(node ast.Node) ast.Visitor {
58 | if node == nil {
59 | return v
60 | }
61 | if err := v.eval(node); err != nil {
62 | v.errors = append(v.errors, err)
63 | }
64 |
65 | return v
66 | }
67 |
68 | func (v *Visitor) eval(node ast.Node) error {
69 | switch t := node.(type) {
70 | case *ast.CallExpr:
71 | return v.evalExpr(t)
72 | case *ast.Ident:
73 | return v.evalIdent(t)
74 | case *ast.GenDecl:
75 | for _, n := range t.Specs {
76 | if err := v.eval(n); err != nil {
77 | return err
78 | }
79 | }
80 | case *ast.FuncDecl:
81 | if t.Body == nil {
82 | return nil
83 | }
84 | for _, b := range t.Body.List {
85 | if err := v.evalStmt(b); err != nil {
86 | return err
87 | }
88 | }
89 | return nil
90 | case *ast.ValueSpec:
91 | for _, e := range t.Values {
92 | if err := v.evalExpr(e); err != nil {
93 | return err
94 | }
95 | }
96 | }
97 | return nil
98 | }
99 |
100 | func (v *Visitor) evalStmt(stmt ast.Stmt) error {
101 | switch t := stmt.(type) {
102 | case *ast.ExprStmt:
103 | return v.evalExpr(t.X)
104 | case *ast.AssignStmt:
105 | for _, e := range t.Rhs {
106 | if err := v.evalArgs(e); err != nil {
107 | return err
108 | }
109 | }
110 | }
111 | return nil
112 | }
113 |
114 | func (v *Visitor) evalExpr(expr ast.Expr) error {
115 | switch t := expr.(type) {
116 | case *ast.CallExpr:
117 | if t.Fun == nil {
118 | return nil
119 | }
120 | for _, a := range t.Args {
121 | switch at := a.(type) {
122 | case *ast.CallExpr:
123 | if sel, ok := t.Fun.(*ast.SelectorExpr); ok {
124 | return v.evalSelector(at, sel)
125 | }
126 |
127 | if err := v.evalArgs(at); err != nil {
128 | return err
129 | }
130 | case *ast.CompositeLit:
131 | for _, e := range at.Elts {
132 | if err := v.evalExpr(e); err != nil {
133 | return err
134 | }
135 | }
136 | }
137 | }
138 | if ft, ok := t.Fun.(*ast.SelectorExpr); ok {
139 | return v.evalSelector(t, ft)
140 | }
141 | case *ast.KeyValueExpr:
142 | return v.evalExpr(t.Value)
143 | }
144 | return nil
145 | }
146 |
147 | func (v *Visitor) evalArgs(expr ast.Expr) error {
148 | switch at := expr.(type) {
149 | case *ast.CompositeLit:
150 | for _, e := range at.Elts {
151 | if err := v.evalExpr(e); err != nil {
152 | return err
153 | }
154 | }
155 | case *ast.CallExpr:
156 | if at.Fun == nil {
157 | return nil
158 | }
159 | switch st := at.Fun.(type) {
160 | case *ast.SelectorExpr:
161 | if err := v.evalSelector(at, st); err != nil {
162 | return err
163 | }
164 | case *ast.Ident:
165 | return v.evalIdent(st)
166 | }
167 | for _, a := range at.Args {
168 | if err := v.evalArgs(a); err != nil {
169 | return err
170 | }
171 | }
172 | }
173 | return nil
174 | }
175 |
176 | func (v *Visitor) evalSelector(expr *ast.CallExpr, sel *ast.SelectorExpr) error {
177 | x, ok := sel.X.(*ast.Ident)
178 | if !ok {
179 | return nil
180 | }
181 | if x.Name == "packr" {
182 | switch sel.Sel.Name {
183 | case "New":
184 | if len(expr.Args) != 2 {
185 | return fmt.Errorf("`New` requires two arguments")
186 | }
187 |
188 | zz := func(e ast.Expr) (string, error) {
189 | switch at := e.(type) {
190 | case *ast.Ident:
191 | switch at.Obj.Kind {
192 | case ast.Var:
193 | if as, ok := at.Obj.Decl.(*ast.AssignStmt); ok {
194 | return v.fromVariable(as)
195 | }
196 | case ast.Con:
197 | if vs, ok := at.Obj.Decl.(*ast.ValueSpec); ok {
198 | return v.fromConstant(vs)
199 | }
200 | }
201 | return "", v.evalIdent(at)
202 | case *ast.BasicLit:
203 | return at.Value, nil
204 | case *ast.CallExpr:
205 | return "", v.evalExpr(at)
206 | }
207 | return "", fmt.Errorf("can't handle %T", e)
208 | }
209 |
210 | k1, err := zz(expr.Args[0])
211 | if err != nil {
212 | return err
213 | }
214 | k2, err := zz(expr.Args[1])
215 | if err != nil {
216 | return err
217 | }
218 | v.addBox(k1, k2)
219 |
220 | return nil
221 | case "NewBox":
222 | for _, e := range expr.Args {
223 | switch at := e.(type) {
224 | case *ast.Ident:
225 | switch at.Obj.Kind {
226 | case ast.Var:
227 | if as, ok := at.Obj.Decl.(*ast.AssignStmt); ok {
228 | v.addVariable("", as)
229 | }
230 | case ast.Con:
231 | if vs, ok := at.Obj.Decl.(*ast.ValueSpec); ok {
232 | v.addConstant("", vs)
233 | }
234 | }
235 | return v.evalIdent(at)
236 | case *ast.BasicLit:
237 | v.addBox("", at.Value)
238 | case *ast.CallExpr:
239 | return v.evalExpr(at)
240 | }
241 | }
242 | }
243 | }
244 |
245 | return nil
246 | }
247 |
248 | func (v *Visitor) evalIdent(i *ast.Ident) error {
249 | if i.Obj == nil {
250 | return nil
251 | }
252 | if s, ok := i.Obj.Decl.(*ast.AssignStmt); ok {
253 | return v.evalStmt(s)
254 | }
255 | return nil
256 | }
257 |
258 | func (v *Visitor) addBox(name string, path string) {
259 | if len(name) == 0 {
260 | name = path
261 | }
262 | name = strings.Replace(name, "\"", "", -1)
263 | path = strings.Replace(path, "\"", "", -1)
264 | abs := path
265 | if _, ok := v.boxes[name]; !ok {
266 | box := NewBox(name, path)
267 | box.Package = v.Package
268 |
269 | pd := filepath.Dir(v.File.Name())
270 | pwd, _ := os.Getwd()
271 | if !filepath.IsAbs(pd) {
272 | pd = filepath.Join(pwd, pd)
273 | }
274 | box.PackageDir = pd
275 |
276 | if !filepath.IsAbs(abs) {
277 | abs = filepath.Join(pd, abs)
278 | }
279 | box.AbsPath = abs
280 | v.boxes[name] = box
281 | }
282 | }
283 | func (v *Visitor) fromVariable(as *ast.AssignStmt) (string, error) {
284 | if len(as.Rhs) == 1 {
285 | if bs, ok := as.Rhs[0].(*ast.BasicLit); ok {
286 | return bs.Value, nil
287 | }
288 | }
289 | return "", fmt.Errorf("unable to find value from variable %v", as)
290 | }
291 |
292 | func (v *Visitor) addVariable(bn string, as *ast.AssignStmt) error {
293 | bv, err := v.fromVariable(as)
294 | if err != nil {
295 | return nil
296 | }
297 | if len(bn) == 0 {
298 | bn = bv
299 | }
300 | v.addBox(bn, bv)
301 | return nil
302 | }
303 |
304 | func (v *Visitor) fromConstant(vs *ast.ValueSpec) (string, error) {
305 | if len(vs.Values) == 1 {
306 | if bs, ok := vs.Values[0].(*ast.BasicLit); ok {
307 | return bs.Value, nil
308 | }
309 | }
310 | return "", fmt.Errorf("unable to find value from constant %v", vs)
311 | }
312 |
313 | func (v *Visitor) addConstant(bn string, vs *ast.ValueSpec) error {
314 | if len(vs.Values) == 1 {
315 | if bs, ok := vs.Values[0].(*ast.BasicLit); ok {
316 | bv := bs.Value
317 | if len(bn) == 0 {
318 | bn = bv
319 | }
320 | v.addBox(bn, bv)
321 | }
322 | }
323 | return nil
324 | }
325 |
--------------------------------------------------------------------------------
/jam/parser/visitor_test.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_Visitor(t *testing.T) {
11 | r := require.New(t)
12 | v := NewVisitor(NewFile("example/example.go", strings.NewReader(example)))
13 |
14 | boxes, err := v.Run()
15 | r.NoError(err)
16 |
17 | r.Equal("example", v.Package)
18 | r.Len(v.errors, 0)
19 |
20 | var act []string
21 | for _, b := range boxes {
22 | act = append(act, b.Name)
23 | }
24 |
25 | exp := []string{"./assets", "./bar", "./constant", "./foo", "./sf", "./templates", "./variable", "beatles"}
26 | r.Len(act, len(exp))
27 | r.Equal(exp, act)
28 | }
29 |
30 | const example = `package example
31 |
32 | import (
33 | "github.com/gobuffalo/packr/v2"
34 | )
35 |
36 | var a = packr.NewBox("./foo")
37 | var pw = packr.New("beatles", "./paperback-writer")
38 |
39 | const constString = "./constant"
40 |
41 | type S struct{}
42 |
43 | func (S) f(packr.Box) {}
44 |
45 | func init() {
46 | // packr.NewBox("../idontexists")
47 |
48 | b := "./variable"
49 | packr.NewBox(b)
50 |
51 | packr.New("beatles", "./day-tripper")
52 |
53 | packr.NewBox(constString)
54 |
55 | // Cannot work from a function
56 | packr.NewBox(strFromFunc())
57 |
58 | // This variable should not be added
59 | fromFunc := strFromFunc()
60 | packr.NewBox(fromFunc)
61 |
62 | foo("/templates", packr.NewBox("./templates"))
63 | packr.NewBox("./assets")
64 |
65 | packr.NewBox("./bar")
66 |
67 | s := S{}
68 | s.f(packr.NewBox("./sf"))
69 | }
70 |
71 | func strFromFunc() string {
72 | return "./fromFunc"
73 | }
74 |
75 | func foo(s string, box packr.Box) {}
76 | `
77 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/a/a.go:
--------------------------------------------------------------------------------
1 | package a
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("a-box", "../c")
7 | }
8 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/b/b.go:
--------------------------------------------------------------------------------
1 | package b
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("b-box", "../c")
7 | packr.New("cb-box", "../c")
8 | }
9 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/c/d.txt:
--------------------------------------------------------------------------------
1 | D
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/c/e.txt:
--------------------------------------------------------------------------------
1 | E
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/c/f.txt:
--------------------------------------------------------------------------------
1 | F
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/go.mod:
--------------------------------------------------------------------------------
1 | module foo
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/gobuffalo/packr/v2 v2.0.0-rc.2 // indirect
7 | golang.org/x/tools v0.0.0-20181116193547-e77c06808af6 // indirect
8 | )
9 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk-pack/go.sum:
--------------------------------------------------------------------------------
1 | errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
2 | errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
6 | github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
7 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
8 | github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
9 | github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
10 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
13 | github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
14 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
15 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
16 | github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
17 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
19 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
20 | github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY=
21 | github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4=
22 | github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs=
23 | github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4=
24 | github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY=
25 | github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w=
26 | github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI=
27 | github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI=
28 | github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk=
29 | github.com/gobuffalo/buffalo-plugins v1.6.9 h1:Z4WSEWPSxHMxrxVwCdy9x0QVZjirywhGpZaB9yeCwdc=
30 | github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw=
31 | github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8=
32 | github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc=
33 | github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
34 | github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
35 | github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
36 | github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
37 | github.com/gobuffalo/envy v1.6.9 h1:ShEJ/fUg/wr5qIYmTTOnUQ0sy1yGo+4uYQJNgg753S8=
38 | github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
39 | github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw=
40 | github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ=
41 | github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs=
42 | github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk=
43 | github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A=
44 | github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0=
45 | github.com/gobuffalo/events v1.1.7 h1:X+wjuT7c1rZNKqhfevIA30oFCgO5JBlnW6hvAJcv1Vg=
46 | github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY=
47 | github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc=
48 | github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
49 | github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
50 | github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
51 | github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
52 | github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
53 | github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
54 | github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
55 | github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328 h1:nvA0/snr4wQeCwBYmrbftniJun/kxOjK/Pz3ivb7wis=
56 | github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI=
57 | github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g=
58 | github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
59 | github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
60 | github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
61 | github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
62 | github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
63 | github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE=
64 | github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI=
65 | github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA=
66 | github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w=
67 | github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU=
68 | github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d h1:mznfLmbY1+EhkTIWhk19fZHuxoOLqZ/wzFUcKr5OGY8=
69 | github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng=
70 | github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I=
71 | github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY=
72 | github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI=
73 | github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E=
74 | github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w=
75 | github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw=
76 | github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0=
77 | github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo=
78 | github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
79 | github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
80 | github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17 h1:DnrA/oPJXI+mdlhX8LS8Gwj3uiTQhKOZCDAAcWSCYk0=
81 | github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew=
82 | github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw=
83 | github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
84 | github.com/gobuffalo/mapi v1.0.1 h1:JRuTiZzDEZhBHkFiHTxJkYRT6CbYuL0K/rn+1byJoEA=
85 | github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
86 | github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM=
87 | github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE=
88 | github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a h1:kROH1vRfBoxH1QIQjINB4qi4TmQTdg2Z/yzrKq1f2qM=
89 | github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg=
90 | github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0=
91 | github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No=
92 | github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo=
93 | github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ=
94 | github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4=
95 | github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME=
96 | github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c=
97 | github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
98 | github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
99 | github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
100 | github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
101 | github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
102 | github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
103 | github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7 h1:7AZMyDyRxIm2cbSXRvUEUJrankvMV1xcAOrrWUWp7yE=
104 | github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
105 | github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24=
106 | github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI=
107 | github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE=
108 | github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU=
109 | github.com/gobuffalo/packr v1.20.0 h1:XDHu3L931kHjr0v80vJ9hAxOMavbSpzuwAXDONsMYcM=
110 | github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw=
111 | github.com/gobuffalo/packr/v2 v2.0.0-rc.2 h1:22PapDc3YjlxFvfJ5ukc47/CwmwSQgZhma2wGf05eC8=
112 | github.com/gobuffalo/packr/v2 v2.0.0-rc.2/go.mod h1:4Xjr6aIxzyYQN6TBp/oJZ4L+X17DGfq3dy0DCidBebw=
113 | github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
114 | github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
115 | github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
116 | github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
117 | github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
118 | github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
119 | github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
120 | github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
121 | github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
122 | github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
123 | github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
124 | github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA=
125 | github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc=
126 | github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24=
127 | github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA=
128 | github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
129 | github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
130 | github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
131 | github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
132 | github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM=
133 | github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc=
134 | github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
135 | github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
136 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
137 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
138 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
139 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
140 | github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
141 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
142 | github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
143 | github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
144 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
145 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
146 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
147 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
148 | github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
149 | github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
150 | github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
151 | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
152 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
153 | github.com/karrick/godirwalk v1.7.5 h1:JQFiMR65pT543bkWP46+k194gS999qo/OYccos9cOXg=
154 | github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
155 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
156 | github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
157 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
158 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
159 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
160 | github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
161 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
162 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
163 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
164 | github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
165 | github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
166 | github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
167 | github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs=
168 | github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c=
169 | github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88=
170 | github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk=
171 | github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
172 | github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
173 | github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
174 | github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
175 | github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4 h1:Mlji5gkcpzkqTROyE4ZxZ8hN7osunMb2RuGVrbvMvCc=
176 | github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
177 | github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc=
178 | github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
179 | github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
180 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
181 | github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc=
182 | github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w=
183 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
184 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
185 | github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
186 | github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
187 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
188 | github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
189 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
190 | github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
191 | github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
192 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
193 | github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
194 | github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
195 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
196 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
197 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
198 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
199 | github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
200 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
201 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
202 | github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
203 | github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
204 | github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
205 | github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
206 | github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
207 | github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
208 | github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
209 | github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
210 | github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
211 | github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
212 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
213 | github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
214 | github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
215 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
216 | github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
217 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
218 | github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
219 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
220 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
221 | github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
222 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
223 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
224 | github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
225 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
226 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
227 | github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
228 | github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
229 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
230 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
231 | golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
232 | golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
233 | golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
234 | golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
235 | golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
236 | golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
237 | golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd h1:VtIkGDhk0ph3t+THbvXHfMZ8QHgsBO39Nh52+74pq7w=
238 | golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
239 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
240 | golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
241 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
242 | golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
243 | golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
244 | golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
245 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
246 | golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
247 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
248 | golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
249 | golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
250 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
251 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
252 | golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
253 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
254 | golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
255 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
256 | golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
257 | golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
258 | golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
259 | golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
260 | golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
261 | golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
262 | golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
263 | golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
264 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
265 | golang.org/x/sys v0.0.0-20181106135930-3a76605856fd h1:5lx5yH6109ClL0rlBzOj++ZkX/njUT+RVgTO2RMbmZo=
266 | golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
267 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
268 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
269 | golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
270 | golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
271 | golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
272 | golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
273 | golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
274 | golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
275 | golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
276 | golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
277 | golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
278 | golang.org/x/tools v0.0.0-20181115011154-2a3f5192be2e h1:C6Dd9cORPM5l1agULNKGE7TsHE1f4fKb6u/C03xjFxo=
279 | golang.org/x/tools v0.0.0-20181115011154-2a3f5192be2e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
280 | golang.org/x/tools v0.0.0-20181116193547-e77c06808af6 h1:eiQyQ1ZGSmM3I3XUf/clCROlBlOlmAUmTJ9l2GjX2GE=
281 | golang.org/x/tools v0.0.0-20181116193547-e77c06808af6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
282 | google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
283 | gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
284 | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
285 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
286 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
287 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
288 | gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
289 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
290 | gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
291 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
292 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
293 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/_r/r.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("bob", "dylan")
7 | }
8 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/e/e.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("tom", "./petty")
7 | packr.NewBox("../e/heartbreakers")
8 | }
9 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/e/heartbreakers/refugee.txt:
--------------------------------------------------------------------------------
1 | YOU DON'T HAVE TO BE A REFUGEE!
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/e/petty/fallin.txt:
--------------------------------------------------------------------------------
1 | FREE FALLIN!
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/franklin/aretha.txt:
--------------------------------------------------------------------------------
1 | RESPECT!
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/franklin/think.txt:
--------------------------------------------------------------------------------
1 | THINK!
2 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/q.go:
--------------------------------------------------------------------------------
1 | package q
2 |
3 | import "github.com/gobuffalo/packr/v2"
4 |
5 | func init() {
6 | packr.New("aretha", "./franklin")
7 | }
8 |
--------------------------------------------------------------------------------
/jam/store/_fixtures/disk/w/w.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | func main() {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/jam/store/clean.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "strings"
7 |
8 | "github.com/gobuffalo/packr/v2/jam/parser"
9 | )
10 |
11 | func Clean(root string) error {
12 | defer func() {
13 | packd := filepath.Join(root, "packrd")
14 | os.RemoveAll(packd)
15 | }()
16 |
17 | p, err := parser.NewFromRoots([]string{root}, &parser.RootsOptions{})
18 | if err != nil {
19 | return err
20 | }
21 |
22 | boxes, err := p.Run()
23 | if err != nil {
24 | return err
25 | }
26 |
27 | d := NewDisk("", "")
28 | for _, box := range boxes {
29 | if err := d.Clean(box); err != nil {
30 | return err
31 | }
32 | }
33 | return nil
34 | }
35 |
36 | func clean(root string) error {
37 | if len(root) == 0 {
38 | pwd, err := os.Getwd()
39 | if err != nil {
40 | return err
41 | }
42 | root = pwd
43 | }
44 | if _, err := os.Stat(root); err != nil {
45 | return nil
46 | }
47 | defer func() {
48 | packd := filepath.Join(root, "packrd")
49 | os.RemoveAll(packd)
50 | }()
51 |
52 | err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
53 | if err != nil {
54 | return err
55 | }
56 | if info.IsDir() {
57 | if filepath.Base(path) == "packrd" {
58 | os.RemoveAll(path)
59 | return filepath.SkipDir
60 | }
61 | }
62 | if strings.HasSuffix(path, "-packr.go") {
63 | err := os.RemoveAll(path)
64 | if err != nil {
65 | return err
66 | }
67 | }
68 | return nil
69 | })
70 | if err != nil {
71 | return err
72 | }
73 |
74 | return nil
75 | }
76 |
--------------------------------------------------------------------------------
/jam/store/disk.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "bytes"
5 | "compress/gzip"
6 | "crypto/md5"
7 | "fmt"
8 | "html/template"
9 | "io"
10 | "io/ioutil"
11 | "os"
12 | "os/exec"
13 | "path"
14 | "path/filepath"
15 | "sort"
16 | "strings"
17 | "sync"
18 |
19 | "github.com/karrick/godirwalk"
20 |
21 | "github.com/gobuffalo/packr/v2/file/resolver/encoding/hex"
22 | "github.com/gobuffalo/packr/v2/plog"
23 | "github.com/rogpeppe/go-internal/modfile"
24 |
25 | "github.com/gobuffalo/packr/v2/jam/parser"
26 | "golang.org/x/sync/errgroup"
27 | )
28 |
29 | var _ Store = &Disk{}
30 |
31 | const DISK_GLOBAL_KEY = "__packr_global__"
32 |
33 | type Disk struct {
34 | DBPath string
35 | DBPackage string
36 | global map[string]string
37 | boxes map[string]*parser.Box
38 | moot *sync.RWMutex
39 | }
40 |
41 | func NewDisk(path string, pkg string) *Disk {
42 | if len(path) == 0 {
43 | path = "packrd"
44 | }
45 | if len(pkg) == 0 {
46 | pkg = "packrd"
47 | }
48 | if !filepath.IsAbs(path) {
49 | path, _ = filepath.Abs(path)
50 | }
51 | return &Disk{
52 | DBPath: path,
53 | DBPackage: pkg,
54 | global: map[string]string{},
55 | boxes: map[string]*parser.Box{},
56 | moot: &sync.RWMutex{},
57 | }
58 | }
59 |
60 | func (d *Disk) FileNames(box *parser.Box) ([]string, error) {
61 | path := box.AbsPath
62 | if len(box.AbsPath) == 0 {
63 | path = box.Path
64 | }
65 | var names []string
66 | if _, err := os.Stat(path); err != nil {
67 | return names, nil
68 | }
69 | err := godirwalk.Walk(path, &godirwalk.Options{
70 | FollowSymbolicLinks: true,
71 | Callback: func(path string, de *godirwalk.Dirent) error {
72 | if !de.IsRegular() {
73 | return nil
74 | }
75 | names = append(names, path)
76 | return nil
77 | },
78 | })
79 | return names, err
80 | }
81 |
82 | func (d *Disk) Files(box *parser.Box) ([]*parser.File, error) {
83 | var files []*parser.File
84 | names, err := d.FileNames(box)
85 | if err != nil {
86 | return files, err
87 | }
88 | for _, n := range names {
89 | b, err := ioutil.ReadFile(n)
90 | if err != nil {
91 | return files, err
92 | }
93 | f := parser.NewFile(n, bytes.NewReader(b))
94 | files = append(files, f)
95 | }
96 | return files, nil
97 | }
98 |
99 | func (d *Disk) Pack(box *parser.Box) error {
100 | plog.Debug(d, "Pack", "box", box.Name)
101 | d.boxes[box.Name] = box
102 | names, err := d.FileNames(box)
103 | if err != nil {
104 | return err
105 | }
106 | for _, n := range names {
107 | _, ok := d.global[n]
108 | if ok {
109 | continue
110 | }
111 | k := makeKey(box, n)
112 | // not in the global, so add it!
113 | d.global[n] = k
114 | }
115 | return nil
116 | }
117 |
118 | func (d *Disk) Clean(box *parser.Box) error {
119 | root := box.PackageDir
120 | if len(root) == 0 {
121 | return fmt.Errorf("can't clean an empty box.PackageDir")
122 | }
123 | plog.Debug(d, "Clean", "box", box.Name, "root", root)
124 | return clean(root)
125 | }
126 |
127 | type options struct {
128 | Package string
129 | GlobalFiles map[string]string
130 | Boxes []optsBox
131 | GK string
132 | }
133 |
134 | type optsBox struct {
135 | Name string
136 | Path string
137 | }
138 |
139 | // Close ...
140 | func (d *Disk) Close() error {
141 | if len(d.boxes) == 0 {
142 | return nil
143 | }
144 |
145 | xb := &parser.Box{Name: DISK_GLOBAL_KEY}
146 | opts := options{
147 | Package: d.DBPackage,
148 | GlobalFiles: map[string]string{},
149 | GK: makeKey(xb, d.DBPath),
150 | }
151 |
152 | wg := errgroup.Group{}
153 | for k, v := range d.global {
154 | func(k, v string) {
155 | wg.Go(func() error {
156 | bb := &bytes.Buffer{}
157 | enc := hex.NewEncoder(bb)
158 | zw := gzip.NewWriter(enc)
159 | f, err := os.Open(k)
160 | if err != nil {
161 | return err
162 | }
163 | defer f.Close()
164 | io.Copy(zw, f)
165 | if err := zw.Close(); err != nil {
166 | return err
167 | }
168 | d.moot.Lock()
169 | opts.GlobalFiles[makeKey(xb, k)] = bb.String()
170 | d.moot.Unlock()
171 | return nil
172 | })
173 | }(k, v)
174 | }
175 |
176 | if err := wg.Wait(); err != nil {
177 | return err
178 | }
179 |
180 | for _, b := range d.boxes {
181 | ob := optsBox{
182 | Name: b.Name,
183 | }
184 | opts.Boxes = append(opts.Boxes, ob)
185 | }
186 |
187 | sort.Slice(opts.Boxes, func(a, b int) bool {
188 | return opts.Boxes[a].Name < opts.Boxes[b].Name
189 | })
190 |
191 | fm := template.FuncMap{
192 | "printBox": func(ob optsBox) (template.HTML, error) {
193 | box := d.boxes[ob.Name]
194 | if box == nil {
195 | return "", fmt.Errorf("could not find box %s", ob.Name)
196 | }
197 | fn, err := d.FileNames(box)
198 | if err != nil {
199 | return "", err
200 | }
201 | if len(fn) == 0 {
202 | return "", nil
203 | }
204 |
205 | type file struct {
206 | Resolver string
207 | ForwardPath string
208 | }
209 |
210 | tmpl, err := template.New("box.go").Parse(diskGlobalBoxTmpl)
211 | if err != nil {
212 | return "", err
213 | }
214 |
215 | var files []file
216 | for _, s := range fn {
217 | p := strings.TrimPrefix(s, box.AbsPath)
218 | p = strings.TrimPrefix(p, string(filepath.Separator))
219 | files = append(files, file{
220 | Resolver: strings.Replace(p, "\\", "/", -1),
221 | ForwardPath: makeKey(box, s),
222 | })
223 | }
224 | opts := map[string]interface{}{
225 | "Box": box,
226 | "Files": files,
227 | }
228 |
229 | bb := &bytes.Buffer{}
230 | if err := tmpl.Execute(bb, opts); err != nil {
231 | return "", err
232 | }
233 | return template.HTML(bb.String()), nil
234 | },
235 | }
236 |
237 | os.MkdirAll(d.DBPath, 0755)
238 | fp := filepath.Join(d.DBPath, "packed-packr.go")
239 | global, err := os.Create(fp)
240 | if err != nil {
241 | return err
242 | }
243 | defer global.Close()
244 |
245 | tmpl := template.New(fp).Funcs(fm)
246 | tmpl, err = tmpl.Parse(diskGlobalTmpl)
247 | if err != nil {
248 | return err
249 | }
250 |
251 | if err := tmpl.Execute(global, opts); err != nil {
252 | return err
253 | }
254 |
255 | var ip string
256 | // Starting in 1.12, we can rely on Go's method for
257 | // resolving where go.mod resides. Prior versions will
258 | // simply return an empty string.
259 | cmd := exec.Command("go", "env", "GOMOD")
260 | out, err := cmd.Output()
261 | if err != nil {
262 | return fmt.Errorf("go.mod cannot be read or does not exist while go module is enabled")
263 | }
264 | mp := strings.TrimSpace(string(out))
265 | if mp == "" {
266 | // We are on a prior version of Go; try and do
267 | // the resolution ourselves.
268 | mp = filepath.Join(filepath.Dir(d.DBPath), "go.mod")
269 | if _, err := os.Stat(mp); err != nil {
270 | mp = filepath.Join(d.DBPath, "go.mod")
271 | }
272 | }
273 |
274 | moddata, err := ioutil.ReadFile(mp)
275 | if err != nil {
276 | return fmt.Errorf("go.mod cannot be read or does not exist while go module is enabled")
277 | }
278 | ip = modfile.ModulePath(moddata)
279 | if ip == "" {
280 | return fmt.Errorf("go.mod is malformed")
281 | }
282 | ip = filepath.Join(ip, strings.TrimPrefix(filepath.Dir(d.DBPath), filepath.Dir(mp)))
283 | ip = strings.Replace(ip, "\\", "/", -1)
284 | ip = path.Join(ip, d.DBPackage)
285 |
286 | for _, n := range opts.Boxes {
287 | b := d.boxes[n.Name]
288 | if b == nil {
289 | continue
290 | }
291 | p := filepath.Join(b.PackageDir, b.Package+"-packr.go")
292 | f, err := os.Create(p)
293 | if err != nil {
294 | return err
295 | }
296 | defer f.Close()
297 |
298 | o := struct {
299 | Package string
300 | Import string
301 | }{
302 | Package: b.Package,
303 | Import: ip,
304 | }
305 |
306 | tmpl, err := template.New(p).Parse(diskImportTmpl)
307 | if err != nil {
308 | return err
309 | }
310 | if err := tmpl.Execute(f, o); err != nil {
311 | return err
312 | }
313 |
314 | }
315 |
316 | return nil
317 | }
318 |
319 | // resolve file paths (only) for the boxes
320 | // compile "global" db
321 | // resolve files for boxes to point at global db
322 | // write global db to disk (default internal/packr)
323 | // write boxes db to disk (default internal/packr)
324 | // write -packr.go files in each package (1 per package) that init the global db
325 |
326 | func makeKey(box *parser.Box, path string) string {
327 | w := md5.New()
328 | fmt.Fprint(w, path)
329 | h := hex.EncodeToString(w.Sum(nil))
330 | return h
331 | }
332 |
--------------------------------------------------------------------------------
/jam/store/disk_packed_test.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "github.com/gobuffalo/packr/v2"
5 | "github.com/gobuffalo/packr/v2/file/resolver"
6 | )
7 |
8 | var _ = func() error {
9 | const gk = DISK_GLOBAL_KEY
10 | g := packr.New(gk, "")
11 |
12 | hgr, err := resolver.NewHexGzip(map[string]string{
13 | "4abf3a9b652ecec6b347eb6acb7ce363": "1f8b08000000000000fff2750c72775508cecc2d28cecfe302040000fffffb1d273b0e000000",
14 | "5cfc8f95f98237a10affc14a76e3e20b": "1f8b08000000000000fff2757477f7745508cecc2d28cecfe302040000ffffb09167470f000000",
15 | "6d8be986fa35821e7e869fbb118e51ba": "1f8b08000000000000fff2f0f7750d5208cecc2d28cecfe302040000fffffb2ef0a60e000000",
16 | "99e5497ae5f5988fafafbcd15ed74d22": "1f8b08000000000000fff2f10c765408cecc2d28cecfe302040000ffffab9bc93e0d000000",
17 | "bb006aa6261a80f6c52c640f713659c1": "1f8b08000000000000ff72720c0a5108cecc2d28cecfe302040000ffff89742ac20d000000",
18 | })
19 | if err != nil {
20 | return err
21 | }
22 | g.DefaultResolver = hgr
23 | func() {
24 | b := packr.New("simpsons", "")
25 | b.SetResolver("kids/bart.txt", packr.Pointer{ForwardBox: gk, ForwardPath: "bb006aa6261a80f6c52c640f713659c1"})
26 | b.SetResolver("kids/lisa.txt", packr.Pointer{ForwardBox: gk, ForwardPath: "99e5497ae5f5988fafafbcd15ed74d22"})
27 | b.SetResolver("kids/maggie.txt", packr.Pointer{ForwardBox: gk, ForwardPath: "5cfc8f95f98237a10affc14a76e3e20b"})
28 | b.SetResolver("parents/homer.txt", packr.Pointer{ForwardBox: gk, ForwardPath: "6d8be986fa35821e7e869fbb118e51ba"})
29 | b.SetResolver("parents/marge.txt", packr.Pointer{ForwardBox: gk, ForwardPath: "4abf3a9b652ecec6b347eb6acb7ce363"})
30 | }()
31 | return nil
32 | }()
33 |
--------------------------------------------------------------------------------
/jam/store/disk_test.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | //
4 | // import (
5 | // "path/filepath"
6 | // "strings"
7 | // "testing"
8 | //
9 | // "github.com/gobuffalo/envy"
10 | // "github.com/gobuffalo/genny/gentest"
11 | // "github.com/gobuffalo/gogen/gomods"
12 | // "github.com/gobuffalo/packr/v2"
13 | // "github.com/gobuffalo/packr/v2/jam/parser"
14 | // "github.com/markbates/oncer"
15 | // "github.com/stretchr/testify/require"
16 | // )
17 | //
18 | // func init() {
19 | // parser.DefaultIgnoredFolders = []string{"vendor", ".git", "node_modules", ".idea"}
20 | // }
21 | //
22 | // func Test_Disk_Generator(t *testing.T) {
23 | // gomods.Disable(func() error {
24 | //
25 | // r := require.New(t)
26 | //
27 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk-pack"}, &parser.RootsOptions{
28 | // IgnoreImports: true,
29 | // })
30 | // r.NoError(err)
31 | //
32 | // boxes, err := p.Run()
33 | // r.NoError(err)
34 | //
35 | // d := NewDisk(".", "")
36 | // for _, b := range boxes {
37 | // r.NoError(d.Pack(b))
38 | // }
39 | //
40 | // r.NoError(d.Close())
41 | //
42 | // res := run.Results()
43 | // r.Len(res.Files, 3)
44 | //
45 | // f := res.Files[0]
46 | // r.Equal("a-packr.go", filepath.Base(f.Name()))
47 | // r.Contains(f.String(), `import _ "github.com/gobuffalo/packr/v2/jam/packrd"`)
48 | // return nil
49 | // })
50 | // }
51 | //
52 | // func Test_Disk_Generator_GoMod(t *testing.T) {
53 | // oe := envy.Get(gomods.ENV, "off")
54 | // _ = envy.MustSet(gomods.ENV, "on")
55 | // defer envy.MustSet(gomods.ENV, oe)
56 | //
57 | // r := require.New(t)
58 | //
59 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk-pack"}, &parser.RootsOptions{
60 | // IgnoreImports: true,
61 | // })
62 | // r.NoError(err)
63 | //
64 | // boxes, err := p.Run()
65 | // r.NoError(err)
66 | //
67 | // d := NewDisk(".", "")
68 | // for _, b := range boxes {
69 | // r.NoError(d.Pack(b))
70 | // }
71 | //
72 | // run := gentest.NewRunner()
73 | // run.WithNew(d.Generator())
74 | // r.NoError(run.Run())
75 | //
76 | // res := run.Results()
77 | // r.Len(res.Files, 3)
78 | //
79 | // f := res.Files[0]
80 | // r.Equal("a-packr.go", filepath.Base(f.Name()))
81 | // r.Contains(f.String(), `import _ "github.com/gobuffalo/packr/v2/jam/packrd"`)
82 | // }
83 | //
84 | // func Test_Disk_FileNames(t *testing.T) {
85 | // r := require.New(t)
86 | //
87 | // d := &Disk{}
88 | //
89 | // box := parser.NewBox("Test_Disk_FileNames", "./_fixtures/disk/franklin")
90 | // names, err := d.FileNames(box)
91 | // r.NoError(err)
92 | // r.Len(names, 2)
93 | //
94 | // r.Equal("aretha.txt", filepath.Base(names[0]))
95 | // r.Equal("think.txt", filepath.Base(names[1]))
96 | // }
97 | //
98 | // func Test_Disk_Files(t *testing.T) {
99 | // r := require.New(t)
100 | //
101 | // d := &Disk{}
102 | //
103 | // box := parser.NewBox("Test_Disk_Files", "./_fixtures/disk/franklin")
104 | // files, err := d.Files(box)
105 | // r.NoError(err)
106 | // r.Len(files, 2)
107 | //
108 | // f := files[0]
109 | // r.Equal("aretha.txt", filepath.Base(f.Name()))
110 | // r.Equal("RESPECT!", strings.TrimSpace(f.String()))
111 | //
112 | // f = files[1]
113 | // r.Equal("think.txt", filepath.Base(f.Name()))
114 | // r.Equal("THINK!", strings.TrimSpace(f.String()))
115 | // }
116 | //
117 | // func Test_Disk_Pack(t *testing.T) {
118 | // oncer.Reset()
119 | // r := require.New(t)
120 | //
121 | // d := NewDisk("", "")
122 | //
123 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk-pack"}, &parser.RootsOptions{
124 | // IgnoreImports: true,
125 | // })
126 | // r.NoError(err)
127 | // boxes, err := p.Run()
128 | // r.NoError(err)
129 | //
130 | // for _, b := range boxes {
131 | // r.NoError(d.Pack(b))
132 | // }
133 | //
134 | // global := d.global
135 | // r.Len(global, 3)
136 | //
137 | // r.Len(d.boxes, 3)
138 | //
139 | // }
140 | //
141 | // func Test_Disk_Packed_Test(t *testing.T) {
142 | // r := require.New(t)
143 | //
144 | // b := packr.NewBox("simpsons")
145 | //
146 | // s, err := b.FindString("parents/homer.txt")
147 | // r.NoError(err)
148 | // r.Equal("HOMER Simpson", strings.TrimSpace(s))
149 | //
150 | // s, err = b.FindString("parents/marge.txt")
151 | // r.NoError(err)
152 | // r.Equal("MARGE Simpson", strings.TrimSpace(s))
153 | //
154 | // _, err = b.FindString("idontexist")
155 | // r.Error(err)
156 | // }
157 | //
158 | // func Test_Disk_Close(t *testing.T) {
159 | // gomods.Disable(func() error {
160 | // r := require.New(t)
161 | //
162 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk-pack"}, nil)
163 | // r.NoError(err)
164 | // boxes, err := p.Run()
165 | // r.NoError(err)
166 | //
167 | // d := NewDisk("./_fixtures/disk-pack", "")
168 | // for _, b := range boxes {
169 | // r.NoError(d.Pack(b))
170 | // }
171 | // r.NoError(d.Close())
172 | // return nil
173 | // })
174 | // }
175 | //
176 | // func Test_Disk_Generator_NoFiles(t *testing.T) {
177 | // gomods.Disable(func() error {
178 | //
179 | // r := require.New(t)
180 | //
181 | // d := NewDisk(".", "")
182 | // r.Len(d.boxes, 0)
183 | //
184 | // run := gentest.NewRunner()
185 | // run.WithNew(d.Generator())
186 | // r.NoError(run.Run())
187 | //
188 | // res := run.Results()
189 | // r.Len(res.Files, 0)
190 | //
191 | // return nil
192 | // })
193 | // }
194 |
--------------------------------------------------------------------------------
/jam/store/disk_tmpl.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | const diskGlobalTmpl = `// +build !skippackr
4 | // Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
5 |
6 | // You can use the "packr2 clean" command to clean up this,
7 | // and any other packr generated files.
8 | package {{.Package}}
9 |
10 | import (
11 | "github.com/gobuffalo/packr/v2"
12 | "github.com/gobuffalo/packr/v2/file/resolver"
13 | )
14 |
15 | var _ = func() error {
16 | const gk = "{{.GK}}"
17 | g := packr.New(gk, "")
18 | hgr, err := resolver.NewHexGzip(map[string]string{
19 | {{- range $k, $v := .GlobalFiles }}
20 | "{{$k}}": "{{$v}}",
21 | {{- end }}
22 | })
23 | if err != nil {
24 | panic(err)
25 | }
26 | g.DefaultResolver = hgr
27 |
28 | {{- range $box := .Boxes}}
29 | {{ printBox $box -}}
30 | {{ end }}
31 | return nil
32 | }()
33 | `
34 |
35 | const diskImportTmpl = `// +build !skippackr
36 | // Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
37 |
38 | // You can use the "packr clean" command to clean up this,
39 | // and any other packr generated files.
40 | package {{.Package}}
41 |
42 | import _ "{{.Import}}"
43 | `
44 |
45 | const diskGlobalBoxTmpl = `
46 | func() {
47 | b := packr.New("{{.Box.Name}}", "{{.Box.Path}}")
48 | {{- range $file := .Files }}
49 | b.SetResolver("{{$file.Resolver}}", packr.Pointer{ForwardBox: gk, ForwardPath: "{{$file.ForwardPath}}"})
50 | {{- end }}
51 | }()`
52 |
--------------------------------------------------------------------------------
/jam/store/env.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "os"
5 | "os/exec"
6 | "path/filepath"
7 | "strings"
8 | "sync"
9 | )
10 |
11 | var goPath = filepath.Join(os.Getenv("HOME"), "go")
12 |
13 | func init() {
14 | var once sync.Once
15 | once.Do(func() {
16 | cmd := exec.Command("go", "env", "GOPATH")
17 | b, err := cmd.CombinedOutput()
18 | if err != nil {
19 | return
20 | }
21 | goPath = strings.TrimSpace(string(b))
22 | })
23 | }
24 |
25 | // GoPath returns the current GOPATH env var
26 | // or if it's missing, the default.
27 | func GoPath() string {
28 | return goPath
29 | }
30 |
31 | // GoBin returns the current GO_BIN env var
32 | // or if it's missing, a default of "go"
33 | func GoBin() string {
34 | go_bin := os.Getenv("GO_BIN")
35 | if go_bin == "" {
36 | return "go"
37 | }
38 | return go_bin
39 | }
40 |
--------------------------------------------------------------------------------
/jam/store/fn.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gobuffalo/packr/v2/jam/parser"
7 | )
8 |
9 | var _ Store = &FnStore{}
10 |
11 | type FnStore struct {
12 | FileNamesFn func(*parser.Box) ([]string, error)
13 | FilesFn func(*parser.Box) ([]*parser.File, error)
14 | PackFn func(*parser.Box) error
15 | CleanFn func(*parser.Box) error
16 | }
17 |
18 | func (f *FnStore) FileNames(box *parser.Box) ([]string, error) {
19 | if f.FileNamesFn == nil {
20 | return []string{}, fmt.Errorf("FileNames not implemented")
21 | }
22 | return f.FileNames(box)
23 | }
24 |
25 | func (f *FnStore) Files(box *parser.Box) ([]*parser.File, error) {
26 | if f.FilesFn == nil {
27 | return []*parser.File{}, fmt.Errorf("Files not implemented")
28 | }
29 | return f.FilesFn(box)
30 | }
31 |
32 | func (f *FnStore) Pack(box *parser.Box) error {
33 | if f.PackFn == nil {
34 | return fmt.Errorf("Pack not implemented")
35 | }
36 | return f.PackFn(box)
37 | }
38 |
39 | func (f *FnStore) Clean(box *parser.Box) error {
40 | if f.CleanFn == nil {
41 | return fmt.Errorf("Clean not implemented")
42 | }
43 | return f.Clean(box)
44 | }
45 |
--------------------------------------------------------------------------------
/jam/store/legacy.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "html/template"
7 | "io"
8 | "os"
9 | "path/filepath"
10 | "sort"
11 | "strings"
12 |
13 | "github.com/gobuffalo/packr/v2/jam/parser"
14 | )
15 |
16 | var _ Store = &Legacy{}
17 |
18 | type Legacy struct {
19 | *Disk
20 | boxes map[string][]legacyBox
21 | }
22 |
23 | func NewLegacy() *Legacy {
24 | return &Legacy{
25 | Disk: NewDisk("", ""),
26 | boxes: map[string][]legacyBox{},
27 | }
28 | }
29 |
30 | func (l *Legacy) Pack(box *parser.Box) error {
31 | files, err := l.Files(box)
32 | if err != nil {
33 | return err
34 | }
35 |
36 | var fcs []legacyFile
37 |
38 | for _, f := range files {
39 | n := strings.TrimPrefix(f.Name(), box.AbsPath+string(filepath.Separator))
40 | c, err := l.prepFile(f)
41 | if err != nil {
42 | return err
43 | }
44 | fcs = append(fcs, legacyFile{Name: n, Contents: c})
45 | }
46 |
47 | sort.Slice(fcs, func(a, b int) bool {
48 | return fcs[a].Name < fcs[b].Name
49 | })
50 |
51 | lbs := l.boxes[box.PackageDir]
52 | lbs = append(lbs, legacyBox{
53 | Box: box,
54 | Files: fcs,
55 | })
56 | l.boxes[box.PackageDir] = lbs
57 | return nil
58 | }
59 |
60 | func (l *Legacy) prepFile(r io.Reader) (string, error) {
61 | bb := &bytes.Buffer{}
62 | if _, err := io.Copy(bb, r); err != nil {
63 | return "", err
64 | }
65 | b, err := json.Marshal(bb.Bytes())
66 | if err != nil {
67 | return "", err
68 | }
69 | return strings.Replace(string(b), "\"", "\\\"", -1), nil
70 | }
71 |
72 | // Close ...
73 | func (l *Legacy) Close() error {
74 | for _, b := range l.boxes {
75 | if len(b) == 0 {
76 | continue
77 | }
78 | bx := b[0].Box
79 | pkg := bx.Package
80 | opts := map[string]interface{}{
81 | "Package": pkg,
82 | "Boxes": b,
83 | }
84 | p := filepath.Join(bx.PackageDir, "a_"+bx.Package+"-packr.go.tmpl")
85 | tmpl, err := template.New(p).Parse(legacyTmpl)
86 |
87 | if err != nil {
88 | return err
89 | }
90 |
91 | f, err := os.Create(p)
92 | if err != nil {
93 | return err
94 | }
95 |
96 | if err := tmpl.Execute(f, opts); err != nil {
97 | return err
98 | }
99 |
100 | }
101 | return nil
102 | }
103 |
104 | type legacyBox struct {
105 | Box *parser.Box
106 | Files []legacyFile
107 | }
108 |
109 | type legacyFile struct {
110 | Name string
111 | Contents string
112 | }
113 |
114 | var legacyTmpl = `// Code generated by github.com/gobuffalo/packr. DO NOT EDIT.
115 |
116 | package {{.Package}}
117 |
118 | import "github.com/gobuffalo/packr"
119 |
120 | // You can use the "packr clean" command to clean up this,
121 | // and any other packr generated files.
122 | func init() {
123 | {{- range $box := .Boxes }}
124 | {{- range $box.Files }}
125 | _ = packr.PackJSONBytes("{{$box.Box.Name}}", "{{.Name}}", "{{.Contents}}")
126 | {{- end }}
127 | {{- end }}
128 | }
129 | `
130 |
--------------------------------------------------------------------------------
/jam/store/legacy_test.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | // func Test_Legacy_Pack(t *testing.T) {
4 | // r := require.New(t)
5 | //
6 | // d := NewLegacy()
7 | //
8 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk"}, &parser.RootsOptions{
9 | // IgnoreImports: true,
10 | // })
11 | // r.NoError(err)
12 | // boxes, err := p.Run()
13 | // r.NoError(err)
14 | //
15 | // for _, b := range boxes {
16 | // r.NoError(d.Pack(b))
17 | // }
18 | //
19 | // db := d.boxes
20 | // r.Len(db, 2)
21 | // for k, v := range db {
22 | // switch filepath.Base(k) {
23 | // case "disk":
24 | // r.Len(v, 1)
25 | // case "e":
26 | // r.Len(v, 2)
27 | // default:
28 | // r.Fail(k)
29 | // }
30 | // }
31 | // }
32 | //
33 | // func Test_Legacy_Close(t *testing.T) {
34 | // oncer.Reset()
35 | // r := require.New(t)
36 | //
37 | // d := NewLegacy()
38 | //
39 | // p, err := parser.NewFromRoots([]string{"./_fixtures/disk"}, &parser.RootsOptions{
40 | // IgnoreImports: true,
41 | // })
42 | // r.NoError(err)
43 | // boxes, err := p.Run()
44 | // r.NoError(err)
45 | //
46 | // for _, b := range boxes {
47 | // r.NoError(d.Pack(b))
48 | // }
49 | // r.Len(d.boxes, 2)
50 | //
51 | // run := gentest.NewRunner()
52 | // r.NoError(run.WithNew(d.Generator()))
53 | // r.NoError(run.Run())
54 | //
55 | // res := run.Results()
56 | // r.Len(res.Files, 2)
57 | // }
58 |
--------------------------------------------------------------------------------
/jam/store/store.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "github.com/gobuffalo/packr/v2/jam/parser"
5 | )
6 |
7 | type Store interface {
8 | FileNames(*parser.Box) ([]string, error)
9 | Files(*parser.Box) ([]*parser.File, error)
10 | Pack(*parser.Box) error
11 | Clean(*parser.Box) error
12 | }
13 |
--------------------------------------------------------------------------------
/jam/store/store_test.go:
--------------------------------------------------------------------------------
1 | package store
2 |
--------------------------------------------------------------------------------
/packr.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gobuffalo/packr/v2/file/resolver"
7 | "github.com/gobuffalo/packr/v2/jam/parser"
8 | "github.com/gobuffalo/packr/v2/plog"
9 | "github.com/markbates/safe"
10 | )
11 |
12 | var boxes = &boxMap{}
13 |
14 | var _ = safe.Run(func() {
15 | p, err := parser.NewFromRoots([]string{}, nil)
16 | if err != nil {
17 | plog.Logger.Error(err)
18 | return
19 | }
20 | boxes, err := p.Run()
21 | if err != nil {
22 | plog.Logger.Error(err)
23 | return
24 | }
25 | for _, box := range boxes {
26 | b := construct(box.Name, box.AbsPath)
27 | _, err = placeBox(b)
28 | if err != nil {
29 | plog.Logger.Error(err)
30 | return
31 | }
32 | }
33 |
34 | })
35 |
36 | func findBox(name string) (*Box, error) {
37 | key := resolver.Key(name)
38 | plog.Debug("packr", "findBox", "name", name, "key", key)
39 |
40 | b, ok := boxes.Load(key)
41 | if !ok {
42 | plog.Debug("packr", "findBox", "name", name, "key", key, "found", ok)
43 | return nil, fmt.Errorf("could not find box %s", name)
44 | }
45 |
46 | plog.Debug(b, "found", "box", b)
47 | return b, nil
48 | }
49 |
50 | func placeBox(b *Box) (*Box, error) {
51 | key := resolver.Key(b.Name)
52 | eb, _ := boxes.LoadOrStore(key, b)
53 |
54 | plog.Debug("packr", "placeBox", "name", eb.Name, "path", eb.Path, "resolution directory", eb.ResolutionDir)
55 | return eb, nil
56 | }
57 |
--------------------------------------------------------------------------------
/packr2/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2018 Mark Bates
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packr2/cmd/build.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gobuffalo/packr/v2/jam"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | var buildCmd = &cobra.Command{
11 | Use: "build",
12 | Short: "Wraps the go build command with packr",
13 | DisableFlagParsing: true,
14 | RunE: func(cmd *cobra.Command, args []string) error {
15 | cargs := parseArgs(args)
16 | if globalOptions.Verbose {
17 | fmt.Println(dont)
18 | }
19 | if err := jam.Pack(globalOptions.PackOptions); err != nil {
20 | return err
21 | }
22 | return goCmd("build", cargs...)
23 | },
24 | }
25 |
26 | func init() {
27 | rootCmd.AddCommand(buildCmd)
28 | }
29 |
--------------------------------------------------------------------------------
/packr2/cmd/clean.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/gobuffalo/packr/v2/jam"
5 | "github.com/spf13/cobra"
6 | )
7 |
8 | var cleanCmd = &cobra.Command{
9 | Use: "clean",
10 | Short: "removes any *-packr.go files",
11 | RunE: func(cmd *cobra.Command, args []string) error {
12 | return jam.Clean(args...)
13 | },
14 | }
15 |
16 | func init() {
17 | rootCmd.AddCommand(cleanCmd)
18 | }
19 |
--------------------------------------------------------------------------------
/packr2/cmd/fix.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | packr "github.com/gobuffalo/packr/v2"
7 | "github.com/gobuffalo/packr/v2/packr2/cmd/fix"
8 | "github.com/spf13/cobra"
9 | )
10 |
11 | // fixCmd represents the info command
12 | var fixCmd = &cobra.Command{
13 | Use: "fix",
14 | Short: fmt.Sprintf("will attempt to fix a application's API to match packr version %s", packr.Version),
15 | RunE: func(cmd *cobra.Command, args []string) error {
16 | return fix.Run()
17 | },
18 | }
19 |
20 | func init() {
21 | fixCmd.Flags().BoolVarP(&fix.YesToAll, "y", "", false, "update all without asking for confirmation")
22 | rootCmd.AddCommand(fixCmd)
23 | }
24 |
--------------------------------------------------------------------------------
/packr2/cmd/fix/fix.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | "strings"
8 |
9 | "github.com/gobuffalo/packr/v2/jam/store"
10 | )
11 |
12 | //YesToAll will be used by the command to skip the questions
13 | var YesToAll bool
14 |
15 | var replace = map[string]string{
16 | "github.com/gobuffalo/packr": "github.com/gobuffalo/packr/v2",
17 | }
18 |
19 | var ic = ImportConverter{
20 | Data: replace,
21 | }
22 |
23 | var checks = []Check{
24 | // packrClean,
25 | ic.Process,
26 | }
27 |
28 | func packrClean(r *Runner) error {
29 | pwd, err := os.Getwd()
30 | if err != nil {
31 | return err
32 | }
33 | store.Clean(pwd)
34 | return nil
35 | }
36 |
37 | func ask(q string) bool {
38 | if YesToAll {
39 | return true
40 | }
41 |
42 | fmt.Printf("? %s [y/n]\n", q)
43 |
44 | reader := bufio.NewReader(os.Stdin)
45 | text, _ := reader.ReadString('\n')
46 |
47 | text = strings.ToLower(strings.TrimSpace(text))
48 | return text == "y" || text == "yes"
49 | }
50 |
--------------------------------------------------------------------------------
/packr2/cmd/fix/imports.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "go/ast"
7 | "go/parser"
8 | "go/printer"
9 | "go/token"
10 | "io/ioutil"
11 | "os"
12 | "path/filepath"
13 | "strconv"
14 | "strings"
15 |
16 | "golang.org/x/tools/go/ast/astutil"
17 | )
18 |
19 | // ImportConverter will changes imports from a -> b
20 | type ImportConverter struct {
21 | Data map[string]string
22 | }
23 |
24 | // Process will walk all the .go files in an application, excluding ./vendor.
25 | // It will then attempt to convert any old import paths to any new import paths
26 | // used by this version Buffalo.
27 | func (c ImportConverter) Process(r *Runner) error {
28 | fmt.Println("~~~ Rewriting Imports ~~~")
29 |
30 | err := filepath.Walk(".", c.processFile)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | if _, err := os.Stat("Gopkg.toml"); err != nil {
36 | return nil
37 | }
38 |
39 | b, err := ioutil.ReadFile("Gopkg.toml")
40 | if err != nil {
41 | return err
42 | }
43 |
44 | for k := range c.Data {
45 | if bytes.Contains(b, []byte(k)) {
46 | r.Warnings = append(r.Warnings, fmt.Sprintf("Your Gopkg.toml contains the following import that need to be changed MANUALLY: %s", k))
47 | }
48 | }
49 |
50 | return nil
51 | }
52 |
53 | func (c ImportConverter) processFile(p string, info os.FileInfo, err error) error {
54 | er := onlyRelevantFiles(p, info, err, func(p string) error {
55 | err := c.rewriteFile(p)
56 | if err != nil {
57 | err = err
58 | }
59 |
60 | return err
61 | })
62 |
63 | return er
64 | }
65 |
66 | func (c ImportConverter) rewriteFile(name string) error {
67 | // create an empty fileset.
68 | fset := token.NewFileSet()
69 |
70 | // parse the .go file.
71 | // we are parsing the entire file with comments, so we don't lose anything
72 | // if we need to write it back out.
73 | f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
74 | if err != nil {
75 | e := err.Error()
76 | msg := "expected 'package', found 'EOF'"
77 | if e[len(e)-len(msg):] == msg {
78 | return nil
79 | }
80 | return err
81 | }
82 |
83 | changed := false
84 | funcs := []*ast.FuncDecl{}
85 | for _, d := range f.Decls {
86 | if fn, isFn := d.(*ast.FuncDecl); isFn {
87 | funcs = append(funcs, fn)
88 | }
89 | }
90 |
91 | for _, fun := range funcs {
92 | ast.Inspect(fun, func(node ast.Node) bool {
93 | switch n := node.(type) {
94 | case *ast.CallExpr:
95 | fn, ok := n.Fun.(*ast.SelectorExpr)
96 | if !ok || fn.Sel == nil {
97 | return true
98 | }
99 |
100 | sel := fn.Sel
101 | i, ok := fn.X.(*ast.Ident)
102 | if !ok {
103 | return true
104 | }
105 | if i.Name != "packr" {
106 | return true
107 | }
108 | if sel.Name == "NewBox" {
109 | sel.Name = "New"
110 | n.Args = append(n.Args, n.Args[0])
111 | changed = true
112 | }
113 | if sel.Name == "MustBytes" {
114 | sel.Name = "Find"
115 | changed = true
116 | }
117 | if sel.Name == "MustBytes" {
118 | sel.Name = "Find"
119 | changed = true
120 | }
121 | }
122 | return true
123 | })
124 | }
125 |
126 | for key, value := range c.Data {
127 | if !astutil.DeleteImport(fset, f, key) {
128 | continue
129 | }
130 |
131 | astutil.AddImport(fset, f, value)
132 | changed = true
133 | }
134 |
135 | commentsChanged, err := c.handleFileComments(f)
136 | if err != nil {
137 | return err
138 | }
139 |
140 | changed = changed || commentsChanged
141 |
142 | // if no change occurred, then we don't need to write to disk, just return.
143 | if !changed {
144 | return nil
145 | }
146 |
147 | // since the imports changed, resort them.
148 | ast.SortImports(fset, f)
149 |
150 | // create a temporary file, this easily avoids conflicts.
151 | temp, err := writeTempResult(name, fset, f)
152 | if err != nil {
153 | return err
154 | }
155 |
156 | // rename the .temp to .go
157 | return os.Rename(temp, name)
158 | }
159 |
160 | func (c ImportConverter) handleFileComments(f *ast.File) (bool, error) {
161 | change := false
162 |
163 | for _, cg := range f.Comments {
164 | for _, cl := range cg.List {
165 | if !strings.HasPrefix(cl.Text, "// import \"") {
166 | continue
167 | }
168 |
169 | // trim off extra comment stuff
170 | ctext := cl.Text
171 | ctext = strings.TrimPrefix(ctext, "// import")
172 | ctext = strings.TrimSpace(ctext)
173 |
174 | // unquote the comment import path value
175 | ctext, err := strconv.Unquote(ctext)
176 | if err != nil {
177 | return false, err
178 | }
179 |
180 | // match the comment import path with the given replacement map
181 | if ctext, ok := c.match(ctext); ok {
182 | cl.Text = "// import " + strconv.Quote(ctext)
183 | change = true
184 | }
185 |
186 | }
187 | }
188 |
189 | return change, nil
190 | }
191 |
192 | // match takes an import path and replacement map.
193 | func (c ImportConverter) match(importpath string) (string, bool) {
194 | for key, value := range c.Data {
195 | if !strings.HasPrefix(importpath, key) {
196 | continue
197 | }
198 |
199 | result := strings.Replace(importpath, key, value, 1)
200 | return result, true
201 | }
202 |
203 | return importpath, false
204 | }
205 |
206 | //onlyRelevantFiles processes only .go files excluding folders like node_modules and vendor.
207 | func onlyRelevantFiles(p string, fi os.FileInfo, err error, fn func(p string) error) error {
208 | if err != nil {
209 | return err
210 | }
211 |
212 | if fi.IsDir() && p != "." {
213 | for _, n := range []string{"_", ".", "vendor", "node_modules", ".git"} {
214 | base := filepath.Base(p)
215 | if strings.HasPrefix(base, n) {
216 | return filepath.SkipDir
217 | }
218 | }
219 |
220 | return nil
221 | }
222 |
223 | ext := filepath.Ext(p)
224 | if ext != ".go" {
225 | return nil
226 | }
227 |
228 | return fn(p)
229 | }
230 |
231 | func writeTempResult(name string, fset *token.FileSet, f *ast.File) (string, error) {
232 | temp := name + ".temp"
233 | w, err := os.Create(temp)
234 | if err != nil {
235 | return "", err
236 | }
237 |
238 | // write changes to .temp file, and include proper formatting.
239 | err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(w, fset, f)
240 | if err != nil {
241 | return "", err
242 | }
243 |
244 | // close the writer
245 | err = w.Close()
246 | if err != nil {
247 | return "", err
248 | }
249 |
250 | return temp, nil
251 | }
252 |
--------------------------------------------------------------------------------
/packr2/cmd/fix/runner.go:
--------------------------------------------------------------------------------
1 | package fix
2 |
3 | import (
4 | "fmt"
5 |
6 | packr "github.com/gobuffalo/packr/v2"
7 | )
8 |
9 | // Check interface for runnable checker functions
10 | type Check func(*Runner) error
11 |
12 | // Runner will run all compatible checks
13 | type Runner struct {
14 | Warnings []string
15 | }
16 |
17 | // Run all compatible checks
18 | func Run() error {
19 | fmt.Printf("! This updater will attempt to update your application to packr version: %s\n", packr.Version)
20 | if !ask("Do you wish to continue?") {
21 | fmt.Println("~~~ cancelling update ~~~")
22 | return nil
23 | }
24 |
25 | r := &Runner{
26 | Warnings: []string{},
27 | }
28 |
29 | defer func() {
30 | if len(r.Warnings) == 0 {
31 | return
32 | }
33 |
34 | fmt.Println("\n\n----------------------------")
35 | fmt.Printf("!!! (%d) Warnings Were Found !!!\n\n", len(r.Warnings))
36 | for _, w := range r.Warnings {
37 | fmt.Printf("[WARNING]: %s\n", w)
38 | }
39 | }()
40 |
41 | for _, c := range checks {
42 | if err := c(r); err != nil {
43 | return err
44 | }
45 | }
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/packr2/cmd/gocmd.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "os/exec"
7 | "path/filepath"
8 | "strings"
9 |
10 | "github.com/gobuffalo/packr/v2/plog"
11 | )
12 |
13 | func goCmd(name string, args ...string) error {
14 | cargs := []string{name}
15 | cargs = append(cargs, args...)
16 | if len(args) > 0 {
17 | err := func() error {
18 | path := "."
19 |
20 | pwd, err := os.Getwd()
21 | if err != nil {
22 | return err
23 | }
24 |
25 | if fi, err := os.Stat(filepath.Join(pwd, args[len(args)-1])); err == nil {
26 | if fi.IsDir() {
27 | return nil
28 | }
29 | path = fi.Name()
30 | }
31 |
32 | if filepath.Ext(path) != ".go" {
33 | return nil
34 | }
35 |
36 | path, err = filepath.Abs(filepath.Dir(path))
37 | if err != nil {
38 | return err
39 | }
40 |
41 | files, err := ioutil.ReadDir(path)
42 | if err != nil {
43 | return err
44 | }
45 | for _, f := range files {
46 | if strings.HasSuffix(f.Name(), "-packr.go") {
47 | cargs = append(cargs, f.Name())
48 | }
49 | }
50 | return nil
51 | }()
52 | if err != nil {
53 | return err
54 | }
55 | }
56 |
57 | goBin := os.Getenv("GO_BIN")
58 | if goBin == "" {
59 | goBin = "go"
60 | }
61 | cp := exec.Command(goBin, cargs...)
62 | plog.Logger.Debug(strings.Join(cp.Args, " "))
63 | cp.Stderr = os.Stderr
64 | cp.Stdin = os.Stdin
65 | cp.Stdout = os.Stdout
66 | return cp.Run()
67 | }
68 |
--------------------------------------------------------------------------------
/packr2/cmd/install.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gobuffalo/packr/v2/jam"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | const dont = `Please don't.
11 | The following commands have been deprecated and should not be used:
12 |
13 | * packr2 build
14 | * packr2 install
15 |
16 | They are, I'll be kind and say, "problematic" and cause more issues
17 | than than the actually solve. Sorry about that. My bad.
18 |
19 | It is recommended you use two commands instead:
20 |
21 | $ packr2
22 | $ go build/install
23 | `
24 |
25 | var installCmd = &cobra.Command{
26 | Use: "install",
27 | Short: "Don't. ru",
28 | DisableFlagParsing: true,
29 | RunE: func(cmd *cobra.Command, args []string) error {
30 | cargs := parseArgs(args)
31 | if globalOptions.Verbose {
32 | fmt.Println(dont)
33 | }
34 | if err := jam.Pack(globalOptions.PackOptions); err != nil {
35 | return err
36 | }
37 | return goCmd("install", cargs...)
38 | },
39 | }
40 |
41 | func init() {
42 | rootCmd.AddCommand(installCmd)
43 | }
44 |
--------------------------------------------------------------------------------
/packr2/cmd/pack.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | func parseArgs(args []string) []string {
4 | var cargs []string
5 | for _, a := range args {
6 | if a == "--legacy" {
7 | globalOptions.Legacy = true
8 | continue
9 | }
10 | if a == "--verbose" {
11 | globalOptions.Verbose = true
12 | continue
13 | }
14 | if a == "--silent" {
15 | globalOptions.Silent = true
16 | continue
17 | }
18 | if a == "--ignore-imports" {
19 | globalOptions.IgnoreImports = true
20 | continue
21 | }
22 | cargs = append(cargs, a)
23 | }
24 | return cargs
25 | }
26 |
--------------------------------------------------------------------------------
/packr2/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/gobuffalo/logger"
8 | "github.com/gobuffalo/packr/v2/jam"
9 | "github.com/gobuffalo/packr/v2/plog"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | var globalOptions = struct {
14 | jam.PackOptions
15 | Verbose bool
16 | Silent bool
17 | }{
18 | PackOptions: jam.PackOptions{},
19 | }
20 |
21 | var rootCmd = &cobra.Command{
22 | Use: "packr2",
23 | Short: "Packr is a simple solution for bundling static assets inside of Go binaries.",
24 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
25 | for _, a := range args {
26 | if a == "--legacy" {
27 | globalOptions.Legacy = true
28 | continue
29 | }
30 | if a == "-v" || a == "--verbose" {
31 | globalOptions.Verbose = true
32 | continue
33 | }
34 | }
35 |
36 | // if the last argument is a .go file or directory we should
37 | // find boxes from there, not from the current directory.
38 | // packr2 build -v cmd/main.go
39 | if len(args) > 0 {
40 | i := len(args) - 1
41 | dir := args[i]
42 | if _, err := os.Stat(dir); err == nil {
43 | if filepath.Ext(dir) == ".go" {
44 | dir = filepath.Dir(dir)
45 | }
46 | os.Chdir(dir)
47 | args[i] = filepath.Base(args[i])
48 | }
49 | }
50 |
51 | if globalOptions.Verbose {
52 | plog.Logger = logger.New(logger.DebugLevel)
53 | }
54 | if globalOptions.Silent {
55 | plog.Logger = logger.New(logger.FatalLevel)
56 | }
57 | return nil
58 | },
59 | RunE: func(cmd *cobra.Command, args []string) error {
60 | opts := globalOptions.PackOptions
61 | roots := opts.Roots
62 | roots = append(roots, args...)
63 | opts.Roots = roots
64 | return jam.Pack(opts)
65 | },
66 | }
67 |
68 | // Execute adds all child commands to the root command and sets flags appropriately.
69 | // This is called by main.main(). It only needs to happen once to the rootCmd.
70 | func Execute() {
71 | if err := rootCmd.Execute(); err != nil {
72 | os.Exit(1)
73 | }
74 | }
75 |
76 | func init() {
77 | rootCmd.PersistentFlags().BoolVarP(&globalOptions.Verbose, "verbose", "v", false, "enables verbose logging")
78 | rootCmd.PersistentFlags().BoolVar(&globalOptions.Legacy, "legacy", false, "uses the legacy resolution and packing system (assumes first arg || pwd for input path)")
79 | rootCmd.PersistentFlags().BoolVar(&globalOptions.Silent, "silent", false, "silences all output")
80 | rootCmd.PersistentFlags().BoolVar(&globalOptions.IgnoreImports, "ignore-imports", false, "when set to true packr won't resolve imports for boxes")
81 | rootCmd.PersistentFlags().StringVar(&globalOptions.StoreCmd, "store-cmd", "", "sub command to use for packing")
82 | }
83 |
--------------------------------------------------------------------------------
/packr2/cmd/version.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | packr "github.com/gobuffalo/packr/v2"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | var versionCmd = &cobra.Command{
11 | Use: "version",
12 | Short: "shows packr version",
13 | RunE: func(cmd *cobra.Command, args []string) error {
14 | fmt.Println(packr.Version)
15 | return nil
16 | },
17 | }
18 |
19 | func init() {
20 | rootCmd.AddCommand(versionCmd)
21 | }
22 |
--------------------------------------------------------------------------------
/packr2/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/gobuffalo/packr/v2/packr2/cmd"
4 |
5 | func main() {
6 | cmd.Execute()
7 | }
8 |
--------------------------------------------------------------------------------
/packr_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import "github.com/gobuffalo/packr/v2/file"
4 |
5 | func qfile(name string, body string) File {
6 | f, err := file.NewFile(name, []byte(body))
7 | if err != nil {
8 | panic(err)
9 | }
10 | return f
11 | }
12 |
--------------------------------------------------------------------------------
/plog/plog.go:
--------------------------------------------------------------------------------
1 | package plog
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/gobuffalo/logger"
8 | "github.com/sirupsen/logrus"
9 | )
10 |
11 | var Logger = logger.New(logger.ErrorLevel)
12 |
13 | func Debug(t interface{}, m string, args ...interface{}) {
14 | if len(args)%2 == 1 {
15 | args = append(args, "")
16 | }
17 | f := logrus.Fields{}
18 | for i := 0; i < len(args); i += 2 {
19 | k := fmt.Sprint(args[i])
20 | v := args[i+1]
21 | if s, ok := v.(fmt.Stringer); ok {
22 | f[k] = s.String()
23 | continue
24 | }
25 | if s, ok := v.(string); ok {
26 | f[k] = s
27 | continue
28 | }
29 | if b, err := json.Marshal(v); err == nil {
30 | f[k] = string(b)
31 | continue
32 | }
33 | f[k] = v
34 | }
35 | e := Logger.WithFields(f)
36 | if s, ok := t.(string); ok {
37 | e.Debugf("%s#%s", s, m)
38 | return
39 | }
40 | e.Debugf("%T#%s", t, m)
41 | }
42 |
--------------------------------------------------------------------------------
/pointer.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "github.com/gobuffalo/packr/v2/file"
5 | "github.com/gobuffalo/packr/v2/file/resolver"
6 | "github.com/gobuffalo/packr/v2/plog"
7 | )
8 |
9 | // Pointer is a resolvr which resolves
10 | // a file from a different box.
11 | type Pointer struct {
12 | ForwardBox string
13 | ForwardPath string
14 | }
15 |
16 | var _ resolver.Resolver = Pointer{}
17 |
18 | // Resolve attempts to find the file in the specific box
19 | // with the specified key
20 | func (p Pointer) Resolve(box string, path string) (file.File, error) {
21 | plog.Debug(p, "Resolve", "box", box, "path", path, "forward-box", p.ForwardBox, "forward-path", p.ForwardPath)
22 | b, err := findBox(p.ForwardBox)
23 | if err != nil {
24 | return nil, err
25 | }
26 | f, err := b.Resolve(p.ForwardPath)
27 | if err != nil {
28 | return f, err
29 | }
30 | plog.Debug(p, "Resolve", "box", box, "path", path, "file", f)
31 | return file.NewFileR(path, f)
32 | }
33 |
--------------------------------------------------------------------------------
/pointer_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/gobuffalo/packr/v2/file/resolver"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_Pointer_Find(t *testing.T) {
11 | r := require.New(t)
12 |
13 | b1 := New("b1", "")
14 | r.NoError(b1.AddString("foo.txt", "FOO!"))
15 |
16 | b2 := New("b2", "")
17 | b2.SetResolver("bar.txt", &Pointer{
18 | ForwardBox: "b1",
19 | ForwardPath: "foo.txt",
20 | })
21 |
22 | s, err := b2.FindString("bar.txt")
23 | r.NoError(err)
24 | r.Equal("FOO!", s)
25 | }
26 |
27 | func Test_Pointer_Find_CorrectName(t *testing.T) {
28 | r := require.New(t)
29 |
30 | gk := "0b5bab905480ad8c6d0695f615dcd644"
31 | g := New(gk, "")
32 | hgr, err := resolver.NewHexGzip(map[string]string{
33 | "48df4e44f4202fe5f6093beee782cb10": "1f8b08000000000000ff4c8ebdaec2300c46f7fb14bed94b5606a70b3f6283a1083186c46a2225354aad56bc3d6a2304933fdbc73ac6fffd79d7dd2f07089253fb87b5006020eb97008099c4820bb68c24465dbb63b355a07f9783cd64d414697e7211058e07a1418c9aa397603c4dd151b336df4b8992a83d514a0c372ec9a3aea345af3f7e7cb07fad21e61ec6e28cd2897bde8c53af2a5a09d4f5f777000000ffffcfb8b477d3000000",
34 | })
35 | r.NoError(err)
36 | g.DefaultResolver = hgr
37 |
38 | b := New("my box", "./templates")
39 | b.SetResolver("index.html", Pointer{ForwardBox: gk, ForwardPath: "48df4e44f4202fe5f6093beee782cb10"})
40 | f, err := b.Resolve("index.html")
41 | r.NoError(err)
42 | fi, err := f.Stat()
43 | r.NoError(err)
44 | r.Equal("index.html", fi.Name())
45 | }
46 |
--------------------------------------------------------------------------------
/resolvers_map.go:
--------------------------------------------------------------------------------
1 | //go:generate mapgen -name "resolvers" -zero "nil" -go-type "resolver.Resolver" -pkg "" -a "nil" -b "nil" -c "nil" -bb "nil" -destination "packr"
2 | // Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
3 |
4 | package packr
5 |
6 | import (
7 | "sort"
8 | "sync"
9 |
10 | "github.com/gobuffalo/packr/v2/file/resolver"
11 | )
12 |
13 | // resolversMap wraps sync.Map and uses the following types:
14 | // key: string
15 | // value: resolver.Resolver
16 | type resolversMap struct {
17 | data sync.Map
18 | }
19 |
20 | // Delete the key from the map
21 | func (m *resolversMap) Delete(key string) {
22 | m.data.Delete(key)
23 | }
24 |
25 | // Load the key from the map.
26 | // Returns resolver.Resolver or bool.
27 | // A false return indicates either the key was not found
28 | // or the value is not of type resolver.Resolver
29 | func (m *resolversMap) Load(key string) (resolver.Resolver, bool) {
30 | i, ok := m.data.Load(key)
31 | if !ok {
32 | return nil, false
33 | }
34 | s, ok := i.(resolver.Resolver)
35 | return s, ok
36 | }
37 |
38 | // LoadOrStore will return an existing key or
39 | // store the value if not already in the map
40 | func (m *resolversMap) LoadOrStore(key string, value resolver.Resolver) (resolver.Resolver, bool) {
41 | i, _ := m.data.LoadOrStore(key, value)
42 | s, ok := i.(resolver.Resolver)
43 | return s, ok
44 | }
45 |
46 | // Range over the resolver.Resolver values in the map
47 | func (m *resolversMap) Range(f func(key string, value resolver.Resolver) bool) {
48 | m.data.Range(func(k, v interface{}) bool {
49 | key, ok := k.(string)
50 | if !ok {
51 | return false
52 | }
53 | value, ok := v.(resolver.Resolver)
54 | if !ok {
55 | return false
56 | }
57 | return f(key, value)
58 | })
59 | }
60 |
61 | // Store a resolver.Resolver in the map
62 | func (m *resolversMap) Store(key string, value resolver.Resolver) {
63 | m.data.Store(key, value)
64 | }
65 |
66 | // Keys returns a list of keys in the map
67 | func (m *resolversMap) Keys() []string {
68 | var keys []string
69 | m.Range(func(key string, value resolver.Resolver) bool {
70 | keys = append(keys, key)
71 | return true
72 | })
73 | sort.Strings(keys)
74 | return keys
75 | }
76 |
--------------------------------------------------------------------------------
/version.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | // Version of Packr
4 | const Version = "v2.8.3"
5 |
--------------------------------------------------------------------------------
/walk.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "sort"
5 | "strings"
6 |
7 | "github.com/gobuffalo/packd"
8 | "github.com/gobuffalo/packr/v2/file"
9 | "github.com/gobuffalo/packr/v2/file/resolver"
10 | "github.com/gobuffalo/packr/v2/plog"
11 | )
12 |
13 | // WalkFunc is used to walk a box
14 | type WalkFunc = packd.WalkFunc
15 |
16 | // Walk will traverse the box and call the WalkFunc for each file in the box/folder.
17 | func (b *Box) Walk(wf WalkFunc) error {
18 | m := map[string]file.File{}
19 |
20 | dr := b.DefaultResolver
21 | if dr == nil {
22 | cd := resolver.OsPath(b.ResolutionDir)
23 | dr = &resolver.Disk{Root: cd}
24 | }
25 | if fm, ok := dr.(file.FileMappable); ok {
26 | for n, f := range fm.FileMap() {
27 | m[n] = f
28 | }
29 | }
30 | var err error
31 | b.resolvers.Range(func(n string, r resolver.Resolver) bool {
32 | var f file.File
33 | f, err = r.Resolve("", n)
34 | if err != nil {
35 | return false
36 | }
37 | keep := true
38 | for k := range m {
39 | if strings.EqualFold(k, n) {
40 | keep = false
41 | }
42 | }
43 | if keep {
44 | m[n] = f
45 | }
46 | return true
47 | })
48 | if err != nil {
49 | return err
50 | }
51 |
52 | var keys = make([]string, 0, len(m))
53 | for k := range m {
54 | keys = append(keys, k)
55 | }
56 | sort.Strings(keys)
57 |
58 | for _, k := range keys {
59 | osPath := resolver.OsPath(k)
60 | plog.Debug(b, "Walk", "path", k, "osPath", osPath)
61 | if err := wf(osPath, m[k]); err != nil {
62 | return err
63 | }
64 | }
65 | return nil
66 | }
67 |
68 | // WalkPrefix will call box.Walk and call the WalkFunc when it finds paths that have a matching prefix
69 | func (b *Box) WalkPrefix(prefix string, wf WalkFunc) error {
70 | ipref := resolver.OsPath(prefix)
71 | return b.Walk(func(path string, f File) error {
72 | ipath := resolver.OsPath(path)
73 | if strings.HasPrefix(ipath, ipref) {
74 | if err := wf(path, f); err != nil {
75 | return err
76 | }
77 | }
78 | return nil
79 | })
80 | }
81 |
--------------------------------------------------------------------------------
/walk_test.go:
--------------------------------------------------------------------------------
1 | package packr
2 |
3 | import (
4 | "path/filepath"
5 | "testing"
6 |
7 | "github.com/gobuffalo/packr/v2/file"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_Box_Walk(t *testing.T) {
12 | r := require.New(t)
13 |
14 | box := NewBox(filepath.Join("_fixtures", "list_test"))
15 | r.NoError(box.AddString(filepath.Join("d", "d.txt"), "D"))
16 |
17 | var act []string
18 | r.NoError(box.Walk(func(path string, f file.File) error {
19 | act = append(act, path)
20 | return nil
21 | }))
22 | exp := []string{"a.txt", filepath.Join("b", "b.txt"), filepath.Join("b", "b2.txt"), filepath.Join("c", "c.txt"), filepath.Join("d", "d.txt")}
23 | r.Equal(exp, act)
24 | }
25 |
26 | func Test_Box_WalkPrefix(t *testing.T) {
27 | r := require.New(t)
28 |
29 | box := NewBox(filepath.Join("_fixtures", "list_test"))
30 | r.NoError(box.AddString(filepath.Join("d", "d.txt"), "D"))
31 |
32 | var act []string
33 | r.NoError(box.WalkPrefix("b/", func(path string, f file.File) error {
34 | act = append(act, path)
35 | return nil
36 | }))
37 | exp := []string{filepath.Join("b", "b.txt"), filepath.Join("b", "b2.txt")}
38 | r.Equal(exp, act)
39 | }
40 |
--------------------------------------------------------------------------------