release: new version

This commit is contained in:
Young Xu 2023-01-01 23:46:41 +08:00 committed by xuthus5
parent 08d0662fe6
commit 752041a69d
Signed by: xuthus5
GPG Key ID: A23CF9620CBB55F9
22 changed files with 979 additions and 50 deletions

View File

@ -6,4 +6,15 @@ coco 快速项目开发脚手架
- 新建项目
- 代码生成
- 自更新
- 工具自更新
## 安装
```shell
go install gitter.top/coco/bootstrap/coco/...@latest
go install gitter.top/coco/protoc-gen-coco@latest
go install github.com/golang/protobuf/protoc-gen-go@latest
go install github.com/bufbuild/buf/cmd/...@latest
go install github.com/google/wire/cmd/wire@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
```

39
coco/main.go Normal file
View File

@ -0,0 +1,39 @@
package main
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gitter.top/coco/bootstrap"
)
var (
rootCmd = &cobra.Command{
Use: "coco",
Short: "golang project toolkit",
}
)
func init() {
logrus.SetFormatter(&logrus.TextFormatter{
ForceColors: true,
EnvironmentOverrideColors: true,
DisableTimestamp: true,
DisableSorting: true,
DisableLevelTruncation: false,
PadLevelText: false,
QuoteEmptyFields: false,
})
rootCmd.AddCommand(bootstrap.Update())
rootCmd.AddCommand(bootstrap.CreateProject())
rootCmd.AddCommand(bootstrap.AddAPICommand())
rootCmd.AddCommand(bootstrap.AddServiceCommand())
rootCmd.AddCommand(bootstrap.GenerateProtoFile())
rootCmd.AddCommand(bootstrap.InjectProtoFile())
}
func main() {
if err := rootCmd.Execute(); err != nil {
logrus.Fatalln(err)
}
}

View File

