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