diff options
author | Mike Crute <mike@crute.us> | 2023-12-05 18:50:09 -0800 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2023-12-05 18:50:09 -0800 |
commit | f0c1818b9148e56f8e1c0c3fd8a6c4070d9a80d3 (patch) | |
tree | 24a21bbec2b84dee3bbc5df0954d4d128cabc5d1 | |
parent | e01c3ce59a9c01398c7aa27374c882e724896ad4 (diff) | |
download | golib-f0c1818b9148e56f8e1c0c3fd8a6c4070d9a80d3.tar.bz2 golib-f0c1818b9148e56f8e1c0c3fd8a6c4070d9a80d3.tar.xz golib-f0c1818b9148e56f8e1c0c3fd8a6c4070d9a80d3.zip |
echo: add CSS and JS minifiersecho/v0.17.0
-rw-r--r-- | echo/controller/css_preprocessor.go | 91 | ||||
-rw-r--r-- | echo/controller/js_preprocessor.go | 110 | ||||
-rw-r--r-- | echo/go.mod | 7 | ||||
-rw-r--r-- | echo/go.sum | 16 |
4 files changed, 208 insertions, 16 deletions
diff --git a/echo/controller/css_preprocessor.go b/echo/controller/css_preprocessor.go index a00beb8..b174198 100644 --- a/echo/controller/css_preprocessor.go +++ b/echo/controller/css_preprocessor.go | |||
@@ -2,40 +2,111 @@ package controller | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | 4 | "bytes" |
5 | "errors" | ||
6 | "io" | ||
5 | "io/fs" | 7 | "io/fs" |
6 | "net/http" | 8 | "net/http" |
9 | "path/filepath" | ||
10 | "strings" | ||
7 | 11 | ||
12 | lru "github.com/hashicorp/golang-lru/v2" | ||
8 | "github.com/labstack/echo/v4" | 13 | "github.com/labstack/echo/v4" |
9 | 14 | ||
10 | "code.crute.us/mcrute/golib/web/css" | 15 | "code.crute.us/mcrute/golib/web/css" |
11 | ) | 16 | ) |
12 | 17 | ||
18 | const defaultCssCacheSize = 100 | ||
19 | |||
13 | type CSSMinifierController struct { | 20 | type CSSMinifierController struct { |
14 | Debug bool | 21 | Debug bool |
22 | Skip bool | ||
15 | Name string | 23 | Name string |
16 | Files fs.FS | 24 | Files fs.FS |
17 | cache []byte | 25 | cache *lru.Cache[string, []byte] |
26 | } | ||
27 | |||
28 | type CSSMinifierConfig struct { | ||
29 | Debug bool | ||
30 | Skip bool | ||
31 | Name string | ||
32 | CacheSize int | ||
33 | Files fs.FS | ||
18 | } | 34 | } |
19 | 35 | ||
20 | func (m *CSSMinifierController) Load() error { | 36 | func NewCSSMinifierController(cfg CSSMinifierConfig) *CSSMinifierController { |
21 | if !m.Debug { | 37 | s := cfg.CacheSize |
22 | c := &bytes.Buffer{} | 38 | if s == 0 { |
23 | err := css.ParseWriteSheet(m.Files, m.Name, c) | 39 | s = defaultCssCacheSize |
24 | m.cache = c.Bytes() | 40 | } |
41 | |||
42 | c, err := lru.New[string, []byte](s) | ||
43 | if err != nil { // Should only happen if size == 0 | ||
44 | panic(err) | ||
45 | } | ||
46 | |||
47 | return &CSSMinifierController{ | ||
48 | Debug: cfg.Debug, | ||
49 | Skip: cfg.Skip, | ||
50 | Name: cfg.Name, | ||
51 | Files: cfg.Files, | ||
52 | cache: c, | ||
53 | } | ||
54 | } | ||
55 | |||
56 | func (m *CSSMinifierController) minify(name string, w io.Writer) error { | ||
57 | fd, err := m.mayOpenFile(name) | ||
58 | if err != nil { | ||
25 | return err | 59 | return err |
26 | } | 60 | } |
27 | return nil | 61 | defer fd.Close() |
62 | return css.ParseWriteSheet(m.Files, name, w) | ||
63 | } | ||
64 | |||
65 | // mayOpenFile tries to open a file and translates fs.ErrNotExist into | ||
66 | // echo.ErrNotFound | ||
67 | func (m *CSSMinifierController) mayOpenFile(path string) (io.ReadCloser, error) { | ||
68 | fd, err := m.Files.Open(path) | ||
69 | if err != nil && errors.Is(err, fs.ErrNotExist) { | ||
70 | return nil, echo.ErrNotFound | ||
71 | } | ||
72 | return fd, err | ||
28 | } | 73 | } |
29 | 74 | ||
30 | func (m *CSSMinifierController) Handle(c echo.Context) error { | 75 | func (m *CSSMinifierController) Handle(c echo.Context) error { |
31 | r := c.Response() | 76 | r := c.Response() |
32 | r.Header().Set("Content-Type", "text/css") | 77 | r.Header().Set("Content-Type", "text/css") |
33 | r.WriteHeader(http.StatusOK) | 78 | |
79 | path := strings.TrimPrefix(filepath.Clean(c.Request().URL.Path), "/") | ||
80 | if filepath.Ext(path) != ".css" { | ||
81 | return c.NoContent(http.StatusBadRequest) | ||
82 | } | ||
34 | 83 | ||
35 | if m.Debug { | 84 | if m.Debug { |
36 | return css.ParseWriteSheet(m.Files, m.Name, r) | 85 | if m.Skip { |
86 | fd, err := m.mayOpenFile(path) | ||
87 | if err != nil { | ||
88 | return err | ||
89 | } | ||
90 | defer fd.Close() | ||
91 | |||
92 | r.WriteHeader(http.StatusOK) | ||
93 | _, err = io.Copy(r, fd) | ||
94 | return err | ||
95 | } | ||
96 | return m.minify(path, r) | ||
37 | } else { | 97 | } else { |
38 | _, err := r.Write(m.cache) | 98 | val, ok := m.cache.Get(path) |
99 | if !ok { | ||
100 | buf := &bytes.Buffer{} | ||
101 | if err := m.minify(path, buf); err != nil { | ||
102 | return err | ||
103 | } | ||
104 | m.cache.Add(path, buf.Bytes()) | ||
105 | val = buf.Bytes() | ||
106 | } | ||
107 | |||
108 | r.WriteHeader(http.StatusOK) | ||
109 | _, err := r.Write(val) | ||
39 | return err | 110 | return err |
40 | } | 111 | } |
41 | } | 112 | } |
diff --git a/echo/controller/js_preprocessor.go b/echo/controller/js_preprocessor.go new file mode 100644 index 0000000..377f270 --- /dev/null +++ b/echo/controller/js_preprocessor.go | |||
@@ -0,0 +1,110 @@ | |||
1 | package controller | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "errors" | ||
6 | "io" | ||
7 | "io/fs" | ||
8 | "net/http" | ||
9 | "path/filepath" | ||
10 | "strings" | ||
11 | |||
12 | lru "github.com/hashicorp/golang-lru/v2" | ||
13 | "github.com/labstack/echo/v4" | ||
14 | "github.com/tdewolff/minify/v2/js" | ||
15 | ) | ||
16 | |||
17 | const defaultJsCacheSize = 100 | ||
18 | |||
19 | type JSMinifierController struct { | ||
20 | Debug bool | ||
21 | Skip bool | ||
22 | Files fs.FS | ||
23 | cache *lru.Cache[string, []byte] | ||
24 | min *js.Minifier | ||
25 | } | ||
26 | |||
27 | type JSMinifierConfig struct { | ||
28 | Debug bool | ||
29 | Skip bool | ||
30 | CacheSize int | ||
31 | Files fs.FS | ||
32 | } | ||
33 | |||
34 | func NewJSMinifierController(cfg JSMinifierConfig) *JSMinifierController { | ||
35 | s := cfg.CacheSize | ||
36 | if s == 0 { | ||
37 | s = defaultJsCacheSize | ||
38 | } | ||
39 | |||
40 | c, err := lru.New[string, []byte](s) | ||
41 | if err != nil { // Should only happen if size == 0 | ||
42 | panic(err) | ||
43 | } | ||
44 | |||
45 | return &JSMinifierController{ | ||
46 | Debug: cfg.Debug, | ||
47 | Skip: cfg.Skip, | ||
48 | Files: cfg.Files, | ||
49 | cache: c, | ||
50 | min: &js.Minifier{}, | ||
51 | } | ||
52 | } | ||
53 | |||
54 | func (m *JSMinifierController) minify(name string, w io.Writer) error { | ||
55 | fd, err := m.mayOpenFile(name) | ||
56 | if err != nil { | ||
57 | return err | ||
58 | } | ||
59 | defer fd.Close() | ||
60 | return m.min.Minify(nil, w, fd, nil) | ||
61 | } | ||
62 | |||
63 | // mayOpenFile tries to open a file and translates fs.ErrNotExist into | ||
64 | // echo.ErrNotFound | ||
65 | func (m *JSMinifierController) mayOpenFile(path string) (io.ReadCloser, error) { | ||
66 | fd, err := m.Files.Open(path) | ||
67 | if err != nil && errors.Is(err, fs.ErrNotExist) { | ||
68 | return nil, echo.ErrNotFound | ||
69 | } | ||
70 | return fd, err | ||
71 | } | ||
72 | |||
73 | func (m *JSMinifierController) Handle(c echo.Context) error { | ||
74 | r := c.Response() | ||
75 | r.Header().Set("Content-Type", "text/javascript") | ||
76 | |||
77 | path := strings.TrimPrefix(filepath.Clean(c.Request().URL.Path), "/") | ||
78 | if filepath.Ext(path) != ".js" { | ||
79 | return c.NoContent(http.StatusBadRequest) | ||
80 | } | ||
81 | |||
82 | if m.Debug { | ||
83 | if m.Skip { | ||
84 | fd, err := m.mayOpenFile(path) | ||
85 | if err != nil { | ||
86 | return err | ||
87 | } | ||
88 | defer fd.Close() | ||
89 | |||
90 | r.WriteHeader(http.StatusOK) | ||
91 | _, err = io.Copy(r, fd) | ||
92 | return err | ||
93 | } | ||
94 | return m.minify(path, r) | ||
95 | } else { | ||
96 | val, ok := m.cache.Get(path) | ||
97 | if !ok { | ||
98 | buf := &bytes.Buffer{} | ||
99 | if err := m.minify(path, buf); err != nil { | ||
100 | return err | ||
101 | } | ||
102 | m.cache.Add(path, buf.Bytes()) | ||
103 | val = buf.Bytes() | ||
104 | } | ||
105 | |||
106 | r.WriteHeader(http.StatusOK) | ||
107 | _, err := r.Write(val) | ||
108 | return err | ||
109 | } | ||
110 | } | ||
diff --git a/echo/go.mod b/echo/go.mod index 23a62be..64877fc 100644 --- a/echo/go.mod +++ b/echo/go.mod | |||
@@ -7,13 +7,15 @@ require ( | |||
7 | code.crute.us/mcrute/golib/clients/netbox/v4 v4.1.0 | 7 | code.crute.us/mcrute/golib/clients/netbox/v4 v4.1.0 |
8 | code.crute.us/mcrute/golib/secrets v0.4.0 | 8 | code.crute.us/mcrute/golib/secrets v0.4.0 |
9 | code.crute.us/mcrute/golib/vault v0.2.6 | 9 | code.crute.us/mcrute/golib/vault v0.2.6 |
10 | code.crute.us/mcrute/golib/web/css v0.1.0 | 10 | code.crute.us/mcrute/golib/web/css v0.1.1 |
11 | github.com/elnormous/contenttype v1.0.3 | 11 | github.com/elnormous/contenttype v1.0.3 |
12 | github.com/hashicorp/golang-lru/v2 v2.0.7 | ||
12 | github.com/labstack/echo/v4 v4.6.1 | 13 | github.com/labstack/echo/v4 v4.6.1 |
13 | github.com/labstack/gommon v0.3.1 | 14 | github.com/labstack/gommon v0.3.1 |
14 | github.com/prometheus/client_golang v1.11.0 | 15 | github.com/prometheus/client_golang v1.11.0 |
15 | github.com/quic-go/quic-go v0.39.0 | 16 | github.com/quic-go/quic-go v0.39.0 |
16 | github.com/stretchr/testify v1.8.1 | 17 | github.com/stretchr/testify v1.8.1 |
18 | github.com/tdewolff/minify/v2 v2.20.9 | ||
17 | gopkg.in/square/go-jose.v2 v2.5.1 | 19 | gopkg.in/square/go-jose.v2 v2.5.1 |
18 | ) | 20 | ) |
19 | 21 | ||
@@ -70,6 +72,7 @@ require ( | |||
70 | github.com/quic-go/qpack v0.4.0 // indirect | 72 | github.com/quic-go/qpack v0.4.0 // indirect |
71 | github.com/quic-go/qtls-go1-20 v0.3.4 // indirect | 73 | github.com/quic-go/qtls-go1-20 v0.3.4 // indirect |
72 | github.com/ryanuber/go-glob v1.0.0 // indirect | 74 | github.com/ryanuber/go-glob v1.0.0 // indirect |
75 | github.com/tdewolff/parse/v2 v2.7.6 // indirect | ||
73 | github.com/valyala/bytebufferpool v1.0.0 // indirect | 76 | github.com/valyala/bytebufferpool v1.0.0 // indirect |
74 | github.com/valyala/fasttemplate v1.2.1 // indirect | 77 | github.com/valyala/fasttemplate v1.2.1 // indirect |
75 | go.uber.org/atomic v1.9.0 // indirect | 78 | go.uber.org/atomic v1.9.0 // indirect |
@@ -78,7 +81,7 @@ require ( | |||
78 | golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect | 81 | golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect |
79 | golang.org/x/mod v0.11.0 // indirect | 82 | golang.org/x/mod v0.11.0 // indirect |
80 | golang.org/x/net v0.10.0 // indirect | 83 | golang.org/x/net v0.10.0 // indirect |
81 | golang.org/x/sys v0.10.0 // indirect | 84 | golang.org/x/sys v0.15.0 // indirect |
82 | golang.org/x/text v0.11.0 // indirect | 85 | golang.org/x/text v0.11.0 // indirect |
83 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect | 86 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect |
84 | golang.org/x/tools v0.9.1 // indirect | 87 | golang.org/x/tools v0.9.1 // indirect |
diff --git a/echo/go.sum b/echo/go.sum index 462635f..05485aa 100644 --- a/echo/go.sum +++ b/echo/go.sum | |||
@@ -38,8 +38,8 @@ code.crute.us/mcrute/golib/secrets v0.4.0 h1:tZzQEOnJshDGuzvvr0n0BMWZbu3ZMB5QRqI | |||
38 | code.crute.us/mcrute/golib/secrets v0.4.0/go.mod h1:c40ezKg/NXe5NE3PaCRIUJC6D6XCoPSu9+duZSdKsNY= | 38 | code.crute.us/mcrute/golib/secrets v0.4.0/go.mod h1:c40ezKg/NXe5NE3PaCRIUJC6D6XCoPSu9+duZSdKsNY= |
39 | code.crute.us/mcrute/golib/vault v0.2.6 h1:X+TlEGFPj6pj3OqmrJprv+wJYdo8QTR2IpP3EfVniHU= | 39 | code.crute.us/mcrute/golib/vault v0.2.6 h1:X+TlEGFPj6pj3OqmrJprv+wJYdo8QTR2IpP3EfVniHU= |
40 | code.crute.us/mcrute/golib/vault v0.2.6/go.mod h1:QBgcKiG94tPHAcxeRyNHrfiLGSKtojlRDLGRX5I6LgE= | 40 | code.crute.us/mcrute/golib/vault v0.2.6/go.mod h1:QBgcKiG94tPHAcxeRyNHrfiLGSKtojlRDLGRX5I6LgE= |
41 | code.crute.us/mcrute/golib/web/css v0.1.0 h1:VdP0i2Q+JC+TxiyWTAdqksDcKU4GKwL2Ly02ZRkyDFw= | 41 | code.crute.us/mcrute/golib/web/css v0.1.1 h1:cJ9/fPMPPLzwkMG6Z99SbpAxyknXXEu2ADR5fRG/yTo= |
42 | code.crute.us/mcrute/golib/web/css v0.1.0/go.mod h1:USqoGbYKNDhEVZITLxSxd/vFXBihL8/N3Gg/v01hNWo= | 42 | code.crute.us/mcrute/golib/web/css v0.1.1/go.mod h1:USqoGbYKNDhEVZITLxSxd/vFXBihL8/N3Gg/v01hNWo= |
43 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | 43 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= |
44 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | 44 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
45 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | 45 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= |
@@ -228,6 +228,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ | |||
228 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | 228 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
229 | github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= | 229 | github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
230 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= | 230 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
231 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= | ||
232 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= | ||
231 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= | 233 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |
232 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | 234 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
233 | github.com/hashicorp/vault/api v1.8.0 h1:7765sW1XBt+qf4XKIYE4ebY9qc/yi9V2/egzGSUNMZU= | 235 | github.com/hashicorp/vault/api v1.8.0 h1:7765sW1XBt+qf4XKIYE4ebY9qc/yi9V2/egzGSUNMZU= |
@@ -373,6 +375,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ | |||
373 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | 375 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
374 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | 376 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= |
375 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | 377 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= |
378 | github.com/tdewolff/minify/v2 v2.20.9 h1:0RGsL+jBpm77obkuNCjNZ2eiN81CZzTnjeVmTqxCmYk= | ||
379 | github.com/tdewolff/minify/v2 v2.20.9/go.mod h1:hZnNtFqXVQ5QIAR05tdgvS7h6E80jyRwHSGVmM4jbzQ= | ||
380 | github.com/tdewolff/parse/v2 v2.7.6 h1:PGZH2b/itDSye9RatReRn4GBhsT+KFEMtAMjHRuY1h8= | ||
381 | github.com/tdewolff/parse/v2 v2.7.6/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= | ||
382 | github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA= | ||
383 | github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= | ||
376 | github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= | 384 | github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= |
377 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= | 385 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= |
378 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | 386 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= |
@@ -530,8 +538,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc | |||
530 | golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | 538 | golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
531 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | 539 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
532 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | 540 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
533 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= | 541 | golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= |
534 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | 542 | golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
535 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | 543 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
536 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | 544 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
537 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | 545 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |