Skip to content

Commit

Permalink
Merge pull request #134 from alexj212/master
Browse files Browse the repository at this point in the history
updated exec - copy command for include and exclude patterns
  • Loading branch information
alexj212 authored Aug 4, 2020
2 parents a35317d + 2574c97 commit 299c760
Show file tree
Hide file tree
Showing 16 changed files with 634 additions and 119 deletions.
22 changes: 18 additions & 4 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion _test/dbmeta/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func init() {
goopt.Description = func() string {
return "ORM and RESTful meta data viewer for SQl databases"
}
goopt.Version = "v0.9.26 (07/31/2020)"
goopt.Version = "v0.9.27 (08/04/2020)"
goopt.Summary = `dbmeta [-v] --sqltype=mysql --connstr "user:password@/dbname" --database <databaseName>
sqltype - sql database type such as [ mysql, mssql, postgres, sqlite, etc. ]
Expand Down
4 changes: 2 additions & 2 deletions code_http.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func GetInvoices(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// @Failure 400 {object} api.HTTPError
// @Failure 404 {object} api.HTTPError
// @Router /invoices [post]
// echo '{"billing_state": "USFzllBypZZJDjtbuDWBnWcrU","billing_country": "KgrvVzwkLcFjnchqPwVoHWkRT","billing_postal_code": "ScJIRKwUTRltasmLeQNMLxJYS","total": 0.03391519763659607,"customer_id": 66,"invoice_date": "2123-11-18T21:39:12.15674111-08:00","billing_address": "nPoieNSaqVDVMBQvfwSXcYdtM","billing_city": "ObTQBQeAscRjOcAkHOOKmkHXU","invoice_id": 7}' | http POST "http://127.0.0.1:8080/invoices" X-Api-User:user123
// echo '{"billing_state": "ZDIUXoQexYEYgpaYJgyitZpjS","billing_country": "xbuWQjVGOCsrKSXCJhxeVSFhQ","billing_postal_code": "fEHjgTFVSOwVZEPNUjpVkmOZV","customer_id": 40,"invoice_date": "2021-12-17T01:29:16.603984343-08:00","billing_address": "GoPOJOqToKgHAXoCRwOLzSsgW","billing_city": "pRhdTdgdcpgiBrgvmCMlFKapm","total": 0.38248355155004915,"invoice_id": 46}' | http POST "http://127.0.0.1:8080/invoices" X-Api-User:user123
func AddInvoices(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
ctx := initializeContext(r)
invoices := &model.Invoices{}
Expand Down Expand Up @@ -192,7 +192,7 @@ func AddInvoices(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// @Failure 400 {object} api.HTTPError
// @Failure 404 {object} api.HTTPError
// @Router /invoices/{argInvoiceID} [put]
// echo '{"billing_state": "USFzllBypZZJDjtbuDWBnWcrU","billing_country": "KgrvVzwkLcFjnchqPwVoHWkRT","billing_postal_code": "ScJIRKwUTRltasmLeQNMLxJYS","total": 0.03391519763659607,"customer_id": 66,"invoice_date": "2123-11-18T21:39:12.15674111-08:00","billing_address": "nPoieNSaqVDVMBQvfwSXcYdtM","billing_city": "ObTQBQeAscRjOcAkHOOKmkHXU","invoice_id": 7}' | http PUT "http://127.0.0.1:8080/invoices/1" X-Api-User:user123
// echo '{"billing_state": "ZDIUXoQexYEYgpaYJgyitZpjS","billing_country": "xbuWQjVGOCsrKSXCJhxeVSFhQ","billing_postal_code": "fEHjgTFVSOwVZEPNUjpVkmOZV","customer_id": 40,"invoice_date": "2021-12-17T01:29:16.603984343-08:00","billing_address": "GoPOJOqToKgHAXoCRwOLzSsgW","billing_city": "pRhdTdgdcpgiBrgvmCMlFKapm","total": 0.38248355155004915,"invoice_id": 46}' | http PUT "http://127.0.0.1:8080/invoices/1" X-Api-User:user123
func UpdateInvoices(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
ctx := initializeContext(r)

Expand Down
267 changes: 233 additions & 34 deletions dbmeta/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"encoding/csv"
"encoding/json"
"fmt"
"github.com/smallnest/gen/utils"
"time"

"go/format"
"io/ioutil"
"os"
Expand All @@ -19,6 +22,7 @@ import (
"github.com/serenize/snaker"
)

// GenTemplate template info struct
type GenTemplate struct {
Name string
Content string
Expand Down Expand Up @@ -111,10 +115,11 @@ func (c *Config) GetTemplate(genTemplate *GenTemplate) (*template.Template, erro
"replace": replace,
"hasField": hasField,
"FmtFieldName": FmtFieldName,
"copy": FileSystemCopy,
"mkdir": Mkdir,
"touch": Touch,
"copy": c.FileSystemCopy,
"mkdir": c.Mkdir,
"touch": c.Touch,
"pwd": Pwd,
"config": c.DisplayConfig,
}

baseName := filepath.Base(genTemplate.Name)
Expand Down Expand Up @@ -376,12 +381,12 @@ func (c *Config) JSONTagOmitEmpty(name string) string {
}

// GenerateTableFile generate file from template using specific table used within templates
func (c *Config) GenerateTableFile(tableInfos map[string]*ModelInfo, tableName, templateFilename, outputDirectory, outputFileName string, formatOutput bool) string {
func (c *Config) GenerateTableFile(tableName, templateFilename, outputDirectory, outputFileName string) string {
buf := bytes.Buffer{}

buf.WriteString(fmt.Sprintf("GenerateTableFile( %s, %s, %s, %s, %t)\n", tableName, templateFilename, outputDirectory, outputFileName, formatOutput))
buf.WriteString(fmt.Sprintf("GenerateTableFile( %s, %s, %s, %)\n", tableName, templateFilename, outputDirectory, outputFileName))

tableInfo, ok := tableInfos[tableName]
tableInfo, ok := c.TableInfos[tableName]
if !ok {
buf.WriteString(fmt.Sprintf("Table: %s - No tableInfo found\n", tableName))
return buf.String()
Expand Down Expand Up @@ -409,7 +414,7 @@ func (c *Config) GenerateTableFile(tableInfos map[string]*ModelInfo, tableName,

outputFile := filepath.Join(fileOutDir, outputFileName)
buf.WriteString(fmt.Sprintf("Writing %s -> %s\n", templateFilename, outputFile))
err = c.WriteTemplate(tpl, data, outputFile, formatOutput)
err = c.WriteTemplate(tpl, data, outputFile)
return buf.String()
}

Expand Down Expand Up @@ -458,7 +463,9 @@ func (c *Config) CreateContextForTableFile(tableInfo *ModelInfo) map[string]inte
}

// WriteTemplate write a template out
func (c *Config) WriteTemplate(genTemplate *GenTemplate, data map[string]interface{}, outputFile string, formatOutput bool) error {
func (c *Config) WriteTemplate(genTemplate *GenTemplate, data map[string]interface{}, outputFile string) error {
//fmt.Printf("WriteTemplate %s\n", outputFile)

if !c.Overwrite && Exists(outputFile) {
fmt.Printf("not overwriting %s\n", outputFile)
return nil
Expand All @@ -468,6 +475,13 @@ func (c *Config) WriteTemplate(genTemplate *GenTemplate, data map[string]interfa
data[key] = value
}

dir := filepath.Dir(outputFile)
parent := filepath.Base(dir)

data["File"] = outputFile
data["Dir"] = dir
data["Parent"] = parent

data["DatabaseName"] = c.SQLDatabase
data["module"] = c.Module

Expand All @@ -492,43 +506,50 @@ func (c *Config) WriteTemplate(genTemplate *GenTemplate, data map[string]interfa

rt, err := c.GetTemplate(genTemplate)
if err != nil {
return fmt.Errorf("Error in loading %s template, error: %v\n", genTemplate.Name, err)
return fmt.Errorf("error in loading %s template, error: %v", genTemplate.Name, err)
}
var buf bytes.Buffer
err = rt.Execute(&buf, data)
if err != nil {
return fmt.Errorf("Error in rendering %s: %s\n", genTemplate.Name, err.Error())
return fmt.Errorf("error in rendering %s: %s", genTemplate.Name, err.Error())
}

fileContents, err := c.format(genTemplate, buf.Bytes(), outputFile)
if err != nil {
return fmt.Errorf("error writing %s - error: %v", outputFile, err)
}

if formatOutput {
formattedSource, err := format.Source(buf.Bytes())
err = ioutil.WriteFile(outputFile, fileContents, 0777)
if err != nil {
return fmt.Errorf("error writing %s - error: %v", outputFile, err)
}

if c.Verbose {
fmt.Printf("writing %s\n", outputFile)
}
return nil
}

func (c *Config) format(genTemplate *GenTemplate, content []byte, outputFile string) ([]byte, error) {
extension := filepath.Ext(outputFile)
if extension == ".go" {
formattedSource, err := format.Source([]byte(content))
if err != nil {
return fmt.Errorf("Error in formatting template: %s outputfile: %s source: %s\n", genTemplate.Name, outputFile, err.Error())
return nil, fmt.Errorf("error in formatting template: %s outputfile: %s source: %s", genTemplate.Name, outputFile, err.Error())
}

fileContents := NormalizeNewlines(formattedSource)
if c.LineEndingCRLF {
fileContents = CRLFNewlines(formattedSource)
}

err = ioutil.WriteFile(outputFile, fileContents, 0777)
} else {
fileContents := NormalizeNewlines(buf.Bytes())
if c.LineEndingCRLF {
fileContents = CRLFNewlines(fileContents)
}

err = ioutil.WriteFile(outputFile, fileContents, 0777)
return fileContents, nil
}

if err != nil {
return fmt.Errorf("error writing %s - error: %v\n", outputFile, err)
fileContents := NormalizeNewlines([]byte(content))
if c.LineEndingCRLF {
fileContents = CRLFNewlines(fileContents)
}

if c.Verbose {
fmt.Printf("writing %s\n", outputFile)
}
return nil
return fileContents, nil
}

// NormalizeNewlines normalizes \r\n (windows) and \r (mac)
Expand Down Expand Up @@ -559,7 +580,7 @@ func Exists(name string) bool {
}

// GenerateFile generate file from template, non table used within templates
func (c *Config) GenerateFile(templateFilename, outputDirectory, outputFileName string, formatOutput bool, overwrite bool) string {
func (c *Config) GenerateFile(templateFilename, outputDirectory, outputFileName string, overwrite bool) string {
buf := bytes.Buffer{}
buf.WriteString(fmt.Sprintf("GenerateFile( %s, %s, %s)\n", templateFilename, outputDirectory, outputFileName))
fileOutDir := outputDirectory
Expand All @@ -579,13 +600,191 @@ func (c *Config) GenerateFile(templateFilename, outputDirectory, outputFileName

outputFile := filepath.Join(fileOutDir, outputFileName)
buf.WriteString(fmt.Sprintf("Writing %s -> %s\n", templateFilename, outputFile))
err = c.WriteTemplate(tpl, data, outputFile, formatOutput)
err = c.WriteTemplate(tpl, data, outputFile)
if err != nil {
buf.WriteString(fmt.Sprintf("Error calling WriteTemplate %s -> %v\n", templateFilename, err))
}
return buf.String()
}

// DisplayConfig display config info
func (c *Config) DisplayConfig() string {

info := fmt.Sprintf(
`DisplayConfig
SQLType : %s
SQLConnStr : %s
SQLDatabase : %s
Module : %s
OutDir : %s
`, c.SQLType, c.SQLConnStr, c.SQLDatabase, c.Module, c.OutDir)

return info
}

type copyRules struct {
result bool
pattern string
r *regexp.Regexp
}

// FileSystemCopy template command to copy files, directories and to pass --include XXX and --exclude YYY regular expressions. Files ending in .tmpl will be processed as a template.
// Files ending in .table.tmpl will be processed as a template iterating through all the tables
func (c *Config) FileSystemCopy(src, dst string, options ...string) string {
dstDir := filepath.Join(c.OutDir, dst)

patterns := make([]*copyRules, 0)

for _, o := range options {

if strings.HasPrefix(o, "--exclude ") {
pattern := o[len("--exclude "):]
r, _ := regexp.Compile(pattern)
if r != nil {
patterns = append(patterns, &copyRules{result: false, r: r, pattern: pattern})
}
}

if strings.HasPrefix(o, "--include ") {
pattern := o[len("--include "):]
r, _ := regexp.Compile(pattern)
if r != nil {
patterns = append(patterns, &copyRules{result: true, r: r, pattern: pattern})
}
}
}

opt := utils.DefaultCopyOptions()

opt.ShouldCopy = func(info os.FileInfo) bool {
name := info.Name()

for _, r := range patterns {
if r.r.Match([]byte(name)) {
//fmt.Printf("copy ShouldCopy %s pattern: [%s] result: %t\n", name, r.pattern, r.result)
return r.result
}
}

return true
}

opt.FileHandler = func(src, dest string, info os.FileInfo) utils.FileHandlerFunc {

if !opt.ShouldCopy(info) {
return func(src, dest string, info os.FileInfo, opt utils.Options, results *utils.Results) (err error) {
results.Info.WriteString(fmt.Sprintf("CopyFile Skipping %s\n", src))
return nil
}
}

if strings.HasSuffix(src, ".table.tmpl") {
//fmt.Printf("@@ HandleTableTemplateFile: src: %s dest: %s Name: %s\n", src, dest, info.Name())
return c.tableFileHandlerFunc
}
if strings.HasSuffix(src, ".tmpl") {
//fmt.Printf("@@ HandleTemplateFile: src: %s dest: %s Name: %s\n", src, dest, info.Name())
return c.fileHandlerFunc
}

return func(src, dest string, info os.FileInfo, opt utils.Options, results *utils.Results) (err error) {
results.Info.WriteString(fmt.Sprintf("CopyFile %s\n", dest))
return utils.DefaultFileCopy(src, dest, info, opt, results)
}
}

result, err := utils.Copy(src, dstDir, opt)
if err != nil {
return fmt.Sprintf("copy returned an error %v", err)
}
return fmt.Sprintf("copy %s %s\n%s\n", src, dstDir, result.String())
}

// Mkdir template command to mkdir under the output directory
func (c *Config) Mkdir(dst string) string {
dstDir := filepath.Join(c.OutDir, dst)

err := os.MkdirAll(dstDir, os.ModePerm)
if err != nil {
return fmt.Sprintf("mkdir returned an error %v", err)

}
return fmt.Sprintf("mkdir %s", dstDir)
}

// Touch template command to touch a file under the output directory
func (c *Config) Touch(dst string) string {
dstDir := filepath.Join(c.OutDir, dst)

_, err := os.Stat(dstDir)
if os.IsNotExist(err) {
file, err := os.Create(dstDir)
if err != nil {
return fmt.Sprintf("touch returned an error %v", err)
}
defer file.Close()
} else {
currentTime := time.Now().Local()
err = os.Chtimes(dstDir, currentTime, currentTime)
if err != nil {
return fmt.Sprintf("touch returned an error %v", err)
}
}
return fmt.Sprintf("touch %s", dstDir)
}

// ".tmpl"
func (c *Config) fileHandlerFunc(src, dest string, info os.FileInfo, opt utils.Options, results *utils.Results) (err error) {
genTemplate := &GenTemplate{
Name: info.Name(),
Content: loadFile(src),
}

data := make(map[string]interface{})

outputFile := dest[0 : len(dest)-5]
results.Info.WriteString(fmt.Sprintf("WriteTemplate %s\n", outputFile))
return c.WriteTemplate(genTemplate, data, outputFile)
}

// ".table.tmpl"
func (c *Config) tableFileHandlerFunc(src, dest string, info os.FileInfo, opt utils.Options, results *utils.Results) (err error) {
genTemplate := &GenTemplate{
Name: info.Name(),
Content: loadFile(src),
}

outputFile := dest[0 : len(dest)-11]

dir := filepath.Dir(outputFile)
tmplateName := filepath.Base(outputFile)
// parent := filepath.Base(dir)
results.Info.WriteString(fmt.Sprintf("WriteTableTemplate %s\n", src))

for tableName, tableInfo := range c.TableInfos {
data := c.CreateContextForTableFile(tableInfo)
// fileName := filepath.Join(dir, tableName+name)
name := c.ReplaceFileNamingTemplate(tableName) + filepath.Ext(tmplateName)
fileName := filepath.Join(dir, name)
results.Info.WriteString(fmt.Sprintf(" table: %-25s %s\n", tableName, fileName))
c.WriteTemplate(genTemplate, data, fileName)
}
return nil
}

func loadFile(src string) string {
// Read entire file content, giving us little control but
// making it very simple. No need to close the file.
content, err := ioutil.ReadFile(src)
if err != nil {
return fmt.Sprintf("error loading %s error: %v", src, err)
}

// Convert []byte to string and print to screen
text := string(content)
return text
}

// SwaggerInfoDetails swagger details
type SwaggerInfoDetails struct {
Version string
Expand Down Expand Up @@ -637,9 +836,9 @@ type Config struct {
FileNamingTemplate string
ModelNamingTemplate string
FieldNamingTemplate string
string
ContextMap map[string]interface{}
TemplateLoader TemplateLoader
ContextMap map[string]interface{}
TemplateLoader TemplateLoader
TableInfos map[string]*ModelInfo
}

// NewConfig create a new code config
Expand Down
Loading

0 comments on commit 299c760

Please sign in to comment.