diff --git a/cmd/envfile.go b/cmd/envfile.go index 8dfcf94..8303e7f 100644 --- a/cmd/envfile.go +++ b/cmd/envfile.go @@ -1,60 +1,107 @@ package FlareCMD import ( - "log/slog" + "fmt" "os" - "path" + "strings" FlareDefine "github.com/soulteary/flare/config/define" FlareModel "github.com/soulteary/flare/config/model" + FlareFn "github.com/soulteary/flare/internal/fn" FlareLogger "github.com/soulteary/flare/internal/logger" "gopkg.in/ini.v1" ) +func CheckDotEnvFileExist(filePath string) bool { + if _, err := os.Stat(filePath); os.IsNotExist(err) { + log := FlareLogger.GetLogger() + log.Debug("默认的 .env 文件不存在,跳过解析。") + return false + } + return true +} + +func GetDotEnvFileStringOrDefault(envs *ini.File, key string, def string) string { + value := strings.TrimSpace(envs.Section("").Key(key).String()) + if value == "" { + log := FlareLogger.GetLogger() + log.Debug(fmt.Sprintf("%s 配置文件值为空,使用默认值。", key)) + return def + } + return value +} + +func GetDotEnvFileBoolOrDefault(envs *ini.File, key string, def bool) bool { + value, err := envs.Section("").Key(key).Bool() + if err != nil { + log := FlareLogger.GetLogger() + log.Debug(fmt.Sprintf("%s 配置文件值异常,使用默认值。", key)) + return def + } + return value +} + func ParseEnvFile(baseFlags FlareModel.Flags) FlareModel.Flags { log := FlareLogger.GetLogger() - workDir, _ := os.Getwd() - envPath := path.Join(workDir, ".env") + envPath := FlareFn.GetWorkDirFile(".env") - if _, err := os.Stat(envPath); os.IsNotExist(err) { - log.Debug("默认的 .env 文件不存在,跳过解析。") + if !CheckDotEnvFileExist(envPath) { return baseFlags } envs, err := ini.Load(envPath) if err != nil { - log.Error("解析 .env 文件出错,请检查文件格式或程序是否具备文件读取权限。", slog.Any("error", err)) - os.Exit(1) + log.Error("解析 .env 文件出错,请检查文件格式或程序是否具备文件读取权限。") + log.Warn("程序将使用默认配置继续运行。") return baseFlags } - defaults := FlareDefine.GetDefaultEnvVars() + err = envs.MapTo(&FlareModel.Envs{}) + if err != nil { + log.Error("解析 .env 文件出错,请检查文件内容是否正确。") + log.Warn("程序使用默认配置继续运行。") + return baseFlags + } + + port, err := envs.Section("").Key("FLARE_PORT").Int() + if err != nil { + log.Warn("FLARE_PORT 的值不是有效的数字,使用默认值。") + } else { + if port < 1 || port > 65535 { + log.Warn("FLARE_PORT 的值不在有效范围内,使用默认值。") + } else { + baseFlags.Port = port + } + } - err = envs.MapTo(&defaults) + user := GetDotEnvFileStringOrDefault(envs, "FLARE_USER", baseFlags.User) + baseFlags.User = user - if envs.Section("").Key("FLARE_PASS") != nil { - baseFlags.User = defaults.Pass + defaults := FlareDefine.GetDefaultEnvVars() + + if user == defaults.User { baseFlags.UserIsGenerated = false - baseFlags.PassIsGenerated = false + } else { + baseFlags.UserIsGenerated = true } - if err != nil { - log.Error("解析 .env 文件出错,请检查文件内容是否正确。", slog.Any("error", err)) - os.Exit(1) + pass := GetDotEnvFileStringOrDefault(envs, "FLARE_PASS", baseFlags.Pass) + baseFlags.Pass = pass + if pass == defaults.Pass { + baseFlags.UserIsGenerated = false } else { - baseFlags.Port = defaults.Port - baseFlags.EnableGuide = defaults.EnableGuide - baseFlags.EnableDeprecatedNotice = defaults.EnableDeprecatedNotice - baseFlags.EnableMinimumRequest = defaults.EnableMinimumRequest - baseFlags.EnableOfflineMode = defaults.EnableOfflineMode - baseFlags.EnableEditor = defaults.EnableEditor - baseFlags.DisableCSP = defaults.DisableCSP - baseFlags.Visibility = defaults.Visibility - baseFlags.DisableLoginMode = defaults.DisableLoginMode - baseFlags.User = defaults.User - baseFlags.Pass = defaults.Pass + baseFlags.UserIsGenerated = true } + baseFlags.DisableLoginMode = GetDotEnvFileBoolOrDefault(envs, "FLARE_DISABLE_LOGIN", baseFlags.DisableLoginMode) + baseFlags.DisableCSP = GetDotEnvFileBoolOrDefault(envs, "FLARE_DISABLE_CSP", baseFlags.DisableCSP) + baseFlags.EnableDeprecatedNotice = GetDotEnvFileBoolOrDefault(envs, "FLARE_DEPRECATED_NOTICE", baseFlags.EnableDeprecatedNotice) + baseFlags.EnableMinimumRequest = GetDotEnvFileBoolOrDefault(envs, "FLARE_MINI_REQUEST", baseFlags.EnableMinimumRequest) + baseFlags.EnableOfflineMode = GetDotEnvFileBoolOrDefault(envs, "FLARE_OFFLINE", baseFlags.EnableOfflineMode) + baseFlags.EnableEditor = GetDotEnvFileBoolOrDefault(envs, "FLARE_EDITOR", baseFlags.EnableEditor) + baseFlags.EnableGuide = GetDotEnvFileBoolOrDefault(envs, "FLARE_GUIDE", baseFlags.EnableGuide) + baseFlags.Visibility = GetDotEnvFileStringOrDefault(envs, "FLARE_VISIBILITY", baseFlags.Visibility) + return baseFlags } diff --git a/cmd/envfile_test.go b/cmd/envfile_test.go index 05551c7..e788b2f 100644 --- a/cmd/envfile_test.go +++ b/cmd/envfile_test.go @@ -2,90 +2,139 @@ package FlareCMD_test import ( "os" - "path" "testing" FlareCMD "github.com/soulteary/flare/cmd" FlareDefine "github.com/soulteary/flare/config/define" + FlareFn "github.com/soulteary/flare/internal/fn" "github.com/stretchr/testify/assert" ) +func TestCheckDotEnvFileExist(t *testing.T) { + envPath := FlareFn.GetWorkDirFile(".env") + + // test .env not exist + os.Remove(envPath) + assert.Equal(t, FlareCMD.CheckDotEnvFileExist(envPath), false) + + // test .env exist + f, _ := os.Create(envPath) + defer os.Remove(f.Name()) + assert.Equal(t, FlareCMD.CheckDotEnvFileExist(envPath), true) +} + func TestParseEnvFile_NotExist(t *testing.T) { os.Setenv("FLARE_DEBUG", "true") defer os.Unsetenv("FLARE_DEBUG") envParsed := FlareCMD.ParseEnvVars() - - workDir, _ := os.Getwd() - envPath := path.Join(workDir, ".env") + envPath := FlareFn.GetWorkDirFile(".env") // test .env not exist os.Remove(envPath) flags := FlareCMD.ParseEnvFile(envParsed) - defaultEnvs := FlareDefine.GetDefaultEnvVars() - - assert.Equal(t, flags.Port, defaultEnvs.Port) - assert.Equal(t, flags.EnableGuide, defaultEnvs.EnableGuide) - assert.Equal(t, flags.EnableDeprecatedNotice, defaultEnvs.EnableDeprecatedNotice) - assert.Equal(t, flags.EnableMinimumRequest, defaultEnvs.EnableMinimumRequest) - assert.Equal(t, flags.DisableLoginMode, defaultEnvs.DisableLoginMode) - assert.Equal(t, flags.Visibility, defaultEnvs.Visibility) - assert.Equal(t, flags.EnableOfflineMode, defaultEnvs.EnableOfflineMode) - assert.Equal(t, flags.EnableEditor, defaultEnvs.EnableEditor) + assert.Equal(t, flags, envParsed) } -// func TestParseEnvFile_Normal(t *testing.T) { -// os.Setenv("FLARE_DEBUG", "true") -// defer os.Unsetenv("FLARE_DEBUG") - -// envParsed := FlareCMD.ParseEnvVars() - -// workDir, _ := os.Getwd() -// envPath := path.Join(workDir, ".env") - -// // test normal -// os.Remove(envPath) -// f, _ := os.Create(envPath) -// defer os.Remove(f.Name()) -// f.Write([]byte("FLARE_PORT=5000\nFLARE_GUIDE=false\nFLARE_OFFLINE=true\nFLARE_VISIBILITY=private")) -// flags := FlareCMD.ParseEnvFile(envParsed) -// assert.Equal(t, flags.Port, 5000) -// assert.Equal(t, flags.EnableGuide, false) -// assert.Equal(t, flags.EnableOfflineMode, true) -// assert.Equal(t, flags.Visibility, "private") -// } - -// func TestParseEnvFile_EmptyConfig(t *testing.T) { -// os.Setenv("FLARE_DEBUG", "true") -// defer os.Unsetenv("FLARE_DEBUG") - -// envParsed := FlareCMD.ParseEnvVars() -// defaultEnvs := FlareDefine.GetDefaultEnvVars() - -// workDir, _ := os.Getwd() -// envPath := path.Join(workDir, ".env") - -// // test empty .env -// os.Remove(envPath) -// f, _ := os.Create(envPath) -// defer os.Remove(f.Name()) -// f.Write([]byte("")) -// flags := FlareCMD.ParseEnvFile(envParsed) -// assert.Equal(t, flags.Port, defaultEnvs.Port) -// assert.Equal(t, flags.EnableGuide, defaultEnvs.EnableGuide) -// assert.Equal(t, flags.EnableDeprecatedNotice, defaultEnvs.EnableDeprecatedNotice) -// assert.Equal(t, flags.EnableMinimumRequest, defaultEnvs.EnableMinimumRequest) -// assert.Equal(t, flags.DisableLoginMode, defaultEnvs.DisableLoginMode) -// assert.Equal(t, flags.Visibility, defaultEnvs.Visibility) -// assert.Equal(t, flags.EnableOfflineMode, defaultEnvs.EnableOfflineMode) -// assert.Equal(t, flags.EnableEditor, defaultEnvs.EnableEditor) -// } - -// func TestParseEnvFile(t *testing.T) { -// // test unmarshal error -// // os.MkdirAll(".env", 0755) -// // defer os.Remove(".env") -// // flags := FlareCMD.ParseEnvFile(envParsed) -// // defaultEnvs := FlareDefine.GetDefaultEnvVars() -// // assert.Equal(t, flags.Port, defaultEnvs.Port) -// } +func TestParseEnvFile_NotParsed(t *testing.T) { + os.Setenv("FLARE_DEBUG", "true") + defer os.Unsetenv("FLARE_DEBUG") + + envParsed := FlareCMD.ParseEnvVars() + envPath := FlareFn.GetWorkDirFile(".env") + + // test .env not exist + os.Mkdir(envPath, 0755) + defer os.Remove(envPath) + flags := FlareCMD.ParseEnvFile(envParsed) + assert.Equal(t, flags, envParsed) +} + +func TestParseEnvFile_ParseErr(t *testing.T) { + os.Setenv("FLARE_DEBUG", "true") + defer os.Unsetenv("FLARE_DEBUG") + + envParsed := FlareCMD.ParseEnvVars() + envPath := FlareFn.GetWorkDirFile(".env") + envParsed.Port = 1234 + envParsed.User = "123" + envParsed.UserIsGenerated = true + envParsed.Pass = "123" + envParsed.PassIsGenerated = true + + // test .env auto correct + f, _ := os.Create(envPath) + defer os.Remove(envPath) + f.Write([]byte("FLARE_PORT=true\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=1111")) + flags := FlareCMD.ParseEnvFile(envParsed) + assert.Equal(t, flags, envParsed) +} + +func TestParseEnvFile_ParseOverwrite(t *testing.T) { + os.Setenv("FLARE_DEBUG", "true") + defer os.Unsetenv("FLARE_DEBUG") + + envParsed := FlareCMD.ParseEnvVars() + envPath := FlareFn.GetWorkDirFile(".env") + envParsed.Port = 1234 + envParsed.User = "123" + envParsed.UserIsGenerated = true + envParsed.Pass = "123" + envParsed.PassIsGenerated = true + + // test .env auto correct + f, _ := os.Create(envPath) + defer os.Remove(envPath) + f.Write([]byte("FLARE_PORT=2345\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=false")) + flags := FlareCMD.ParseEnvFile(envParsed) + + envParsed.Port = 2345 + envParsed.EnableGuide = false + + assert.Equal(t, flags, envParsed) +} + +func TestParseEnvFile_PortError(t *testing.T) { + os.Setenv("FLARE_DEBUG", "true") + defer os.Unsetenv("FLARE_DEBUG") + + envParsed := FlareCMD.ParseEnvVars() + envPath := FlareFn.GetWorkDirFile(".env") + envParsed.Port = 1234 + envParsed.User = "123" + envParsed.UserIsGenerated = true + envParsed.Pass = "123" + envParsed.PassIsGenerated = true + + // test .env auto correct + f, _ := os.Create(envPath) + defer os.Remove(envPath) + f.Write([]byte("FLARE_PORT=9999999\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=false")) + flags := FlareCMD.ParseEnvFile(envParsed) + + envParsed.EnableGuide = false + + assert.Equal(t, flags, envParsed) +} + +func TestParseEnvFile_User(t *testing.T) { + os.Setenv("FLARE_DEBUG", "true") + defer os.Unsetenv("FLARE_DEBUG") + + defaults := FlareDefine.GetDefaultEnvVars() + + envParsed := FlareCMD.ParseEnvVars() + envPath := FlareFn.GetWorkDirFile(".env") + envParsed.User = defaults.User + envParsed.Pass = defaults.Pass + envParsed.UserIsGenerated = false + envParsed.PassIsGenerated = false + + // test .env auto correct + f, _ := os.Create(envPath) + defer os.Remove(envPath) + f.Write([]byte("FLARE_PORT=5005\nFLARE_USER=flare\nFLARE_PASS=\n")) + flags := FlareCMD.ParseEnvFile(envParsed) + + assert.Equal(t, flags, envParsed) +} diff --git a/config/define/cmd.go b/config/define/cmd.go index 9fb0230..3105224 100644 --- a/config/define/cmd.go +++ b/config/define/cmd.go @@ -28,5 +28,8 @@ func GetDefaultEnvVars() FlareModel.Envs { EnableEditor: DEFAULT_ENABLE_EDITOR, Visibility: DEFAULT_VISIBILITY, DisableCSP: DEFAULT_DISABLE_CSP, + + User: DEFAULT_USER_NAME, + Pass: "", } } diff --git a/internal/fn/fn.go b/internal/fn/fn.go new file mode 100644 index 0000000..6e11f67 --- /dev/null +++ b/internal/fn/fn.go @@ -0,0 +1,15 @@ +package FlareFn + +import ( + "os" + "path" +) + +func GetWorkDir() string { + workDir, _ := os.Getwd() + return workDir +} + +func GetWorkDirFile(filename string) string { + return path.Join(GetWorkDir(), ".env") +}