github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/cmd/fns/initialization/command.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package initialization
    19  
    20  import (
    21  	"fmt"
    22  	"github.com/aacfactory/errors"
    23  	"github.com/aacfactory/fns/cmd/fns/initialization/base"
    24  	"github.com/urfave/cli/v2"
    25  	"golang.org/x/mod/modfile"
    26  	"path/filepath"
    27  	"runtime"
    28  	"strconv"
    29  	"strings"
    30  )
    31  
    32  var Command = &cli.Command{
    33  	Name:        "init",
    34  	Aliases:     nil,
    35  	Usage:       "fns init --mod={mod} --img={docker image name} --work={true} --version={go version} {project dir}",
    36  	Description: "init fns project",
    37  	ArgsUsage:   "",
    38  	Category:    "",
    39  	Flags: []cli.Flag{
    40  		&cli.StringFlag{
    41  			Name:     "mod",
    42  			Aliases:  []string{"m"},
    43  			Required: true,
    44  			Usage:    "project go mod path",
    45  		},
    46  		&cli.BoolFlag{
    47  			Name:     "work",
    48  			Aliases:  []string{"w"},
    49  			Required: false,
    50  			Usage:    "use go work",
    51  		},
    52  		&cli.StringFlag{
    53  			Name:     "img",
    54  			Aliases:  []string{"i"},
    55  			Required: false,
    56  			Usage:    "project docker image name",
    57  		},
    58  		&cli.StringFlag{
    59  			Name:     "version",
    60  			Required: false,
    61  			Usage:    "go version, e.g.: 1.21.0",
    62  		},
    63  	},
    64  	Action: func(ctx *cli.Context) (err error) {
    65  		projectDir := strings.TrimSpace(ctx.Args().First())
    66  		if projectDir == "" {
    67  			projectDir = "."
    68  		}
    69  		if !filepath.IsAbs(projectDir) {
    70  			projectDir, err = filepath.Abs(projectDir)
    71  			if err != nil {
    72  				err = errors.Warning("fns: init fns project failed").WithCause(err).WithMeta("dir", projectDir)
    73  				return
    74  			}
    75  		}
    76  		projectDir = filepath.ToSlash(projectDir)
    77  		projectPath := strings.TrimSpace(ctx.String("mod"))
    78  		img := strings.TrimSpace(ctx.String("img"))
    79  		work := ctx.Bool("work")
    80  		goVersion := ctx.String("version")
    81  		if goVersion == "" {
    82  			goVersion = runtime.Version()[2:]
    83  		}
    84  		if !ValidGoVersion(goVersion) {
    85  			err = errors.Warning("fns: init fns project failed").WithCause(fmt.Errorf("go version must be gte %s", runtime.Version())).WithMeta("dir", projectDir).WithMeta("path", projectPath)
    86  			return
    87  		}
    88  		writeErr := base.Write(ctx.Context, goVersion, projectPath, img, work, projectDir)
    89  		if writeErr != nil {
    90  			err = errors.Warning("fns: init fns project failed").WithCause(writeErr).WithMeta("dir", projectDir).WithMeta("path", projectPath)
    91  			return
    92  		}
    93  		if work {
    94  			fmt.Println("fns: project has been initialized, please run `go work sync` and `go mod tidy` to fetch requires and run `go generate` to generate source files!")
    95  		} else {
    96  			fmt.Println("fns: project has been initialized, please run `go mod tidy` to fetch requires and run `go generate` to generate source files!")
    97  		}
    98  		return
    99  	},
   100  }
   101  
   102  func ParseGoVersion(s string) (v Version) {
   103  	ss := strings.Split(s, ".")
   104  	if len(ss) > 0 {
   105  		v.Major, _ = strconv.Atoi(ss[0])
   106  	}
   107  	if len(ss) > 1 {
   108  		v.Miner, _ = strconv.Atoi(ss[1])
   109  	}
   110  	if len(ss) > 2 {
   111  		v.Miner, _ = strconv.Atoi(ss[2])
   112  	}
   113  	return
   114  }
   115  
   116  type Version struct {
   117  	Major int
   118  	Miner int
   119  	Patch int
   120  }
   121  
   122  func ValidGoVersion(target string) (ok bool) {
   123  	if !modfile.GoVersionRE.MatchString(target) {
   124  		return
   125  	}
   126  	tv := ParseGoVersion(target)
   127  	rv := ParseGoVersion(runtime.Version()[2:])
   128  	if tv.Major >= rv.Major {
   129  		if tv.Miner >= rv.Miner {
   130  			if tv.Patch >= rv.Patch {
   131  				ok = true
   132  			}
   133  		}
   134  	}
   135  	return
   136  }