You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
4.4 KiB
235 lines
4.4 KiB
package mime
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"go/format"
|
|
"os"
|
|
"path"
|
|
"text/template"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var (
|
|
ErrDuplicate = errors.New("duplicate")
|
|
ErrNotFound = errors.New("not found")
|
|
)
|
|
|
|
const (
|
|
NameExt = "ext"
|
|
NameMime = "mime"
|
|
)
|
|
|
|
type Config struct {
|
|
Source string
|
|
|
|
Mimes []Data `yaml:"mime"`
|
|
MimePrefix string
|
|
MimeTpl string
|
|
MimeResult string
|
|
MimePackage string
|
|
|
|
Extensions []Data `yaml:"ext"`
|
|
ExtPrefix string
|
|
ExtTpl string
|
|
ExtResult 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 {
|
|
return func(c *Config) {
|
|
c.ExtTpl = name
|
|
}
|
|
}
|
|
|
|
func WithExtPacakge(name string) Option {
|
|
return func(c *Config) {
|
|
c.ExtPackage = name
|
|
}
|
|
}
|
|
|
|
func WithExtResult(name string) Option {
|
|
return func(c *Config) {
|
|
c.ExtResult = name
|
|
}
|
|
}
|
|
|
|
func WithMimeTpl(name string) Option {
|
|
return func(c *Config) {
|
|
c.MimeTpl = name
|
|
}
|
|
}
|
|
|
|
func WithMimePackage(name string) Option {
|
|
return func(c *Config) {
|
|
c.MimePackage = name
|
|
}
|
|
}
|
|
|
|
func WithMimeResult(name string) Option {
|
|
return func(c *Config) {
|
|
c.MimeResult = name
|
|
}
|
|
}
|
|
|
|
type Option func(*Config)
|
|
|
|
func funcMap() template.FuncMap {
|
|
return template.FuncMap{
|
|
"name": VarName,
|
|
"value": Value,
|
|
}
|
|
}
|
|
|
|
func Generate(fileName string, opts ...Option) error {
|
|
cfg := Config{
|
|
Source: fileName,
|
|
|
|
ExtPrefix: "Ext",
|
|
ExtTpl: "mime/tpl/extension.text.tmpl",
|
|
ExtResult: "extension.go",
|
|
ExtPackage: "mime",
|
|
|
|
MimeTpl: "mime/tpl/mime.text.tmpl",
|
|
MimePrefix: "",
|
|
MimeResult: "mime.go",
|
|
MimePackage: "mime",
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(&cfg)
|
|
}
|
|
|
|
data, cerr := os.ReadFile(fileName)
|
|
if cerr != nil {
|
|
return fmt.Errorf("read file:%w", cerr)
|
|
}
|
|
|
|
if uerr := yaml.Unmarshal(data, &cfg); uerr != nil {
|
|
return fmt.Errorf("unmarshal:%w", uerr)
|
|
}
|
|
|
|
if validErr := cfg.ValidateAndFillExt(); validErr != nil {
|
|
return fmt.Errorf("config:%w", validErr)
|
|
}
|
|
|
|
template, err := template.New("mimes").Funcs(funcMap()).ParseFiles(cfg.ExtTpl, cfg.MimeTpl)
|
|
if err != nil {
|
|
return fmt.Errorf("ext template:%w", err)
|
|
}
|
|
|
|
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 {
|
|
return fmt.Errorf("ext file:%w", err)
|
|
}
|
|
|
|
if exErr := tpl.ExecuteTemplate(extFile, cfg.Base(name), cfg); exErr != nil {
|
|
return fmt.Errorf("ext execute:%w", exErr)
|
|
}
|
|
|
|
if formatErr := Format(extFile.Name()); formatErr != nil {
|
|
return fmt.Errorf("format ext:%w", formatErr)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Format file and write it.
|
|
func Format(name string) error {
|
|
in, err := os.ReadFile(name)
|
|
if err != nil {
|
|
return fmt.Errorf("read file:%w", err)
|
|
}
|
|
|
|
out, err := format.Source(in)
|
|
if err != nil {
|
|
return fmt.Errorf("format source:%w", err)
|
|
}
|
|
|
|
file, err := os.Create(name)
|
|
if err != nil {
|
|
return fmt.Errorf("ext file:%w", err)
|
|
}
|
|
|
|
if _, err := file.Write(out); err != nil {
|
|
return fmt.Errorf("write:%w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|