github.com/ppphp/yayagf@v0.0.1/internal/file/file.go (about)

     1  package file
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/ppphp/yayagf/internal/blueprint"
    13  	"github.com/ppphp/yayagf/internal/command"
    14  	"github.com/ppphp/yayagf/internal/log"
    15  	"github.com/ppphp/yayagf/internal/swagger"
    16  )
    17  
    18  var ErrNoRoot = errors.New("cannot find root")
    19  
    20  func GetAppRoot() (string, error) {
    21  	pwd, err := os.Getwd()
    22  	if err != nil {
    23  		return "", err
    24  	}
    25  	return FindAppRoot(pwd)
    26  }
    27  
    28  // find dir contains go.mod
    29  func FindAppRoot(path string) (string, error) {
    30  	if _, err := os.Open(filepath.Join(path, "go.mod")); os.IsNotExist(err) {
    31  		if path != "/" {
    32  			return FindAppRoot(filepath.Dir(path))
    33  		} else {
    34  			return "", errors.New("no project, sb")
    35  		}
    36  	} else if err != nil {
    37  		return "", err
    38  	} else {
    39  		return path, nil
    40  	}
    41  }
    42  
    43  var goModRegexp = regexp.MustCompile("^module (.+)$")
    44  
    45  // 不看源码了,internal没法直接import,意思意思得了
    46  func GetMod(path string) (string, error) {
    47  	root, err := FindAppRoot(path)
    48  	if err != nil {
    49  		return "", err
    50  	}
    51  	file, err := ioutil.ReadFile(filepath.Join(root, "go.mod"))
    52  	if err != nil {
    53  		return "", err
    54  	}
    55  	for _, line := range strings.Split(string(file), "\n") {
    56  		if goModRegexp.MatchString(line) {
    57  			return goModRegexp.FindAllStringSubmatch(line, -1)[0][1], nil
    58  		}
    59  	}
    60  	return "", errors.New("no error")
    61  }
    62  
    63  type ProjectInfo struct {
    64  	// 项目根文件夹,全称
    65  	Root string
    66  	// 项目模块名
    67  	Mod string
    68  	// 项目bin的名称
    69  	BinName string
    70  }
    71  
    72  func GetProjectInfo() ProjectInfo {
    73  	root, _ := GetAppRoot()
    74  	mod, _ := GetMod(root)
    75  	return ProjectInfo{
    76  		Root:    root,
    77  		Mod:     mod,
    78  		BinName: filepath.Base(root),
    79  	}
    80  }
    81  
    82  func ExtractMod(arg1 string) (string, string, string) {
    83  	namespace, name := filepath.Split(arg1)
    84  	mod := filepath.Join(namespace, name)
    85  	return mod, namespace, name
    86  }
    87  
    88  func InitProject(mod, dir, name string) (int, error) {
    89  	log.Printf("init project")
    90  	if err, o, e := command.DoCommand("go", "mod", "init", mod); err != nil {
    91  		log.Errorf("go mod failed %v %v\n", o, e)
    92  		return 1, err
    93  	}
    94  
    95  	log.Printf("create %v", filepath.Join(dir, "main.go"))
    96  	if err := blueprint.WriteFileWithTmpl(filepath.Join(dir, "main.go"), MainGo, struct{ Mod string }{mod}); err != nil {
    97  		log.Println(err.Error())
    98  		return 1, err
    99  	}
   100  	log.Printf("create %v", filepath.Join(dir, "app", "router", "router.go"))
   101  	if err := blueprint.WriteFileWithTmpl(filepath.Join(dir, "app", "router", "router.go"), RouterGo, nil); err != nil {
   102  		log.Println(err.Error())
   103  		return 1, err
   104  	}
   105  
   106  	if err := blueprint.WriteFileWithTmpl(filepath.Join(dir, "app", "config", "config.go"), ConfigGo, nil); err != nil {
   107  		log.Println(err.Error())
   108  		return 1, err
   109  	}
   110  	if err := blueprint.WriteFileWithTmpl(filepath.Join(dir, "conf.toml"), fmt.Sprintf(`
   111  db=""
   112  port=8080
   113  [log]
   114  filename="./log/%v.log"
   115  level=5
   116  `, name), nil); err != nil {
   117  		log.Println(err.Error())
   118  		return 1, err
   119  	}
   120  
   121  	log.Printf("init swagger")
   122  	root, err := GetAppRoot()
   123  	if err != nil {
   124  		return 1, err
   125  	}
   126  	if err := swagger.GenerateSwagger(root); err != nil {
   127  		log.Errorf("swag failed %v", err)
   128  		return 1, err
   129  	}
   130  
   131  	log.Printf("init git")
   132  	if err, _, errs := command.DoCommand("git", "init"); err != nil {
   133  		log.Errorf("git failed %v", errs)
   134  		return 1, err
   135  	}
   136  	if err := blueprint.WriteFileWithTmpl(filepath.Join(dir, ".gitignore"), `
   137  {{.Name}}
   138  {{.Name}}.tar
   139  *.log
   140  `, struct{ Name string }{name}); err != nil {
   141  		log.Errorf("gitignore failed %v", err)
   142  		return 1, err
   143  	}
   144  
   145  	log.Printf("init docker")
   146  	if err := ioutil.WriteFile(filepath.Join(dir, "Dockerfile"), []byte(fmt.Sprintf(`
   147  FROM golang as back
   148  
   149  ENV GOPROXY=https://goproxy.io
   150  ENV GOSUMDB=off
   151  ENV GOPRIVATE=gitlab.papegames.com/*
   152  ENV CGO_ENABLED=0
   153  ENV GOOS=linux
   154  ENV GOARCH=amd64
   155  ENV GO111MODULE=on
   156  
   157  WORKDIR /main
   158  
   159  ADD go.mod ./
   160  ADD go.sum ./
   161  RUN go mod download
   162  
   163  ADD app ./app/
   164  ADD main.go ./
   165  RUN go build -o /main/main
   166  
   167  FROM scratch
   168  WORKDIR /main
   169  COPY --from=back /main/main .
   170  
   171  CMD ["/main/main"]
   172  
   173  `)), 0644); err != nil {
   174  		log.Errorf("docker failed %v", err)
   175  		return 1, err
   176  	}
   177  
   178  	if err := ioutil.WriteFile(filepath.Join(dir, "README.md"), []byte("\n"), 0644); err != nil {
   179  		log.Errorf("readme failed %v", err)
   180  		return 1, err
   181  	}
   182  	return 0, nil
   183  }
   184  
   185  const (
   186  	MainGo = `package main
   187  
   188  import (
   189  	"fmt"
   190  
   191  	// {{.Mod}}/app/crud"
   192  	"github.com/ppphp/yayagf/pkg/handlers"
   193  	"github.com/ppphp/yayagf/pkg/log"
   194  	"github.com/ppphp/yayagf/pkg/maotai"
   195  	"github.com/ppphp/yayagf/pkg/model"
   196  	"github.com/ppphp/yayagf/pkg/prom"
   197  	"github.com/gin-gonic/gin"
   198  	"{{.Mod}}/app/config"
   199  	"{{.Mod}}/app/doc"
   200  	"{{.Mod}}/app/router"
   201  )
   202  // @title "{{.Mod}} API
   203  // @version master
   204  // @description This is a {{.Mod}} server
   205  
   206  // @contact.name 风车
   207  // @contact.url https://{{.Mod}}
   208  // @contact.email liukaiwen@papegames.net
   209  
   210  // @host localhost:8080
   211  // @BasePath /api/v1
   212  
   213  func main() {
   214  	if err := config.LoadConfig(); err != nil {
   215  		log.Errorf("load config failed (%v)", err)
   216  		return
   217  	}
   218  
   219  	log.Tweak(config.GetConfig().Log)
   220  	gin.DefaultWriter = log.GetLogger().Out
   221  	r := maotai.Default("{{.Mod}}")
   222  	router.RegisterRouter(r)
   223  
   224  	drv, err := model.Open("mysql", config.GetConfig().DB)
   225  	if err != nil {
   226  		log.Errorf("create sql driver failed (%v)", err)
   227  		return
   228  	}
   229  	//crud.C = crud.NewClient(crud.Driver(drv))
   230  	//if err := crud.C.Schema.Create(context.Background()); err != nil {
   231  	//	log.Errorf(err)
   232  	//	return
   233  	//}
   234  	handlers.MountALotOfThingToEndpoint(r.Group("admin"),
   235  		handlers.WithMetric(r.TTLHist, r.URLConn,
   236  			prom.SysCPU(), prom.SysMem(), prom.SysDisk(), prom.SysLoad(), prom.GoRoutine(), prom.GoMem(),
   237  			prom.DbConnection(config.GetConfig().DB, drv.DB()), prom.DBWaitCount(config.GetConfig().DB, drv.DB()),
   238  			prom.DBWaitDuration(config.GetConfig().DB, drv.DB()), prom.DbClose(config.GetConfig().DB, drv.DB()),
   239  			prom.BuildInfo()),
   240  		handlers.WithSwagger(doc.Swagger),
   241  	)
   242  
   243  	if err := r.Run(fmt.Sprintf(":%v", config.GetConfig().Port)); err != nil {
   244  		log.Errorf("run app failed (%v)", err)
   245  		return
   246  	}
   247  }
   248  `
   249  
   250  	RouterGo = `package router
   251  
   252  import (
   253  	"github.com/gin-contrib/cors"
   254  	"github.com/ppphp/yayagf/pkg/log"
   255  	"github.com/ppphp/yayagf/pkg/maotai"
   256  	"github.com/ppphp/yayagf/pkg/middleware"
   257  )
   258  
   259  func RegisterRouter(r *maotai.MaoTai) {
   260  	r.Use(cors.Default())
   261  	api := r.Group("/")
   262  	api.Use(middleware.Ginrus(log.GetLogger()))
   263  
   264  }
   265  `
   266  
   267  	ConfigGo = `package config
   268  
   269  import (
   270  	"sync"
   271  
   272  	"github.com/ppphp/yayagf/pkg/config"
   273  	"github.com/ppphp/yayagf/pkg/log"
   274  )
   275  
   276  var lock sync.RWMutex
   277  
   278  type Config struct {
   279  	DB   string
   280  	Port int
   281  	Log  log.Config
   282  }
   283  
   284  var conf = new(Config)
   285  
   286  // only support ini like config
   287  func LoadConfig() error {
   288  	lock.Lock()
   289  	defer lock.Unlock()
   290  	if err := config.LoadConfig(conf); err != nil {
   291  		return err
   292  	}
   293  
   294  	log.Infof("%v", conf)
   295  
   296  	return nil
   297  }
   298  
   299  func GetConfig() Config {
   300  	lock.RLock()
   301  	defer lock.RUnlock()
   302  	return *conf
   303  }
   304  `
   305  )