소스 검색

更新构建信息和版本控制

增加了获取构建时间和Git信息的功能,并改进了版本号的生成逻辑。重构了一些代码以减少不必要的资源导入,并在示例服务中添加了更多输出信息。
SongZihuan 2 주 전
부모
커밋
62ecb33aca
19개의 변경된 파일260개의 추가작업 그리고 23개의 파일을 삭제
  1. 9 1
      .gitignore
  2. 42 0
      CHANGELOG.md
  3. 2 1
      README.md
  4. 0 0
      REPORT
  5. 0 1
      VERSION
  6. 2 0
      get_date.ps1
  7. 1 0
      get_date.sh
  8. 11 0
      get_date_posix.go
  9. 11 0
      get_date_win32.go
  10. 27 0
      get_git.ps1
  11. 22 0
      get_git.sh
  12. 106 7
      resource.go
  13. 1 0
      src/cmd/lionv1/main.go
  14. 1 0
      src/cmd/tigerv1/main.go
  15. 2 2
      src/commandlineargs/define_data_type.go
  16. 4 4
      src/commandlineargs/export_printer.go
  17. 0 3
      src/config/global_config.go
  18. 17 3
      src/global/variabl.go
  19. 2 1
      src/server/example1/server.go

+ 9 - 1
.gitignore

@@ -16,4 +16,12 @@ pkg
 go-remote.sh
 
 testself
-test_self
+test_self
+
+output
+
+build_date.txt
+
+commit_data.txt
+tag_data.txt
+tag_commit_data.txt

+ 42 - 0
CHANGELOG.md

