ok-2
This commit is contained in:
@@ -1,193 +1,47 @@
|
||||
package initcmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sunhpc/internal/auth"
|
||||
"sunhpc/internal/db"
|
||||
"sunhpc/internal/log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
appName string = "sunhpc"
|
||||
defaultDBPath string = "/var/lib/sunhpc"
|
||||
defaultDBName string = "sunhpc.db"
|
||||
)
|
||||
func NewDatabaseCmd() *cobra.Command {
|
||||
var force bool
|
||||
|
||||
var (
|
||||
forceDB bool
|
||||
dbPath string
|
||||
dbName string
|
||||
dbFullPath string
|
||||
)
|
||||
|
||||
func initDBPathWithViper() error {
|
||||
/*
|
||||
从 Viper 配置文件获取数据库路径
|
||||
配置文件里的键要和 Viper.GetXXX 的键对应
|
||||
配置文件格式:
|
||||
db:
|
||||
path: "/tmp/sunhpc" # 自定义数据库路径
|
||||
name: "my_sunhpc.db" # 自定义数据库名
|
||||
*/
|
||||
|
||||
log.Infof("从 Viper 配置文件获取数据库路径...")
|
||||
|
||||
// ========== 第一步:设置 Viper 配置文件规则(核心) ==========
|
||||
// 1. 设置Viper基础规则
|
||||
viper.SetConfigType("yaml") // 配置文件类型
|
||||
viper.SetConfigName("config") // 配置文件名(不带后缀)
|
||||
viper.SetEnvPrefix(appName) // 环境变量前缀:SUNHPC_
|
||||
viper.AutomaticEnv() // 自动读取环境变量(可选,增强兼容性)
|
||||
|
||||
// 2. 添加配置文件搜索目录(Viper 会按顺序查找,找到第一个就停止)
|
||||
// 优先级:当前目录 → 用户级目录 → 系统级目录
|
||||
|
||||
// ① 当前目录(开发/测试常用)
|
||||
viper.AddConfigPath(".")
|
||||
|
||||
// ② Linux/macOS 用户级目录(~/.config/sunhpc/)
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
viper.AddConfigPath(filepath.Join(homeDir, ".config", appName))
|
||||
}
|
||||
// ③ Linux/macOS 系统级目录(/etc/sunhpc/)
|
||||
viper.AddConfigPath(filepath.Join("/etc", appName))
|
||||
|
||||
// ========== 第二步:设置默认值(最低优先级) ==========
|
||||
viper.SetDefault("db.path", defaultDBPath)
|
||||
viper.SetDefault("db.name", defaultDBName)
|
||||
|
||||
// ========== 第三步:绑定环境变量(优先级高于默认值,低于配置文件) ==========
|
||||
viper.BindEnv("db.path", "DB_PATH") // 绑定 SUNHPC_DB_PATH → db.path
|
||||
viper.BindEnv("db.name", "DB_NAME") // 绑定 SUNHPC_DB_NAME → db.name
|
||||
|
||||
// ========== 第四步:读取配置文件(优先级高于环境变量,低于默认值) ==========
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
log.Info("未找到配置文件,将使用环境变量/默认值")
|
||||
return nil // 配置文件存在但格式错误,返回错误
|
||||
}
|
||||
log.Warnf("读取配置文件失败: %v", err)
|
||||
return fmt.Errorf("读取配置文件失败: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("成功加载配置文件: %s", viper.ConfigFileUsed())
|
||||
return nil
|
||||
}
|
||||
|
||||
func initDBPath() error {
|
||||
|
||||
// 1. 从 Viper 配置文件获取数据库路径(加载配置文件->环境变量->默认值)
|
||||
if err := initDBPathWithViper(); err != nil {
|
||||
return fmt.Errorf("Viper初始化数据库失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 从Viper获取数据库路径
|
||||
dbPath = viper.GetString("db.path")
|
||||
dbName = viper.GetString("db.name")
|
||||
|
||||
// 3. 拼接数据库路径
|
||||
dbFullPath = filepath.Join(dbPath, dbName)
|
||||
log.Infof("数据库完整路径: %s", dbFullPath)
|
||||
|
||||
// 3. 检查数据库文件是否存在
|
||||
dir := filepath.Dir(dbFullPath)
|
||||
// 4. 检查数据库目录是否存在
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
log.Infof("数据库目录不存在,创建目录: %s", dir)
|
||||
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("创建数据库目录失败: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var databaseCmd = &cobra.Command{
|
||||
Use: "database",
|
||||
Short: "初始化数据库",
|
||||
Long: `初始化SQLite数据库,创建所有表结构和默认数据。
|
||||
cmd := &cobra.Command{
|
||||
Use: "database",
|
||||
Short: "初始化数据库",
|
||||
Long: `初始化SQLite数据库,创建所有表结构和默认数据。
|
||||
|
||||
示例:
|
||||
sunhpc init database # 初始化数据库
|
||||
sunhpc init database --force # 强制重新初始化`,
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := auth.RequireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug("初始化数据库...")
|
||||
|
||||
if err := initDBPath(); err != nil {
|
||||
return fmt.Errorf("初始化数据库路径失败: %w", err)
|
||||
}
|
||||
|
||||
log.Debugf("数据库目录存在: %s", dbPath)
|
||||
|
||||
// 强制模式:用户确认
|
||||
if forceDB {
|
||||
log.Warn("⚠️ 警告:强制重新初始化将清空数据库中的所有数据!")
|
||||
fmt.Printf("数据库路径: %s\n", dbFullPath)
|
||||
fmt.Print("确认要重新初始化数据库吗?这将删除所有现有数据。(Y/yes): ")
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取用户输入失败: %v", err)
|
||||
Annotations: map[string]string{
|
||||
"skip-db-check": "true", // 标记此命令跳过数据库检查
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := auth.RequireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
input = strings.TrimSpace(strings.ToLower(input))
|
||||
if input != "y" && input != "yes" {
|
||||
log.Info("操作已取消")
|
||||
return nil
|
||||
log.Info("初始化数据库...")
|
||||
if force {
|
||||
log.Warn("⚠️ 警告:强制重新初始化将清空数据库中的所有数据!")
|
||||
}
|
||||
|
||||
log.Info("用户确认重新初始化数据库")
|
||||
}
|
||||
|
||||
// 数据库存在且不是强制模式则跳过初始化
|
||||
if _, err := os.Stat(dbFullPath); err == nil && !forceDB {
|
||||
log.Infof("数据库文件已存在: %s", dbFullPath)
|
||||
dbInst := db.MustGetDB() // panic if fail (ok for CLI tool)
|
||||
if err := dbInst.InitSchema(force); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("数据库初始化完成")
|
||||
return nil
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// 初始化数据库(使用配置的路径)
|
||||
database, err := db.GetInstanceWithConfig(dbPath, dbName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("初始化数据库失败: %v", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
// 如果是强制模式,设置强制重新初始化标志
|
||||
if forceDB {
|
||||
database.SetForceInit(true)
|
||||
log.Info("强制重新初始化数据库表...")
|
||||
|
||||
// 关闭现有连接以触发重新连接
|
||||
if err := database.CloseConnection(); err != nil {
|
||||
return fmt.Errorf("关闭现有数据库连接失败: %v", err)
|
||||
}
|
||||
|
||||
// 重新连接并初始化
|
||||
if err := database.Connect(); err != nil {
|
||||
return fmt.Errorf("强制重新初始化数据库失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("数据库初始化成功: %s", dbFullPath)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
databaseCmd.Flags().BoolVarP(&forceDB, "force", "f", false, "强制重新初始化,删除现有数据库")
|
||||
Cmd.AddCommand(databaseCmd)
|
||||
cmd.Flags().BoolVarP(&force, "force", "f", false, "强制重新初始化")
|
||||
return cmd
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user