types (#1)
All checks were successful
continuous-integration/drone/push Build is passing

Co-authored-by: andrey1s <andrey@4devs.pro>
Reviewed-on: #1
Co-authored-by: andrey <andrey@4devs.io>
Co-committed-by: andrey <andrey@4devs.io>
This commit was merged in pull request #1.
This commit is contained in:
2022-09-30 10:14:29 +03:00
parent 779846fe9a
commit 8ff25d212d
16 changed files with 25869 additions and 10249 deletions

42
.drone.yml Normal file
View File

@@ -0,0 +1,42 @@
kind: pipeline
name: default
steps:
- name: golangci-lint
image: golangci/golangci-lint:v1.49
volumes:
- name: deps
path: /go/src/mod
commands:
- golangci-lint run --timeout 5m
- name: test
image: golang
volumes:
- name: deps
path: /go/src/mod
commands:
- go test ./...
- name: scripts golangci-lint
image: golangci/golangci-lint:v1.49
volumes:
- name: deps
path: /go/src/mod
commands:
- cd scripts
- golangci-lint run --timeout 5m
- name: scripts test
image: golang
volumes:
- name: deps
path: /go/src/mod
commands:
- cd scripts
- go test ./...
volumes:
- name: deps
temp: {}

43
.golangci.yml Normal file
View File

@@ -0,0 +1,43 @@
linters-settings:
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
goconst:
min-len: 2
min-occurrences: 2
gocyclo:
min-complexity: 15
golint:
min-confidence: 0
govet:
check-shadowing: true
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
varnamelen:
min-name-length: 2
linters:
enable-all: true
disable:
- varcheck
- maligned
- scopelint
- nosnakecase
- ifshort
- golint
- interfacer
- structcheck
- deadcode
- exhaustivestruct
- exhaustruct
# is disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649
- rowserrcheck
- sqlclosecheck
- wastedassign

View File

@@ -1,2 +1,3 @@
# mime # mime
[![Build Status](https://drone.gitoa.ru/api/badges/go-4devs/mime/status.svg)](https://drone.gitoa.ru/go-4devs/mime)

17292
extension.go

File diff suppressed because it is too large Load Diff

13352
mime.go

File diff suppressed because it is too large Load Diff

1666
mime.json

File diff suppressed because it is too large Load Diff

3394
mime.yaml Normal file

File diff suppressed because it is too large Load Diff

36
mime_example_test.go Normal file
View File

@@ -0,0 +1,36 @@
package mime_test
import (
"fmt"
"gitoa.ru/go-4devs/mime"
)
func ExampleMime_String() {
fmt.Printf("%v", mime.TextHTML)
// Output:
// text/html
}
func ExampleMime_Is() {
fmt.Printf("%v\n%v",
mime.TextHTML.Is(mime.ApplicationJSON, mime.ApplicationJavascript),
mime.TextHTML.Is(mime.ApplicationJavascript, mime.TextHTML),
)
// Output:
// false
// true
}
func ExampleMime_ExtTypes() {
fmt.Printf("%v\n%v",
mime.TextHTML.ExtTypes(),
mime.ApplicationJavascript.ExtTypes(),
)
// Output:
// [html htm shtml]
// [js mjs jsm]
}

View File

@@ -27,7 +27,7 @@ func Mime() *console.Command {
Name: "mime", Name: "mime",
Description: "generate mime from file", Description: "generate mime from file",
Configure: func(ctx context.Context, cfg *input.Definition) error { Configure: func(ctx context.Context, cfg *input.Definition) error {
cfg.SetArgument(ArgFile, "file", argument.Required) cfg.SetArgument(ArgFile, "yaml file", argument.Required)
cfg.SetOptions( cfg.SetOptions(
option.String(OptExtTpl, "extension template", option.Default("mime/tpl/extension.text.tmpl")), option.String(OptExtTpl, "extension template", option.Default("mime/tpl/extension.text.tmpl")),
option.String(OptExtPackage, "extension package", option.Default("mime")), option.String(OptExtPackage, "extension package", option.Default("mime")),

View File

@@ -6,4 +6,5 @@ require (
github.com/achiku/varfmt v0.0.0-20160708124000-f820e1efecee github.com/achiku/varfmt v0.0.0-20160708124000-f820e1efecee
gitoa.ru/go-4devs/closer v0.1.1 gitoa.ru/go-4devs/closer v0.1.1
gitoa.ru/go-4devs/console v0.1.2 gitoa.ru/go-4devs/console v0.1.2
gopkg.in/yaml.v3 v3.0.1
) )

View File

@@ -3,8 +3,10 @@ github.com/achiku/varfmt v0.0.0-20160708124000-f820e1efecee/go.mod h1:RKS7P4TSY/
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -18,6 +20,7 @@ gitoa.ru/go-4devs/closer v0.1.1/go.mod h1:S+QAdgSt4CVLH3v3YZK1Mukl7SVn2Z0CYj0oJQ
gitoa.ru/go-4devs/console v0.1.2 h1:SsQWLSClXFwWFseH6CGKQfmCtG84aHOiaFHG3oZlJ8s= gitoa.ru/go-4devs/console v0.1.2 h1:SsQWLSClXFwWFseH6CGKQfmCtG84aHOiaFHG3oZlJ8s=
gitoa.ru/go-4devs/console v0.1.2/go.mod h1:ddqmjQ0yr9v+oa5E3Bu3X/SUcws/ENR5f5cz1g5fHbk= gitoa.ru/go-4devs/console v0.1.2/go.mod h1:ddqmjQ0yr9v+oa5E3Bu3X/SUcws/ENR5f5cz1g5fHbk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -11,8 +11,10 @@ import (
func main() { func main() {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
closer.AddLast(func() error { closer.AddLast(func() error {
cancel() cancel()
return nil return nil
}) })

View File

@@ -1,31 +1,105 @@
package mime package mime
import ( import (
"encoding/json" "errors"
"fmt" "fmt"
"go/format" "go/format"
"io/ioutil"
"os" "os"
"path" "path"
"text/template" "text/template"
"gopkg.in/yaml.v3"
)
var (
ErrDuplicate = errors.New("duplicate")
ErrNotFound = errors.New("not found")
)
const (
NameExt = "ext"
NameMime = "mime"
) )
type Config struct { type Config struct {
Source string Source string
Mimes map[string][]string Mimes []Data `yaml:"mime"`
MimePrefix string MimePrefix string
MimeTpl string MimeTpl string
MimeResult string MimeResult string
MimePackage string MimePackage string
Extensions map[string][]string Extensions []Data `yaml:"ext"`
ExtPrefix string ExtPrefix string
ExtTpl string ExtTpl string
ExtResult string ExtResult string
ExtPackage string ExtPackage string
} }
type Data struct {
Name string `yaml:"name"`
ID int `yaml:"id"`
Value []string `yaml:"value,omitempty"`
}
func (c *Config) Base(name string) string {
switch name {
case NameExt:
return path.Base(c.ExtTpl)
case NameMime:
return path.Base(c.MimeTpl)
}
return ""
}
func (c *Config) Result(name string) string {
switch name {
case NameExt:
return c.ExtResult
case NameMime:
return c.MimeResult
}
return ""
}
func (c *Config) ValidateAndFillExt() error {
mimes := make(map[string]int)
mimeIDs := make(map[int]string)
extIndex := make(map[string]int)
for idx, ext := range c.Extensions {
if _, ok := extIndex[ext.Name]; ok {
return fmt.Errorf("extension %v %w: with id %v", ext.Name, ErrDuplicate, c.Extensions[extIndex[ext.Name]].ID)
}
extIndex[ext.Name] = idx
}
for _, mime := range c.Mimes {
if _, ok := mimes[mime.Name]; ok {
return fmt.Errorf("mime %v %w: with id %v", mime.Name, ErrDuplicate, mimes[mime.Name])
}
if _, ok := mimeIDs[mime.ID]; ok {
return fmt.Errorf("ID %v %w: with name %v", mime.ID, ErrDuplicate, mimeIDs[mime.ID])
}
for _, ext := range mime.Value {
idx, ok := extIndex[ext]
if !ok {
return fmt.Errorf("%w ext by %v", ErrNotFound, mime.Name)
}
c.Extensions[idx].Value = append(c.Extensions[idx].Value, mime.Name)
}
}
return nil
}
func WithExtTpl(name string) Option { func WithExtTpl(name string) Option {
return func(c *Config) { return func(c *Config) {
c.ExtTpl = name c.ExtTpl = name
@@ -78,11 +152,9 @@ func Generate(fileName string, opts ...Option) error {
ExtPrefix: "Ext", ExtPrefix: "Ext",
ExtTpl: "mime/tpl/extension.text.tmpl", ExtTpl: "mime/tpl/extension.text.tmpl",
ExtResult: "extension.go", ExtResult: "extension.go",
Extensions: make(map[string][]string),
ExtPackage: "mime", ExtPackage: "mime",
MimeTpl: "mime/tpl/mime.text.tmpl", MimeTpl: "mime/tpl/mime.text.tmpl",
Mimes: make(map[string][]string),
MimePrefix: "", MimePrefix: "",
MimeResult: "mime.go", MimeResult: "mime.go",
MimePackage: "mime", MimePackage: "mime",
@@ -92,46 +164,47 @@ func Generate(fileName string, opts ...Option) error {
opt(&cfg) opt(&cfg)
} }
data, err := os.ReadFile(fileName) data, cerr := os.ReadFile(fileName)
if err != nil { if cerr != nil {
return fmt.Errorf("read file:%w", err) return fmt.Errorf("read file:%w", cerr)
} }
if err := json.Unmarshal(data, &cfg.Mimes); err != nil { if uerr := yaml.Unmarshal(data, &cfg); uerr != nil {
return fmt.Errorf("unmarshal:%w", err) return fmt.Errorf("unmarshal:%w", uerr)
} }
cfg.Extensions = extensions(cfg.Mimes) if validErr := cfg.ValidateAndFillExt(); validErr != nil {
return fmt.Errorf("config:%w", validErr)
}
template, err := template.New("mimes").Funcs(funcMap()).ParseFiles(cfg.ExtTpl, cfg.MimeTpl) template, err := template.New("mimes").Funcs(funcMap()).ParseFiles(cfg.ExtTpl, cfg.MimeTpl)
if err != nil { if err != nil {
return fmt.Errorf("ext template:%w", err) return fmt.Errorf("ext template:%w", err)
} }
extFile, err := os.Create(cfg.ExtResult) if exErr := Create(template, NameExt, cfg); exErr != nil {
return fmt.Errorf("ext create:%w", exErr)
}
if mimeErr := Create(template, NameMime, cfg); mimeErr != nil {
return fmt.Errorf("mime create:%w", mimeErr)
}
return nil
}
func Create(tpl *template.Template, name string, cfg Config) error {
extFile, err := os.Create(cfg.Result(name))
if err != nil { if err != nil {
return fmt.Errorf("ext file:%w", err) return fmt.Errorf("ext file:%w", err)
} }
if err := template.ExecuteTemplate(extFile, path.Base(cfg.ExtTpl), cfg); err != nil { if exErr := tpl.ExecuteTemplate(extFile, cfg.Base(name), cfg); exErr != nil {
return fmt.Errorf("ext execute:%w", err) return fmt.Errorf("ext execute:%w", exErr)
} }
if err := Format(extFile.Name()); err != nil { if formatErr := Format(extFile.Name()); formatErr != nil {
return fmt.Errorf("format ext:%w", err) return fmt.Errorf("format ext:%w", formatErr)
}
mimeFile, err := os.Create(cfg.MimeResult)
if err != nil {
return fmt.Errorf("mime file:%w", err)
}
if err := template.ExecuteTemplate(mimeFile, path.Base(cfg.MimeTpl), cfg); err != nil {
return fmt.Errorf("mime execute:%w", err)
}
if err := Format(mimeFile.Name()); err != nil {
return fmt.Errorf("format mime:%w", err)
} }
return nil return nil
@@ -139,13 +212,14 @@ func Generate(fileName string, opts ...Option) error {
// Format file and write it. // Format file and write it.
func Format(name string) error { func Format(name string) error {
in, err := ioutil.ReadFile(name) in, err := os.ReadFile(name)
if err != nil { if err != nil {
return err return fmt.Errorf("read file:%w", err)
} }
out, err := format.Source(in) out, err := format.Source(in)
if err != nil { if err != nil {
return err return fmt.Errorf("format source:%w", err)
} }
file, err := os.Create(name) file, err := os.Create(name)
@@ -159,19 +233,3 @@ func Format(name string) error {
return nil return nil
} }
func extensions(mimes map[string][]string) map[string][]string {
out := make(map[string][]string)
for mime, exts := range mimes {
for _, ext := range exts {
if _, ok := out[ext]; ok {
out[ext] = append(out[ext], mime)
continue
}
out[ext] = []string{ext}
}
}
return out
}

View File

@@ -1,19 +1,58 @@
// Code generated by gitoa.ru/go-4devs/mime and sourse {{.Source}} // Code generated by gitoa.ru/go-4devs/mime and sourse {{.Source}}
package {{.ExtPackage}} package {{.ExtPackage}}
const ( import "fmt"
{{- range $key, $value := .Extensions }}
{{ name $.ExtPrefix $key }} = "{{ $key }}"
{{- end}}
)
func Mime(name string) []string { type Ext int
switch name {
{{- range $key, $value := .Extensions }} type ExtTypes []Ext
case {{ name $.ExtPrefix $key }}:
return {{ value $value }} func (v Ext) Is(types ...Ext) bool {
for _, ext := range types {
if ext == v {
return true
}
}
return false
}
func (v Ext) String() string {
switch v {
{{- range $value := .Extensions }}
case {{ name $.ExtPrefix $value.Name }}:
return "{{- $value.Name -}}"
{{- end}}
}
return fmt.Sprintf("Ext(%d)",v)
}
func (v Ext) MimeTypes() MimeTypes{
switch v {
{{- range $value := .Extensions }}
case {{ name $.ExtPrefix $value.Name }}:
return MimeTypes{ {{- value $.MimePrefix $value.Value -}} }
{{- end}} {{- end}}
} }
return nil return nil
} }
const (
{{- range $value := .Extensions }}
{{ name $.ExtPrefix $value.Name }} Ext = {{ $value.ID }}
{{- end}}
)
func ExtFromString(name string) Ext {
switch name {
{{- range $value := .Extensions }}
case "{{- $value.Name -}}":
return {{ name $.ExtPrefix $value.Name }}
{{- end}}
}
return 0
}

View File

@@ -1,19 +1,57 @@
// Code generated by gitoa.ru/go-4devs/mime and sourse {{.Source}} // Code generated by gitoa.ru/go-4devs/mime and sourse {{.Source}}
package {{.MimePackage}} package {{.MimePackage}}
const ( import "fmt"
{{- range $key, $value := .Mimes }}
{{ name $.MimePrefix $key }} = "{{ $key }}"
{{- end}}
)
func Extension(name string) []string { type Mime int
switch name {
{{- range $key, $value := .Mimes }} type MimeTypes []Mime
case {{ name $.MimePrefix $key }}:
return {{ value $value }} func (v Mime) Is(types ...Mime) bool {
for _, mime := range types {
if mime == v {
return true
}
}
return false
}
func (v Mime) String() string {
switch v {
{{- range $value := .Mimes }}
case {{ name $.MimePrefix $value.Name }}:
return "{{- $value.Name -}}"
{{- end}}
}
return fmt.Sprintf("Mime(%d)",v)
}
func (v Mime) ExtTypes() ExtTypes{
switch v {
{{- range $value := .Mimes }}
case {{ name $.MimePrefix $value.Name }}:
return []Ext{ {{- value $.ExtPrefix $value.Value -}} }
{{- end}} {{- end}}
} }
return nil return nil
} }
const (
{{- range $value := .Mimes }}
{{ name $.MimePrefix $value.Name }} Mime = {{ $value.ID }}
{{- end}}
)
func MimeFromString(name string) Mime {
switch name {
{{- range $value := .Mimes }}
case "{{- $value.Name -}}":
return {{ name $.MimePrefix $value.Name }}
{{- end}}
}
return 0
}

View File

@@ -1,7 +1,7 @@
package mime package mime
import ( import (
"fmt" "bytes"
"strings" "strings"
"unicode" "unicode"
@@ -27,6 +27,11 @@ func VarName(prefix, name string) string {
return varfmt.PublicVarName(prefix + "_" + name) return varfmt.PublicVarName(prefix + "_" + name)
} }
func Value(val []string) string { func Value(prefix string, val []string) string {
return fmt.Sprintf("%#v", val) var out bytes.Buffer
for _, name := range val {
out.WriteString(VarName(prefix, name) + ",")
}
return out.String()
} }