@@ -0,0 +1,42 @@
+# 变更日志 - Changelog
+
+本项目所有显著变更都将记录在此文件中。
+
+其格式基于 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+且本项目遵循 [语义化版本控制](https://semver.org/spec/v2.0.0.html)。
+
+## [0.1.1] - 2025-04-3
+
+### 新增功能
+
+- 获取构建时时间
+- 获取构建时`Git`信息(若有):当前`commit hash`、当前最新`tag`(若有)、以及`tag`(若有)对应的`commit hash`(若有)。
+- 清洗通过`go:embed`读取的文件:仅保留第一行(某些文件),删除`BOM`,删除`\r`。
+- 修改语义化版本号获取:
+  - 从`VERSION`文件获取(第一优先级,可以以v/V开头,必须满足语义化版本哈规定)。
+  - 从`git`获取最新的`tag`(第二优先级,可以以v/V开头,必须满足语义化版本哈规定)。
+    - 当该`tag`对应的并非当前`commit`时,`tag`会加上`+dev`标签
+    - 当该`tag`以`0.`开头时,`tag`会加上`+dev`标签
+  - 采用版本号`0.0.0`
+    - 若无`commit hash`,则最终版本号为`0.0.0+dev-1744225466`,其中`1744225466`为编译时间戳。
+    - 若有`commit hash`,则最终版本号为`0.0.0+1744225466-be8f4ff51e6ed2e01171b38459406dc5dac306ea`,其中`1744225466`为编译时间戳,`be8f4ff51e6ed2e01171b38459406dc5dac306ea`为`commit hash`。
+- `Server.Example1`例子更完善,输出更多信息。
+
+### 重构
+
+- 减少`import resource "github.com/SongZihuan/BackendServerTemplate"`的引用。
+
+## [0.1.0] - 2025-04-3
+
+### 新增功能
+
+- 日志(支持投递到标准输出、文件、日期切割的文件、自定义输出、多输出合并)
+- 命令行参数(支持`string`、`bool`、`uint`、`int`)
+- 配置文件(支持`json`和`yaml`格式,也可以自定义解析器)
+- 退出信号量捕获(在`posix`系统上可以使用信号量捕获退出信号,并做清理操作。在`win32`上,命令行的`ctrl+c`也可被捕获,但当程序作为服务在后台运行时,相关停止、重启操作暂未内捕获)
+- 全局变量和资源(打包了`Version`、`License`、`Name`、`Report`等变量)
+- 服务模式(可使用控制单元启动多服务,或直接启动单服务)
+
+### 删除
+
+- 删除`test_self`文件夹

+ 2 - 1
README.md

@@ -26,7 +26,8 @@
 
 ## 编译
 
-使用`go build`进行正常编译即可。
+使用请先在项目根目录执行`go:generate ./...`,随后执行`go build github.com/SongZihuan/BackendServerTemplate/src/cmd/<lionv1/tigerv1>`进行正常编译即可。
+**注意:把`<lionv1/tigerv1>`替换成你具体想编译的包名,最终指令例如:go build github.com/SongZihuan/BackendServerTemplate/src/cmd/lionv1**
 
 日后支持:
 

+ 0 - 0
REEPORT → REPORT


+ 0 - 1
VERSION

@@ -1 +0,0 @@
-v1.0.0

+ 2 - 0
get_date.ps1

@@ -0,0 +1,2 @@
+$timestamp = [math]::Floor([decimal]((Get-Date).ToUniversalTime() | Get-Date -UFormat %s))
+Set-Content -Path "build_date.txt" -Value $timestamp

+ 1 - 0
get_date.sh

@@ -0,0 +1 @@
+date '+%s' > build_date.txt

+ 11 - 0
get_date_posix.go

@@ -0,0 +1,11 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+//go:build !windows
+
+//go:generate /bin/bash ./get_date.sh
+
+//go:generate /bin/bash ./get_git.sh
+
+package resource

+ 11 - 0
get_date_win32.go

@@ -0,0 +1,11 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+//go:build windows
+
+//go:generate powershell -ExecutionPolicy RemoteSigned ./get_date.ps1
+
+//go:generate powershell -ExecutionPolicy RemoteSigned ./get_git.ps1
+
+package resource

+ 27 - 0
get_git.ps1

@@ -0,0 +1,27 @@
+if (Test-Path -Path ".\.git" -PathType Container) {
+    # 如果 .git 目录存在
+    $last_commit = git rev-parse HEAD 2>$null
+    $last_tag = git describe --tags --abbrev=0 2>$null
+
+    if (-not [string]::IsNullOrEmpty($last_tag)) {
+        # 如果有标签
+        $last_tag_commit = git rev-list -n 1 $last_tag 2>$null
+
+        Set-Content -Path "commit_data.txt" -Value $last_commit -Encoding UTF8
+        Set-Content -Path "tag_data.txt" -Value $last_tag -Encoding UTF8
+        Set-Content -Path "tag_commit_data.txt" -Value $last_tag_commit -Encoding UTF8
+    } else {
+        # 如果没有标签
+        Set-Content -Path "commit_data.txt" -Value $last_commit -Encoding UTF8
+        New-Item -Path "tag_data.txt" -ItemType File -Force
+        New-Item -Path "tag_commit_data.txt" -ItemType File -Force
+    }
+} else {
+    # 如果 .git 目录不存在
+    New-Item -Path "commit_data.txt" -ItemType File -Force
+    New-Item -Path "tag_data.txt" -ItemType File -Force
+    New-Item -Path "tag_commit_data.txt" -ItemType File -Force
+}
+
+# 创建 VERSION 文件
+New-Item -Path "VERSION" -ItemType File -Force

+ 22 - 0
get_git.sh

@@ -0,0 +1,22 @@
+if [ -d "./.git" ]; then
+    last_commit="$(git rev-parse HEAD 2>/dev/null)"
+    last_tag="$(git describe --tags --abbrev=0 2>/dev/null)"
+
+    if [ -n "$last_tag" ]; then
+      last_tag_commit="$(git rev-list -n 1 "$last_tag" 2>/dev/null)"
+
+      echo "$last_commit" > commit_data.txt
+      echo "$last_tag" > tag_data.txt
+      echo "$last_tag_commit" > tag_commit_data.txt
+    else
+      echo "$last_commit" > commit_data.txt
+      touch tag_data.txt
+      touch tag_commit_data.txt
+    fi
+else
+    touch commit_data.txt
+    touch tag_data.txt
+    touch tag_commit_data.txt
+fi
+
+touch "VERSION"

+ 106 - 7
resource.go

@@ -4,33 +4,132 @@ import (
 	_ "embed"
 	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/reutils"
+	"strconv"
 	"strings"
+	"time"
 )
 
 //go:embed VERSION
+var version string
 var Version string
-
 var SemanticVersioning string
 
 //go:embed LICENSE
 var License string
 
-//go:embed REEPORT
+//go:embed REPORT
 var Report string
 
 //go:embed NAME
 var Name string
 
+//go:embed build_date.txt
+var buildDateTxt string
+
+var BuildTime time.Time
+
+//go:embed commit_data.txt
+var GitCommitHash string
+
+//go:embed tag_data.txt
+var GitTag string
+
+//go:embed tag_commit_data.txt
+var GitTagCommitHash string
+
 func init() {
+	initCleanFile()
+	initName()
+	initBuildDate()
+	initVersion()
+}
+
+func initCleanFile() {
+	License = utilsClenFileDataMoreLine(License)
+	Report = utilsClenFileDataMoreLine(Report)
+
+	version = utilsClenFileData(version)
+	Name = utilsClenFileData(Name)
+	buildDateTxt = utilsClenFileData(buildDateTxt)
+	GitCommitHash = utilsClenFileData(GitCommitHash)
+	GitTag = utilsClenFileData(GitTag)
+	GitTagCommitHash = utilsClenFileData(GitTagCommitHash)
+}
+
+func initName() {
 	if Name == "" {
 		Name = "Backend-Server"
 	}
+}
+
+func initBuildDate() {
+	if buildDateTxt == "" {
+		BuildTime = time.Now()
+		return
+	}
 
-	Version = strings.ToLower(Version)
-	ver := strings.TrimPrefix(Version, "v")
-	if !reutils.IsSemanticVersion(ver) {
-		panic(fmt.Sprintf("%s is not a semantic versioning.", Version))
+	res, err := strconv.ParseInt(buildDateTxt, 10, 64)
+	if err != nil {
+		panic(fmt.Sprintf("get build timestamp error: %s", err.Error()))
+	}
+	BuildTime = time.Unix(res, 0)
+}
+
+func initVersion() {
+	SemanticVersioning = strings.TrimPrefix(strings.ToLower(version), "v")
+	if SemanticVersioning == "" {
+		SemanticVersioning = strings.TrimPrefix(strings.ToLower(GitTag), "v")
+		if SemanticVersioning == "" {
+			if GitCommitHash != "" {
+				SemanticVersioning = fmt.Sprintf("0.0.0+dev-%d-%s", BuildTime.Unix(), GitCommitHash)
+			} else {
+				SemanticVersioning = fmt.Sprintf("0.0.0+dev-%d", BuildTime.Unix())
+			}
+			Version = "v" + SemanticVersioning
+		} else if reutils.IsSemanticVersion(SemanticVersioning) {
+			if GitCommitHash != "" && GitTagCommitHash != "" && GitCommitHash != GitTagCommitHash && !strings.Contains(SemanticVersioning, "dev") {
+				SemanticVersioning = SemanticVersioning + fmt.Sprintf("+dev-%s", GitTagCommitHash)
+			} else if strings.HasPrefix(SemanticVersioning, "0.") {
+				SemanticVersioning = SemanticVersioning + "-dev"
+			}
+			Version = "v" + SemanticVersioning
+		} else {
+			panic(fmt.Sprintf("%s is not a semantic versioning.", SemanticVersioning))
+		}
+	} else if reutils.IsSemanticVersion(SemanticVersioning) {
+		Version = "v" + SemanticVersioning
 	} else {
-		SemanticVersioning = ver
+		panic(fmt.Sprintf("%s is not a semantic versioning.", SemanticVersioning))
 	}
 }
+
+func utilsClenFileData(data string) (res string) {
+	res = utilsCheckAndRemoveBOM(data)
+	res = strings.Replace(res, "\r", "", -1)
+	res = strings.Split(res, "\n")[0]
+	res = strings.TrimSpace(res)
+	return res
+}
+
+func utilsClenFileDataMoreLine(data string) (res string) {
+	res = utilsCheckAndRemoveBOM(data)
+	res = strings.Replace(res, "\r", "", -1)
+	return res
+}
+
+func utilsCheckAndRemoveBOM(s string) string {
+	// UTF-8 BOM 的字节序列为 0xEF, 0xBB, 0xBF
+	bom := []byte{0xEF, 0xBB, 0xBF}
+
+	// 将字符串转换为字节切片
+	bytes := []byte(s)
+
+	// 检查前三个字节是否是 BOM
+	if len(bytes) >= 3 && bytes[0] == bom[0] && bytes[1] == bom[1] && bytes[2] == bom[2] {
+		// 如果存在 BOM,则删除它
+		return string(bytes[3:])
+	}
+
+	// 如果不存在 BOM,则返回原始字符串
+	return s
+}

+ 1 - 0
src/cmd/lionv1/main.go

@@ -5,6 +5,7 @@
 package main
 
 import (
+	_ "github.com/SongZihuan/BackendServerTemplate/src/global"
 	lionv1 "github.com/SongZihuan/BackendServerTemplate/src/mainfunc/lion/v1"
 	"os"
 )

+ 1 - 0
src/cmd/tigerv1/main.go

@@ -5,6 +5,7 @@
 package main
 
 import (
+	_ "github.com/SongZihuan/BackendServerTemplate/src/global"
 	tigerv1 "github.com/SongZihuan/BackendServerTemplate/src/mainfunc/tiger/v1"
 	"os"
 )

+ 2 - 2
src/commandlineargs/define_data_type.go

@@ -7,7 +7,7 @@ package commandlineargs
 import (
 	"flag"
 	"fmt"
-	resource "github.com/SongZihuan/BackendServerTemplate"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/osutils"
 )
 
@@ -55,7 +55,7 @@ func initData() {
 
 		NameData:  "", // 默认值为空,具体Name为什么则由config决定
 		NameName:  "name",
-		NameUsage: fmt.Sprintf("Set the name of the running program, the default is %s.", resource.Name),
+		NameUsage: fmt.Sprintf("Set the name of the running program, the default is %s.", global.Name),
 
 		HelpData:  false,
 		HelpName:  "help",

+ 4 - 4
src/commandlineargs/export_printer.go

@@ -7,7 +7,7 @@ package commandlineargs
 import (
 	"flag"
 	"fmt"
-	resource "github.com/SongZihuan/BackendServerTemplate"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/osutils"
 	"io"
@@ -22,7 +22,7 @@ func (d *CommandLineArgsDataType) PrintUsage() (int, error) {
 }
 
 func (d *CommandLineArgsDataType) FprintVersion(writer io.Writer) (int, error) {
-	version := formatutils.FormatTextToWidth(fmt.Sprintf("Version of %s: %s", osutils.GetArgs0Name(), resource.Version), formatutils.NormalConsoleWidth)
+	version := formatutils.FormatTextToWidth(fmt.Sprintf("Version of %s: %s", osutils.GetArgs0Name(), global.SemanticVersioning), formatutils.NormalConsoleWidth)
 	return fmt.Fprintf(writer, "%s\n", version)
 }
 
@@ -32,7 +32,7 @@ func (d *CommandLineArgsDataType) PrintVersion() (int, error) {
 
 func (d *CommandLineArgsDataType) FprintLicense(writer io.Writer) (int, error) {
 	title := formatutils.FormatTextToWidth(fmt.Sprintf("License of %s:", osutils.GetArgs0Name()), formatutils.NormalConsoleWidth)
-	license := formatutils.FormatTextToWidth(resource.License, formatutils.NormalConsoleWidth)
+	license := formatutils.FormatTextToWidth(global.License, formatutils.NormalConsoleWidth)
 	return fmt.Fprintf(writer, "%s\n%s\n", title, license)
 }
 
@@ -42,7 +42,7 @@ func (d *CommandLineArgsDataType) PrintLicense() (int, error) {
 
 func (d *CommandLineArgsDataType) FprintReport(writer io.Writer) (int, error) {
 	// 不需要title
-	report := formatutils.FormatTextToWidth(resource.Report, formatutils.NormalConsoleWidth)
+	report := formatutils.FormatTextToWidth(global.Report, formatutils.NormalConsoleWidth)
 	return fmt.Fprintf(writer, "%s\n", report)
 }
 

+ 0 - 3
src/config/global_config.go

@@ -1,7 +1,6 @@
 package config
 
 import (
-	resource "github.com/SongZihuan/BackendServerTemplate"
 	"github.com/SongZihuan/BackendServerTemplate/src/commandlineargs"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configerror"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configparser"
@@ -57,8 +56,6 @@ func (d *GlobalConfig) process(c *configInfo) (cfgErr configerror.Error) {
 		global.Name = commandlineargs.Name()
 	} else if d.Name != "" {
 		global.Name = d.Name
-	} else {
-		global.Name = resource.Name
 	}
 
 	d.Name = global.Name

+ 17 - 3
src/global/variabl.go

@@ -9,7 +9,21 @@ import (
 	"time"
 )
 
-var Version = resource.Version
-var Name = resource.Name
+var (
+	// Version SemanticVersioning License Report 继承自resource
+	Version            = resource.Version
+	SemanticVersioning = resource.SemanticVersioning
+	License            = resource.License
+	Report             = resource.Report
+	BuildTime          = resource.BuildTime
+	GitCommitHash      = resource.GitCommitHash
+	GitTag             = resource.GitTag
+	GitTagCommitHash   = resource.GitTagCommitHash
 
-var Location *time.Location
+	// Name 当config读取配置文件加载时可能会被更改
+	Name = resource.Name
+)
+
+var (
+	Location *time.Location
+)

+ 2 - 1
src/server/example1/server.go

@@ -6,6 +6,7 @@ package example1
 
 import (
 	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/serverinterface"
 	"sync"
@@ -76,7 +77,7 @@ func (s *ServerExample1) Run() {
 
 MainCycle:
 	for {
-		fmt.Println("Example1: I am running!")
+		fmt.Printf("Example1: I am running! BuildDate: '%s' Commit: '%s' Version: '%s' Now: '%s'\n", global.BuildTime.Format(time.DateTime), global.GitCommitHash, global.Version, time.Now().Format(time.DateTime))
 
 		select {
 		case <-s.ctx.Listen():