Move 'esc' tool out of image into vendor'd source

Smaller that way, and more consistent

(Note we run it with GC enabled; it crashes in CI otherwise)
This commit is contained in:
Bryan Boreham
2020-12-29 22:01:40 +00:00
parent bebc124ae5
commit bba4879bf3
48 changed files with 23625 additions and 3 deletions

20
vendor/github.com/mjibson/esc/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,20 @@
language: go
matrix:
include:
- go: 1.10.x
- go: 1.11.x
install:
- go get golang.org/x/lint/golint
- go get ./...
- go install .
script:
- go generate ./...
- esc -o static.go testdata
- go test -v ./...
- go vet ./...
- LINT=$(golint ./...) && echo $LINT
- test -z "$LINT"
- GOFMT=$(gofmt -s -d .) && echo $GOFMT
- test -z "$GOFMT"

20
vendor/github.com/mjibson/esc/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 Matt Jibson
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

96
vendor/github.com/mjibson/esc/README.md generated vendored Normal file
View File

@@ -0,0 +1,96 @@
# esc
[![GoDoc](https://godoc.org/github.com/mjibson/esc?status.svg)](https://godoc.org/github.com/mjibson/esc)
esc embeds files into go programs and provides http.FileSystem interfaces
to them.
It adds all named files or files recursively under named directories at the
path specified. The output file provides an http.FileSystem interface with
zero dependencies on packages outside the standard library.
## Installation
`go get -u github.com/mjibson/esc`
## Usage
`esc [flag] [name ...]`
The flags are:
```
-o=""
output filename, defaults to stdout
-pkg="main"
package name of output file, defaults to main
-prefix=""
strip given prefix from filenames
-ignore=""
regular expression for files to ignore
-include=""
regular expression for files to include
-modtime=""
Unix timestamp to override as modification time for all files
-private
unexport functions by prefixing them with esc, e.g. FS -> escFS
-no-compress
do not compress files
```
## Accessing Embedded Files
After producing an output file, the assets may be accessed with the FS()
function, which takes a flag to use local assets instead (for local
development).
* (_esc)?FS(Must)?(Byte|String) returns an asset as a (byte slice|string).
* (_esc)?FSMust(Byte|String) panics if the asset is not found.
## Go Generate
esc can be invoked by go generate:
`//go:generate esc -o static.go -pkg server static`
## Example
Embedded assets can be served with HTTP using the http.FileServer.
Assuming you have a directory structure similar to the following:
```
.
├── main.go
└── static
├── css
│   └── style.css
└── index.html
```
Where main.go contains:
```
package main
import (
"log"
"net/http"
)
func main() {
// FS() is created by esc and returns a http.Filesystem.
http.Handle("/static/", http.FileServer(FS(false)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
1. Generate the embedded data:
`esc -o static.go static`
2. Start the server:
`go run main.go static.go`
3. Access http://localhost:8080/static/index.html to view the files.
You can see worked example in [example](example) dir
just run it as
`go run example/main.go example/static.go`

80
vendor/github.com/mjibson/esc/doc.go generated vendored Normal file
View File

@@ -0,0 +1,80 @@
/*
esc embeds files into go programs and provides http.FileSystem interfaces
to them.
It adds all named files or files recursively under named directories at the
path specified. The output file provides an http.FileSystem interface with
zero dependencies on packages outside the standard library.
Usage:
esc [flag] [name ...]
The flags are:
-o=""
output filename, defaults to stdout
-pkg="main"
package name of output file, defaults to main
-prefix=""
strip given prefix from filenames
-ignore=""
regular expression for files to ignore
-include=""
regular expression for files to include
-modtime=""
Unix timestamp to override as modification time for all files
-private
unexport functions by prefixing them with esc, e.g. FS -> escFS
-no-compress
do not compress files
Accessing Embedded Files
After producing an output file, the assets may be accessed with the FS()
function, which takes a flag to use local assets instead (for local
development).
FS(Must)?(Byte|String) returns an asset as a (byte slice|string).
FSMust(Byte|String) panics if the asset is not found.
Go Generate
esc can be invoked by go generate:
//go:generate esc -o static.go -pkg server static
Example
Embedded assets can be served with HTTP using the http.FileServer.
Assuming you have a directory structure similar to the following:
.
├── main.go
└── static
├── css
│   └── style.css
└── index.html
Where main.go contains:
package main
import (
"log"
"net/http"
)
func main() {
// FS() is created by esc and returns a http.Filesystem.
http.Handle("/static/", http.FileServer(FS(false)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
1. Generate the embedded data:
esc -o static.go static
2. Start the server:
go run main.go static.go
3. Access http://localhost:8080/static/index.html to view the files.
*/
package main

486
vendor/github.com/mjibson/esc/embed/embed.go generated vendored Normal file
View File

@@ -0,0 +1,486 @@
// Package embed implements all file embedding logic for github.com/mjibson/esc.
package embed
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"text/template"
"github.com/pkg/errors"
"golang.org/x/tools/imports"
)
// Config contains all information needed to run esc.
type Config struct {
// OutputFile is the file name to write output, else stdout.
OutputFile string
// Package name for the generated file.
Package string
// Prefix is stripped from filenames.
Prefix string
// Ignore is the regexp for files we should ignore (for example `\.DS_Store`).
Ignore string
// Include is the regexp for files to include. If provided, only files that
// match will be included.
Include string
// ModTime is the Unix timestamp to override as modification time for all files.
ModTime string
// Private, if true, causes autogenerated functions to be unexported.
Private bool
// NoCompression, if true, stores the files without compression.
NoCompression bool
// Invocation, if set, is added to the invocation string in the generated template.
Invocation string
// Files is the list of files or directories to embed.
Files []string
}
var modTime *int64
var tmpl = template.Must(template.New("").Parse(fileTemplate))
type templateParams struct {
Invocation string
PackageName string
FunctionPrefix string
Files []*_escFile
Dirs []*_escDir
}
type _escFile struct {
Name string
BaseName string
Data []byte
Local string
ModTime int64
Compressed string
fileinfo os.FileInfo
}
type _escDir struct {
Name string
BaseName string
Local string
ChildFileNames []string
}
// Run executes a Config.
func Run(conf *Config, out io.Writer) error {
var err error
if conf.ModTime != "" {
i, err := strconv.ParseInt(conf.ModTime, 10, 64)
if err != nil {
return fmt.Errorf("modtime must be an integer: %v", err)
}
modTime = &i
}
alreadyPrepared := make(map[string]bool, 10)
escFiles := make([]*_escFile, 0, 10)
prefix := filepath.ToSlash(conf.Prefix)
var ignoreRegexp *regexp.Regexp
if conf.Ignore != "" {
ignoreRegexp, err = regexp.Compile(conf.Ignore)
if err != nil {
return err
}
}
var includeRegexp *regexp.Regexp
if conf.Include != "" {
includeRegexp, err = regexp.Compile(conf.Include)
if err != nil {
return err
}
}
gzipLevel := gzip.BestCompression
if conf.NoCompression {
gzipLevel = gzip.NoCompression
}
directories := make([]*_escDir, 0, 10)
for _, base := range conf.Files {
files := []string{base}
for len(files) > 0 {
fname := files[0]
files = files[1:]
if ignoreRegexp != nil && ignoreRegexp.MatchString(fname) {
continue
}
f, err := os.Open(fname)
if err != nil {
return err
}
fi, err := f.Stat()
if err != nil {
return err
}
fpath := filepath.ToSlash(fname)
n := canonicFileName(fname, prefix)
if fi.IsDir() {
fis, err := f.Readdir(0)
if err != nil {
return err
}
dir := &_escDir{
Name: n,
BaseName: path.Base(n),
Local: fpath,
ChildFileNames: make([]string, 0, len(fis)),
}
for _, fi := range fis {
childFName := filepath.Join(fname, fi.Name())
files = append(files, childFName)
if ignoreRegexp != nil && ignoreRegexp.MatchString(childFName) {
continue
}
if includeRegexp == nil || includeRegexp.MatchString(childFName) {
dir.ChildFileNames = append(dir.ChildFileNames, canonicFileName(filepath.Join(fname, fi.Name()), prefix))
}
}
sort.Strings(dir.ChildFileNames)
directories = append(directories, dir)
} else if includeRegexp == nil || includeRegexp.MatchString(fname) {
b, err := ioutil.ReadAll(f)
if err != nil {
return errors.Wrap(err, "readAll return err")
}
if alreadyPrepared[n] {
return fmt.Errorf("%s, %s: duplicate Name after prefix removal", n, fpath)
}
escFile := &_escFile{
Name: n,
BaseName: path.Base(n),
Data: b,
Local: fpath,
fileinfo: fi,
ModTime: fi.ModTime().Unix(),
}
if modTime != nil {
escFile.ModTime = *modTime
}
if err := escFile.fillCompressed(gzipLevel); err != nil {
return err
}
escFiles = append(escFiles, escFile)
alreadyPrepared[n] = true
}
f.Close()
}
}
sort.Slice(escFiles, func(i, j int) bool { return strings.Compare(escFiles[i].Name, escFiles[j].Name) == -1 })
sort.Slice(directories, func(i, j int) bool { return strings.Compare(directories[i].Name, directories[j].Name) == -1 })
functionPrefix := ""
if conf.Private {
functionPrefix = "_esc"
}
buf := bytes.NewBuffer(nil)
tmpl.Execute(buf, templateParams{
Invocation: conf.Invocation,
PackageName: conf.Package,
FunctionPrefix: functionPrefix,
Files: escFiles,
Dirs: directories,
})
fakeOutFileName := "static.go"
if conf.OutputFile != "" {
fakeOutFileName = conf.OutputFile
}
data, err := imports.Process(fakeOutFileName, buf.Bytes(), nil)
if err != nil {
return errors.Wrap(err, "imports.Process return error")
}
fmt.Fprint(out, string(data))
return nil
}
func canonicFileName(fname, prefix string) string {
fpath := filepath.ToSlash(fname)
return path.Join("/", strings.TrimPrefix(fpath, prefix))
}
func (f *_escFile) fillCompressed(gzipLevel int) error {
var buf bytes.Buffer
gw, err := gzip.NewWriterLevel(&buf, gzipLevel)
if err != nil {
return err
}
if _, err := gw.Write(f.Data); err != nil {
return err
}
if err := gw.Close(); err != nil {
return err
}
var b bytes.Buffer
b64 := base64.NewEncoder(base64.StdEncoding, &b)
b64.Write(buf.Bytes())
b64.Close()
res := "\n"
chunk := make([]byte, 80)
for n, _ := b.Read(chunk); n > 0; n, _ = b.Read(chunk) {
res += string(chunk[0:n]) + "\n"
}
f.Compressed = res
return nil
}
const (
fileTemplate = `// Code generated by "esc{{with .Invocation}} {{.}}{{end}}"; DO NOT EDIT.
package {{.PackageName}}
import (
"bytes"
"compress/gzip"
"encoding/base64"
"io/ioutil"
"net/http"
"os"
"path"
"sync"
"time"
)
type _escLocalFS struct{}
var _escLocal _escLocalFS
type _escStaticFS struct{}
var _escStatic _escStaticFS
type _escDirectory struct {
fs http.FileSystem
name string
}
type _escFile struct {
compressed string
size int64
modtime int64
local string
isDir bool
once sync.Once
data []byte
name string
}
func (_escLocalFS) Open(name string) (http.File, error) {
f, present := _escData[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
return os.Open(f.local)
}
func (_escStaticFS) prepare(name string) (*_escFile, error) {
f, present := _escData[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
var err error
f.once.Do(func() {
f.name = path.Base(name)
if f.size == 0 {
return
}
var gr *gzip.Reader
b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed))
gr, err = gzip.NewReader(b64)
if err != nil {
return
}
f.data, err = ioutil.ReadAll(gr)
})
if err != nil {
return nil, err
}
return f, nil
}
func (fs _escStaticFS) Open(name string) (http.File, error) {
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
func (dir _escDirectory) Open(name string) (http.File, error) {
return dir.fs.Open(dir.name + name)
}
func (f *_escFile) File() (http.File, error) {
type httpFile struct {
*bytes.Reader
*_escFile
}
return &httpFile{
Reader: bytes.NewReader(f.data),
_escFile: f,
}, nil
}
func (f *_escFile) Close() error {
return nil
}
func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
if !f.isDir {
return nil, fmt.Errorf(" escFile.Readdir: '%s' is not directory", f.name)
}
fis, ok := _escDirs[f.local]
if !ok {
return nil, fmt.Errorf(" escFile.Readdir: '%s' is directory, but we have no info about content of this dir, local=%s", f.name, f.local)
}
limit := count
if count <= 0 || limit > len(fis) {
limit = len(fis)
}
if len(fis) == 0 && count > 0 {
return nil, io.EOF
}
return fis[0:limit], nil
}
func (f *_escFile) Stat() (os.FileInfo, error) {
return f, nil
}
func (f *_escFile) Name() string {
return f.name
}
func (f *_escFile) Size() int64 {
return f.size
}
func (f *_escFile) Mode() os.FileMode {
return 0
}
func (f *_escFile) ModTime() time.Time {
return time.Unix(f.modtime, 0)
}
func (f *_escFile) IsDir() bool {
return f.isDir
}
func (f *_escFile) Sys() interface{} {
return f
}
// {{.FunctionPrefix}}FS returns a http.Filesystem for the embedded assets. If useLocal is true,
// the filesystem's contents are instead used.
func {{.FunctionPrefix}}FS(useLocal bool) http.FileSystem {
if useLocal {
return _escLocal
}
return _escStatic
}
// {{.FunctionPrefix}}Dir returns a http.Filesystem for the embedded assets on a given prefix dir.
// If useLocal is true, the filesystem's contents are instead used.
func {{.FunctionPrefix}}Dir(useLocal bool, name string) http.FileSystem {
if useLocal {
return _escDirectory{fs: _escLocal, name: name}
}
return _escDirectory{fs: _escStatic, name: name}
}
// {{.FunctionPrefix}}FSByte returns the named file from the embedded assets. If useLocal is
// true, the filesystem's contents are instead used.
func {{.FunctionPrefix}}FSByte(useLocal bool, name string) ([]byte, error) {
if useLocal {
f, err := _escLocal.Open(name)
if err != nil {
return nil, err
}
b, err := ioutil.ReadAll(f)
_ = f.Close()
return b, err
}
f, err := _escStatic.prepare(name)
if err != nil {
return nil, err
}
return f.data, nil
}
// {{.FunctionPrefix}}FSMustByte is the same as {{.FunctionPrefix}}FSByte, but panics if name is not present.
func {{.FunctionPrefix}}FSMustByte(useLocal bool, name string) []byte {
b, err := {{.FunctionPrefix}}FSByte(useLocal, name)
if err != nil {
panic(err)
}
return b
}
// {{.FunctionPrefix}}FSString is the string version of {{.FunctionPrefix}}FSByte.
func {{.FunctionPrefix}}FSString(useLocal bool, name string) (string, error) {
b, err := {{.FunctionPrefix}}FSByte(useLocal, name)
return string(b), err
}
// {{.FunctionPrefix}}FSMustString is the string version of {{.FunctionPrefix}}FSMustByte.
func {{.FunctionPrefix}}FSMustString(useLocal bool, name string) string {
return string({{.FunctionPrefix}}FSMustByte(useLocal, name))
}
var _escData = map[string]*_escFile{
{{ range .Files }}
"{{ .Name }}": {
name: "{{ .BaseName }}",
local: "{{ .Local }}",
size: {{ .Data | len }},
modtime: {{ .ModTime }},
compressed: ` + "`" + `{{ .Compressed }}` + "`" + `,
},
{{ end -}}
{{ range .Dirs }}
"{{ .Name }}": {
name: "{{ .BaseName }}",
local: ` + "`" + `{{ .Local }}` + "`" + `,
isDir: true,
},
{{ end }}
}
var _escDirs = map[string][]os.FileInfo{
{{ range .Dirs }}
"{{ .Local }}": {
{{ range .ChildFileNames -}}
_escData["{{.}}"],
{{ end }}
},
{{ end }}
}
`
)

40
vendor/github.com/mjibson/esc/main.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"flag"
"log"
"os"
"strings"
"github.com/mjibson/esc/embed"
)
func main() {
conf := &embed.Config{
Invocation: strings.Join(os.Args[1:], " "),
}
flag.StringVar(&conf.OutputFile, "o", "", "Output file, else stdout.")
flag.StringVar(&conf.Package, "pkg", "main", "Package.")
flag.StringVar(&conf.Prefix, "prefix", "", "Prefix to strip from filesnames.")
flag.StringVar(&conf.Ignore, "ignore", "", "Regexp for files we should ignore (for example \\\\.DS_Store).")
flag.StringVar(&conf.Include, "include", "", "Regexp for files to include. Only files that match will be included.")
flag.StringVar(&conf.ModTime, "modtime", "", "Unix timestamp to override as modification time for all files.")
flag.BoolVar(&conf.Private, "private", false, "If true, do not export autogenerated functions.")
flag.BoolVar(&conf.NoCompression, "no-compress", false, "If true, do not compress files.")
flag.Parse()
conf.Files = flag.Args()
var err error
out := os.Stdout
if conf.OutputFile != "" {
if out, err = os.Create(conf.OutputFile); err != nil {
log.Fatal(err)
}
defer out.Close()
}
if err = embed.Run(conf, out); err != nil {
log.Fatal(err)
}
}