@ -1,4 +1,4 @@
package main
package bootstrap
type Config struct {
Version string `yaml:"version"`

57
coco_generate.go Normal file
View File

@ -0,0 +1,57 @@
package bootstrap
import (
"os"
"os/exec"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func GenerateProtoFile() *cobra.Command {
var protoFile string
var onlyGout, onlyCocout bool
cmd := &cobra.Command{
Use: "gen",
Short: "generate proto file",
PreRun: func(_ *cobra.Command, _ []string) {
stat, err := os.Stat(protoFile)
if err != nil {
logrus.Errorf("read proto file %s failed: %v", protoFile, err)
return
}
if stat.IsDir() {
logrus.Errorf("proto file can not be directory")
return
}
},
Run: func(_ *cobra.Command, _ []string) {
var args = []string{protoFile}
var goOut = "--go_out=.."
var cocoOut = "--coco_out=.."
if onlyGout {
args = append(args, goOut)
}
if onlyCocout {
args = append(args, cocoOut)
}
if !onlyCocout && !onlyGout {
args = append(args, cocoOut, goOut)
}
var command = exec.Command("protoc", args...)
output, err := command.CombinedOutput()
logrus.Infof("exec command: %s", command.String())
if err != nil {
logrus.Errorf("exec command failed: %v: %v\noutput: %v", command.String(), err, string(output))
return
}
logrus.Infof("generate %s success", protoFile)
},
}
cmd.Flags().StringVar(&protoFile, "path", "", "proto file path")
cmd.Flags().BoolVar(&onlyGout, "onlyGo", false, "only generate by protoc-gen-go")
cmd.Flags().BoolVar(&onlyCocout, "onlyCoco", false, "only generate by protoc-gen-coco")
return cmd
}

59
coco_inject.go Normal file
View File

@ -0,0 +1,59 @@
package bootstrap
import (
"os"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gitter.top/common/gobuf"
)
func InjectProtoFile() *cobra.Command {
var protoFile string
var tags []string
var tagStyle string
cmd := &cobra.Command{
Use: "inject",
Short: "inject pb.go file",
PreRun: func(_ *cobra.Command, _ []string) {
stat, err := os.Stat(protoFile)
if err != nil {
logrus.Errorf("read pb.go file %s failed: %v", protoFile, err)
return
}
if stat.IsDir() {
logrus.Errorf("proto file can not be directory")
return
}
},
Run: func(_ *cobra.Command, _ []string) {
var getStyle = func(style string) gobuf.TagValueStyle {
if style == "underline" {
return gobuf.Underline
}
if style == "lowercase" {
return gobuf.LowerCase
}
return gobuf.UpperCase
}
var inject = gobuf.NewInjectTag(protoFile)
for _, tag := range tags {
inject.WithTags(gobuf.InjectTagProps{
TagName: tag,
Style: getStyle(tagStyle),
})
}
if err := inject.Inject(); err != nil {
logrus.Errorf("inject %s file failed: %v", protoFile, err)
return
}
logrus.Infof("inject %s success", protoFile)
},
}
cmd.Flags().StringVar(&protoFile, "path", "", "pb.go file path")
cmd.Flags().StringVar(&tagStyle, "style", "underline", "tag value style, value underline|lowercase|uppercase")
cmd.Flags().StringSliceVar(&tags, "tags", []string{"bson"}, "inject tag field name")
return cmd
}

View File

@ -1,26 +1,26 @@
package main
package bootstrap
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
gitea_api "gitter.top/coco/components/gitea-api"
"gitter.top/coco/components/runtime"
"gitter.top/coco/components/yaml"
)
func cocoUpdate() *cobra.Command {
func Update() *cobra.Command {
var config Config
var configPath string
var easyaml = NewEasYaml()
var rt = NewRuntime()
return &cobra.Command{
Use: "update",
Short: "coco tool update",
Short: "coco update",
PreRun: func(cmd *cobra.Command, args []string) {
configPath = runtime.ReplaceEachSlash(fmt.Sprintf("%s/.coco.yaml", runtime.GetHomeDir()))
_ = yaml.Read(configPath, &config)
configPath = rt.ReplaceEachSlash(fmt.Sprintf("%s/.coco.yaml", rt.GetHomeDir()))
_ = easyaml.Read(configPath, &config)
},
Run: func(cmd *cobra.Command, args []string) {
client, err := gitea_api.NewClient("https://gitter.top")
client, err := NewGiteaClient("https://gitter.top")
if err != nil {
logrus.Errorf("new gitea api failed: %v", err)
return
@ -36,19 +36,19 @@ func cocoUpdate() *cobra.Command {
}
// exec update
repo := fmt.Sprintf("gitter.top/coco/bootstrap@%s", commitID)
if output, err := runtime.Exec("go", "build", "-o", "coco", repo); err != nil {
logrus.Errorf("update coco failed: %v", err)
repo := fmt.Sprintf("gitter.top/coco/bootstrap/coco/...@%s", commitID)
if _, err := rt.Exec("go", "install", repo); err != nil {
logrus.Errorf("update bootstrap failed: %v", err)
return
} else {
logrus.Infof("%s", output)
}
config.Version = commitID
if err := yaml.Write(configPath, &config); err != nil {
if err := easyaml.Write(configPath, &config); err != nil {
logrus.Errorf("write config failed: %v", err)
return
}
logrus.Infof("update success!")
},
}
}

77
create_api.go Normal file
View File

@ -0,0 +1,77 @@
package bootstrap
import (
"os"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gitter.top/common/gobuf"
)
func AddAPICommand() *cobra.Command {
pbPath, _ := os.Getwd()
var routerGroup = ""
var routerName = ""
cmd := &cobra.Command{
Use: "addapi",
Short: "add api for service",
Run: func(cmd *cobra.Command, args []string) {
if routerName == "" {
logrus.Errorf("router name --name empty")
return
}
routerName = FirstUpper(routerName)
buf, err := gobuf.NewParser(pbPath)
if err != nil {
logrus.Errorf("read proto file failed: %v", err)
return
}
if buf.ExistRPC(routerGroup, routerName) {
logrus.Warnf("router name exist")
return
}
err = buf.AddRPC(routerGroup, routerName)
if err != nil {
logrus.Warnf("add router failed: %v", err)
return
}
},
}
cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto file path")
cmd.Flags().StringVar(&routerName, "name", routerName, "api name")
cmd.Flags().StringVar(&routerGroup, "service", routerGroup, "service name")
return cmd
}
func AddServiceCommand() *cobra.Command {
var pbPath = ""
var svcName = ""
cmd := &cobra.Command{
Use: "addgroup",
Short: "add router group",
Run: func(cmd *cobra.Command, args []string) {
if svcName == "" {
logrus.Errorf("router group name -- name empty")
return
}
buf, err := gobuf.NewParser(pbPath)
if err != nil {
logrus.Errorf("read proto file failed: %v", err)
return
}
if buf.ExistService(svcName) {
logrus.Errorf("router group name exist")
return
}
if err := buf.AddService(svcName); err != nil {
logrus.Errorf("add router group failed: %+v", err)
return
}
},
}
cmd.Flags().StringVar(&pbPath, "path", pbPath, "proto file path")
cmd.Flags().StringVar(&svcName, "name", svcName, "router group name, such as UserModule")
return cmd
}

45
create_project.go Normal file
View File

@ -0,0 +1,45 @@
package bootstrap
import (
"fmt"
"os"
"path"
"github.com/spf13/cobra"
"gitter.top/coco/bootstrap/template"
)
func CreateProject() *cobra.Command {
var name, output string
cmd := &cobra.Command{
Use: "new",
Short: "create new project",
PreRun: func(cmd *cobra.Command, args []string) {
if name != "" {
return
}
if len(args) == 1 {
name = args[0]
return
}
name = "DemoProject"
},
Run: func(cmd *cobra.Command, args []string) {
b := &template.Builder{
Path: output,
Name: name,
}
b.Path = path.Join(output, b.Name)
if err := b.Build(); err != nil {
_, _ = fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
},
}
cmd.Flags().StringVar(&name, "name", "", "project name")
cmd.Flags().StringVar(&output, "path", ".", "project path")
return cmd
}

26
go.mod
View File

@ -1,18 +1,24 @@
module gitter.top/xuthus5/coco
module gitter.top/coco/bootstrap
go 1.18
go 1.20
require (
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
gitter.top/coco/components v0.0.0-20230101151943-8e94d6d01339
code.gitea.io/sdk/gitea v0.17.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
gitter.top/common/gobuf v0.0.1
gopkg.in/yaml.v3 v3.0.1
)
require (
code.gitea.io/sdk/gitea v0.15.1 // indirect
github.com/hashicorp/go-version v1.2.1 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/emicklei/proto v1.13.2 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gitter.top/sync/proto-contrib v0.15.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)

23
main.go
View File

@ -1,23 +0,0 @@
package main
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var (
rootCmd = &cobra.Command{
Use: "coco",
Short: "golang project generator",
}
)
func init() {
rootCmd.AddCommand(cocoUpdate())
}
func main() {
if err := rootCmd.Execute(); err != nil {
logrus.Fatalln(err)
}
}

89
template/creator.go Normal file
View File

@ -0,0 +1,89 @@
package template
import (
"bytes"
"fmt"
"os"
"strings"
"text/template"
)
var (
scaffold = map[string]string{
"/.gitignore": templateGitignore,
"/Makefile": templateMakefile,
"/Dockerfile": templateDockerfile,
"/docker-compose.yaml": templateDockerCompose,
"/buf.yaml": templateBuf,
"/buf.gen.yaml": templateBufGen,
"/buf.work.yaml": templateBufWork,
"/go.mod": templateModule,
"/config_dev.yaml": templateDevYaml,
"/config_prod.yaml": templateProdYaml,
"/proto/v1/file_module.proto": templateApiservicesProto,
"/proto/v1/file_model.proto": templateProto,
"/proto/v1/buf.yaml": templateBuf,
"/cmd/serve.go": templateCmdNewServe,
"/cmd/exec.go": templateCmdExec,
"/common/time.go": templateCommon,
"/config/config.go": templateConfig,
"/register/register.go": templateRouter,
"/internal/repositories/.gitkeep": "",
"/services/.gitkeep": "",
"/gen/.gitkeep": "",
}
)
type Builder struct {
Name string
Path string
SSH string
}
func (b *Builder) Build() error {
if err := os.MkdirAll(b.Path, 0755); err != nil {
return err
}
if err := b.write(b.Path+"/"+b.Name+".go", templateMain); err != nil {
return err
}
for sr, v := range scaffold {
i := strings.LastIndex(sr, "/")
if i > 0 {
dir := sr[:i]
if err := os.MkdirAll(b.Path+dir, 0755); err != nil {
return err
}
}
if err := b.write(b.Path+sr, v); err != nil {
return err
}
}
return nil
}
func (b *Builder) write(name, tpl string) (err error) {
defer func() {
if err := recover(); err != nil {
fmt.Println("Failed")
}
}()
fmt.Printf("create %s \n", name)
data, err := b.parse(tpl)
if err != nil {
return
}
return os.WriteFile(name, data, 0644)
}
func (b *Builder) parse(s string) ([]byte, error) {
t, err := template.New("").Parse(s)
if err != nil {
return nil, err
}
var buf bytes.Buffer
if err := t.Execute(&buf, b); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

View File

@ -0,0 +1,70 @@
package template
const templateApiservicesProto = `syntax = "proto3";
package proto.v1;
option go_package = "{{.Name}}/gen;genv1";
// @route_group: true
// @base_url: /v1/file
// @gen_to: ./services/controller/v1/file_controller.go
// @rpc_to: ./services/rpc/v1/file_impl.go
service FileService {
// @desc: 列表
// @author: Young Xu
// @method: GET
// @api: /list
rpc List (FileServiceListRequest) returns (FileServiceListResponse);
// @desc: 上传
// @author: Young Xu
// @method: POST
// @api: /upload
rpc Upload (FileServiceUploadRequest) returns (FileServiceUploadResponse);
// @desc: 删除
// @author: Young Xu
// @method: DELETE
// @api: /delete
rpc Delete (FileServiceDeleteRequest) returns (FileServiceDeleteResponse);
// @desc: 下载
// @author: Young Xu
// @method: GET
// @api: /download
rpc Download (FileServiceDownloadRequest) returns (FileServiceDownloadResponse);
}
message FileServiceListRequest {
string dirname = 1; // 目录
}
message FileServiceListResponse {
message Item {
int64 file_id = 1; // 文件ID
string filename = 2; // 文件名
string file_size = 3; // 文件大小
string created_at = 4; // 上传时间
string dirname = 5; // 文件路径
bool is_directory = 6; // 是否是目录
}
repeated Item items = 1; // 列表
}
message FileServiceUploadRequest {}
message FileServiceUploadResponse {}
message FileServiceDeleteRequest {
int64 file_id = 1; // 文件名
}
message FileServiceDeleteResponse {}
message FileServiceDownloadRequest {
// @v: required
string file_id = 1; // 文件ID
}
message FileServiceDownloadResponse {}
`

View File

@ -0,0 +1,83 @@
package template
const templateCmdExec = `package cmd
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gitter.top/common/lormatter"
"{{.Name}}/config"
)
var (
rootCmd = &cobra.Command{}
cfgFile string
)
func Execute() {
// 预加载配置文件
loadConfig()
if err := rootCmd.Execute(); err != nil {
logrus.Fatalf("exec command failed: %v", err)
}
}
func init() {
var formatter = lormatter.Formatter{
ShowTime: true,
ShowFile: true,
}
formatter.Register()
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "config_dev.yaml", "config file")
rootCmd.AddCommand(apiServerCommand) // API服务
rootCmd.AddCommand(grpcServerCommand) // GRPC服务
}
func loadConfig() {
// 初始化配置文件
config.New(cfgFile)
conf := config.Get()
if err := conf.Load(); err != nil {
panic(err)
}
}
`
const templateCmdNewServe = `package cmd
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"{{.Name}}/register"
)
var (
apiServerCommand = &cobra.Command{
Use: "api",
Short: "start api server",
Long: "start api server",
Run: func(cmd *cobra.Command, args []string) {
router := register.NewRegister()
if err := router.NewRouter(); err != nil {
logrus.Errorf("register router failed: %v", err)
}
},
}
)
var (
grpcServerCommand = &cobra.Command{
Use: "grpc",
Short: "start grpc server",
Long: "start grpc server",
Run: func(cmd *cobra.Command, args []string) {
router := register.NewRegister()
if err := router.NewGrpc(); err != nil {
logrus.Errorf("register grpc failed: %v", err)
}
},
}
)
`

View File

@ -0,0 +1,10 @@
package template
const templateCommon = `package common
import "time"
func Unix2Datetime(t int64) string {
return time.Unix(t, 0).Format(time.DateTime)
}
`

View File

@ -0,0 +1,62 @@
package template
const templateConfig = `package config
import (
"os"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
)
type ServerConfig struct {
ServerName string ` + "`" + `yaml:"server-name"` + "`" + `
ServerListen string ` + "`" + `yaml:"server-listen"` + "`" + `
GrpcListen string ` + "`" + `yaml:"grpc-listen"` + "`" + `
Environment string ` + "`" + `yaml:"environment"` + "`" + `
}
type ServerConf struct {
ConfigFile string
ServerConfig ` + "`" + `yaml:",inline"` + "`" + `
}
var conf *ServerConf
func New(fileName string) {
conf = new(ServerConf)
conf.ConfigFile = fileName
if err := conf.Load(); err != nil {
logrus.Fatalf("read config file failed: %v", err)
}
}
func Get() *ServerConf {
if conf == nil {
panic("config file not initialized")
}
return conf
}
func (receiver *ServerConf) Load() error {
data, err := os.ReadFile(receiver.ConfigFile)
if err != nil && !os.IsNotExist(err) {
return err
}
if err := yaml.Unmarshal(data, receiver); err != nil {
return err
}
return nil
}
func (receiver *ServerConf) Rewrite() error {
data, err := yaml.Marshal(receiver)
if err != nil {
return err
}
if err := os.WriteFile(receiver.ConfigFile, data, os.ModePerm); err != nil {
return err
}
return nil
}
`

10
template/template_main.go Normal file
View File

@ -0,0 +1,10 @@
package template
const templateMain = `package main
import "{{.Name}}/cmd"
func main() {
cmd.Execute()
}
`

View File

@ -0,0 +1,19 @@
package template
const templateProto = `syntax = "proto3";
package proto.v1;
option go_package = "{{.Name}}/gen;genv1";
// @table_name: t_file
message ModelFileRecord {
int64 id = 1;
string filename = 2;
string file_size = 3;
string dirname = 4;
int64 created_at = 5;
bool is_directory = 6;
}
`

View File

@ -0,0 +1,18 @@
package template
const templateModule = `module {{.Name}}
go 1.20
require (
github.com/gin-gonic/gin v1.9.1
github.com/google/wire v0.5.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
gitter.top/coco/coco v0.0.1
gitter.top/common/lormatter v0.0.0-20230910075849-28d49dccd03a
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v3 v3.0.1
)
`

View File

@ -0,0 +1,104 @@
package template
const templateGitignore = `.idea
{{.Name}}
{{.Name}}.exe
{{.Name}}.exe~
`
const templateMakefile = `.PHONY : clean all ui api gen wire
gen:
ifeq ($(wildcard "webui/node_modules"),)
buf generate
else
buf generate --exclude-path webui/node_modules
endif
wire:
go mod tidy
cd gen/wire && wire
ui:
cd webui && npm install && npm run build
api:
go mod tidy && go build .
./{{.Name}} api
build: gen wire ui api
run: gen wire ui api
./{{.Name}} api
all: gen wire ui api
docker:
podman build -t images.internal/{{.Name}}:latest .
podman push images.internal/{{.Name}}:latest
`
const templateDockerfile = `FROM images.internal/devel:latest
WORKDIR /app
COPY . /app
RUN make build
EXPOSE 38001
ENTRYPOINT [ "./{{.Name}}", "api" ]
`
const templateDockerCompose = `version: "3"
services:
server:
image: images.internal/{{.Name}}:latest
container_name: {{.Name}}
restart: always
volumes:
- /data/containers/{{.Name}}:/app/data
ports:
- "30001:38080"
`
const templateBuf = `version: v1
breaking:
use:
- FILE
lint:
use:
- DEFAULT
except:
- MINIMAL
`
const templateBufGen = `version: v1
plugins:
- plugin: buf.build/protocolbuffers/go
out: gen
opt: paths=source_relative
- plugin: coco
out: gen
opt:
- paths=source_relative
- prefix=proto
- project_name={{.Name}}
- plugin: buf.build/community/stephenh-ts-proto
out: ./webui/src/gen
opt:
- paths=source_relative
- snakeToCamel=json
- esModuleInterop=true
- plugin: buf.build/grpc/go:v1.3.0
out: gen
opt:
- paths=source_relative
- require_unimplemented_servers=false
`
const templateBufWork = `version: v1
directories:
- proto
`

View File

@ -0,0 +1,62 @@
package template
const templateRouter = `package register
import (
"net"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gitter.top/coco/coco"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"{{.Name}}/config"
"{{.Name}}/gen/wire"
)
type Register struct{
*config.ServerConf
}
func NewRegister() *Register {
return &Register{config.Get()}
}
// NewRouter 注册路由
func (receiver *Register) NewRouter() error {
// 从这里开始实例化路由注册器
var register = coco.NewRegister()
register.DefaultRouter(coco.WithListenAddress(receiver.ServerListen),
coco.WithGinMode(gin.ReleaseMode), coco.WithCors(), coco.WithRecovery())
// register.RegisterStruct(wire.InitFileService())
_ = register.PreRun(func() error {
engine := register.RawEngine()
engine.Static("/assets", "./webui/dist/assets")
engine.NoRoute(func(ctx *gin.Context) {
ctx.File("./webui/dist/index.html")
})
return nil
})
logrus.Infof("start api server: http://%s", receiver.ServerListen)
register.Run()
return nil
}
// NewGrpc 注册grpc服务端
func (receiver *Register) NewGrpc() error {
lis, err := net.Listen("tcp", receiver.GrpcListen)
if err != nil {
logrus.Fatalf("failed to listen grpc: %v", err)
}
s := grpc.NewServer()
//genv1.RegisterFileServiceServer(s, &rpcv1.FileService{})
// Register reflection service on gRPC server.
reflection.Register(s)
logrus.Infof("grpc server: %s", receiver.GrpcListen)
if err := s.Serve(lis); err != nil {
logrus.Fatalf("failed to serve grpc: %v", err)
}
return nil
}
`

13
template/template_yaml.go Normal file
View File

@ -0,0 +1,13 @@
package template
const templateDevYaml = `server-name: {{.Name}}
server-listen: 0.0.0.0:38080
grpc-listen: 0.0.0.0:38090
environment: dev
`
const templateProdYaml = `server-name: {{.Name}}
server-listen: 0.0.0.0:38080
grpc-listen: 0.0.0.0:38090
environment: prod
`

118
util.go Normal file
View File

@ -0,0 +1,118 @@
package bootstrap
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"code.gitea.io/sdk/gitea"
"gopkg.in/yaml.v3"
)
// FirstUpper 字符串首字母大写
func FirstUpper(s string) string {
if s == "" {
return ""
}
return strings.ToUpper(s[:1]) + s[1:]
}
type GiteaClient struct {
client *gitea.Client
}
func NewGiteaClient(addr string) (*GiteaClient, error) {
client, err := gitea.NewClient(addr)
if err != nil {
return nil, err
}
return &GiteaClient{client: client}, nil
}
func (c *GiteaClient) GetLatestCommitID(owner, repoName string) (string, error) {
commits, _, err := c.client.ListRepoCommits(owner, repoName, gitea.ListCommitOptions{
ListOptions: gitea.ListOptions{
Page: 1,
PageSize: 1,
},
})
if err != nil {
return "", err
}
return commits[0].SHA, nil
}
type EasYaml struct {
}
func NewEasYaml() *EasYaml {
return &EasYaml{}
}
func (y *EasYaml) Read(filename string, ptr interface{}) error {
body, err := os.ReadFile(filename)
if err != nil {
return err
}
if err := yaml.Unmarshal(body, ptr); err != nil {
return err
}
return nil
}
func (y *EasYaml) Write(filename string, ptr interface{}) error {
body, err := yaml.Marshal(ptr)
if err != nil {
return err
}
return os.WriteFile(filename, body, os.ModePerm)
}
type Runtime struct {
}
func NewRuntime() *Runtime {
return &Runtime{}
}
func (r *Runtime) Exec(cmd string, args ...string) (output string, err error) {
command := exec.Command(cmd, args...)
body, err := command.Output()
if err != nil {
return "", err
}
return string(body), nil
}
type GOOS string
const (
Linux GOOS = "linux"
Windows GOOS = "windows"
Darwin GOOS = "darwin"
Freebsd GOOS = "freebsd"
)
// GetGOOS get GOOS value
func (r *Runtime) GetGOOS() GOOS {
return GOOS(runtime.GOOS)
}
// GetHomeDir get home directory
func (r *Runtime) GetHomeDir() string {
switch r.GetGOOS() {
case Linux:
return os.Getenv("HOME")
case Windows:
return os.Getenv("USERPROFILE")
default:
return os.Getenv("HOME")
}
}
// ReplaceEachSlash replacing each slash ('/') character
func (r *Runtime) ReplaceEachSlash(filename string) string {
return filepath.FromSlash(filename)
}