123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- package main
- import (
- "fmt"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "strconv"
- "strings"
- "time"
- "github.com/siddontang/go/ioutil2"
- "github.com/urfave/cli"
- )
- func main() {
- app := cli.NewApp()
- app.Name = "liverpcgen"
- app.Usage = "Genproto generate files to call liverpc, include *.pb.go and *.liverpc.go\n" +
- "EXAMPLE:\n liverpcgen APP_NAME"
- app.Version = "1.0.0"
- app.Commands = []cli.Command{
- {
- Name: "update",
- Usage: "update the tool its self",
- Action: actionUpdate,
- },
- }
- app.Action = actionGenerate
- err := app.Run(os.Args)
- if err != nil {
- log.Fatal(err)
- }
- }
- func autoUpdate(ctx *cli.Context) (err error) {
- tfile, e := ioutil.ReadFile("/tmp/liverpcgentime")
- if e != nil {
- tfile = []byte{'0'}
- }
- ts, _ := strconv.ParseInt(string(tfile), 0, 64)
- current := time.Now().Unix()
- if (current - int64(ts)) > 3600*12 { // 12 hours old
- ioutil.WriteFile("/tmp/liverpcgentime", []byte(strconv.FormatInt(current, 10)), 0777)
- err = actionUpdate(ctx)
- if err != nil {
- return
- }
- }
- return
- }
- // actionGenerate invokes protoc to generate files
- func actionGenerate(ctx *cli.Context) (err error) {
- if err = autoUpdate(ctx); err != nil {
- return
- }
- appName := ctx.Args().Get(0)
- if appName == "" {
- cli.ShowAppHelpAndExit(ctx, 1)
- }
- here := ctx.Args().Get(1)
- goPath := initGopath()
- goCommonPath := goPath + "/src/go-common"
- if !fileExist(goCommonPath) {
- return cli.NewExitError("go-common not exist : "+goCommonPath, 1)
- }
- var rpcPath = goCommonPath + "/app/service/live/" + appName + "/api/liverpc"
- if here == "here" {
- rpcPath, err = os.Getwd()
- if err != nil {
- return cli.NewExitError(err, 1)
- }
- }
- if !fileExist(rpcPath) {
- os.MkdirAll(rpcPath, 0755)
- }
- log.Println("Generate for path: " + rpcPath)
- // find protos
- hasProto := fileExistWithSuffix(rpcPath, ".proto")
- if !hasProto {
- return cli.NewExitError("No proto files found in path : "+rpcPath, 1)
- }
- files, err := ioutil.ReadDir(rpcPath)
- if err != nil {
- return cli.NewExitError("Cannot read dir : "+rpcPath+" error: "+err.Error(), 1)
- }
- for _, file := range files {
- if file.IsDir() {
- if strings.HasPrefix(file.Name(), "v") {
- //if !file
- p := rpcPath + "/" + file.Name()
- if fileExistWithSuffix(p, ".proto") {
- err = runCmd(fmt.Sprintf("cd %s && protoc -I%s -I%s -I. --gogofaster_out=. --liverpc_out=. %s/*.proto",
- rpcPath, goCommonPath+"/vendor", goCommonPath, file.Name()))
- if err != nil {
- return cli.NewExitError("run protoc err: "+err.Error(), 1)
- }
- log.Println("generated for path: ", p)
- } else {
- log.Println("no protofiles found in " + p + " skip")
- }
- }
- }
- }
- // generate client code
- log.Println("generating client.go ...")
- resetPrint()
- var outputCliDeclares []string
- var outputCliAssigns []string
- var outputImports []string
- split := strings.Split(rpcPath, "/")
- clientPkg := split[len(split)-1]
- ap("// Code generated by liverpcgen, DO NOT EDIT.")
- ap("// source: *.proto files under this directory")
- ap("// If you want to change this file, Please see README in go-common/app/tool/liverpc/protoc-gen-liverpc/")
- ap("package " + clientPkg)
- ap("")
- ap("import (")
- ap(` "go-common/library/net/rpc/liverpc"`)
- pkgPrefix := strings.Replace(rpcPath, goPath+"/src/", "", 1)
- files, err = ioutil.ReadDir(rpcPath)
- if err != nil {
- return cli.NewExitError("Cannot read dir : "+rpcPath+" error: "+err.Error(), 1)
- }
- for _, file := range files {
- if strings.HasPrefix(file.Name(), "client.v") {
- pkg := strings.Split(file.Name(), ".")[1]
- pkgUpper := strings.ToUpper(pkg)
- var b []byte
- b, err = ioutil.ReadFile(rpcPath + "/" + file.Name())
- fileContent := string(b)
- if err != nil {
- return cli.NewExitError("fail to read file: "+rpcPath+"/"+file.Name(), 1)
- }
- fileContent = strings.TrimSuffix(fileContent, "\n")
- if fileContent != "" {
- names := strings.Split(fileContent, "\n")
- for _, name := range names {
- apVar(&outputCliDeclares, fmt.Sprintf(" // %s%s presents the controller in liverpc",
- pkgUpper, name))
- apVar(&outputCliDeclares, fmt.Sprintf(" %s%s %s.%sRPCClient", pkgUpper, name, pkg, name))
- apVar(&outputCliAssigns, fmt.Sprintf(" cli.%s%s = %s.New%sRPCClient(realCli)", pkgUpper, name, pkg, name))
- }
- log.Println("merge " + rpcPath + "/" + file.Name())
- apVar(&outputImports, fmt.Sprintf(` "%s/%s"`, pkgPrefix, pkg))
- }
- os.Remove(rpcPath + "/" + file.Name())
- }
- }
- ap(outputImports...)
- ap(")")
- ap("")
- ap("// Client that represents a liverpc " + appName + " service api")
- ap("type Client struct {")
- ap(" cli *liverpc.Client")
- ap(outputCliDeclares...)
- ap("}")
- ap("")
- discoveryId := strings.Replace(appName, "-", "", -1)
- discoveryId = strings.Replace(discoveryId, "_", "", -1)
- discoveryId = "live." + discoveryId
- ap("// DiscoveryAppId the discovery id is not the tree name")
- ap(`var DiscoveryAppId = "` + discoveryId + `"`)
- ap("")
- ap("// New a Client that represents a liverpc " + discoveryId + " service api")
- ap("// conf can be empty, and it will use discovery to find service by default")
- ap("// conf.AppID will be overwrite by a fixed value DiscoveryAppId")
- ap("// therefore is no need to set")
- ap("func New(conf *liverpc.ClientConfig) *Client {")
- ap(" if conf == nil {")
- ap(" conf = &liverpc.ClientConfig{}")
- ap(" }")
- ap(" conf.AppID = DiscoveryAppId")
- ap(" var realCli = liverpc.NewClient(conf)")
- ap(" cli := &Client{cli:realCli}")
- ap(" cli.clientInit(realCli)")
- ap(" return cli")
- ap("}")
- ap("")
- ap("")
- ap("func (cli *Client)GetRawCli() *liverpc.Client {")
- ap(" return cli.cli")
- ap("}")
- ap("")
- ap("func (cli *Client)clientInit(realCli *liverpc.Client) {")
- ap(outputCliAssigns...)
- ap("}")
- output := getOutput()
- err = ioutil.WriteFile(rpcPath+"/client.go", []byte(output), 0755)
- if err != nil {
- return cli.NewExitError("write file err : "+err.Error()+"; path: "+rpcPath+"/client.go", 1)
- }
- runCmd("gofmt -s -w " + rpcPath + "/client.go")
- return
- }
- var buf []string
- func resetPrint() {
- buf = make([]string, 0)
- }
- // append to default buf
- func ap(args ...string) {
- buf = append(buf, args...)
- }
- // append to var "b"
- func apVar(b *[]string, str ...string) {
- *b = append(*b, str...)
- }
- func getOutput() string {
- return strings.Join(buf, "\n")
- }
- // equals to `ls dir/*ext` has result
- func fileExistWithSuffix(dir string, ext string) bool {
- hasFile := false
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if !info.IsDir() {
- if strings.HasSuffix(info.Name(), ext) {
- hasFile = true
- return fmt.Errorf("stop")
- }
- }
- return nil
- })
- return hasFile
- }
- // actionUpdate update the tools its self
- func actionUpdate(ctx *cli.Context) (err error) {
- log.Printf("Updating liverpcgen.....")
- goPath := initGopath()
- goCommonPath := goPath + "/src/go-common"
- if !fileExist(goCommonPath) {
- return cli.NewExitError("go-common not exist : "+goCommonPath, 1)
- }
- cmd1 := fmt.Sprintf("cd %s/app/tool/liverpc/protoc-gen-liverpc && go install", goCommonPath)
- cmd2 := fmt.Sprintf("cd %s/app/tool/liverpc/liverpcgen && go install", goCommonPath)
- err = runCmd(cmd1)
- if err != nil {
- return cli.NewExitError("update fail: "+err.Error(), 1)
- }
- err = runCmd(cmd2)
- if err != nil {
- return cli.NewExitError("update fail: "+err.Error(), 1)
- }
- log.Printf("Updated!")
- return
- }
- // runCmd runs the cmd & print output (both stdout & stderr)
- func runCmd(cmd string) (err error) {
- fmt.Printf("CMD: %s\n", cmd)
- out, err := exec.Command("/bin/bash", "-c", cmd).CombinedOutput()
- fmt.Print(string(out))
- return
- }
- func fileExist(file string) bool {
- return ioutil2.FileExists(file)
- }
- func initGopath() string {
- root, err := goPath()
- if err != nil || root == "" {
- log.Printf("can not read GOPATH, use ~/go as default GOPATH")
- root = path.Join(os.Getenv("HOME"), "go")
- }
- return root
- }
- func goPath() (string, error) {
- gopaths := strings.Split(os.Getenv("GOPATH"), ":")
- if len(gopaths) == 1 {
- return gopaths[0], nil
- }
- for _, gp := range gopaths {
- absgp, err := filepath.Abs(gp)
- if err != nil {
- return "", err
- }
- if fileExist(absgp + "/src/go-common") {
- return absgp, nil
- }
- }
- return "", fmt.Errorf("can't found current gopath")
- }
|