feat: migrate config beside executable
This commit is contained in:
+32
-32
@@ -28,6 +28,8 @@ import (
|
||||
|
||||
const version = "0.1.0-dev"
|
||||
|
||||
var openDefaultConfig = config.OpenDefault
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
os.Exit(runCLI(os.Args[1:], os.Stdout, os.Stderr))
|
||||
@@ -53,14 +55,9 @@ func runCLI(args []string, out, errout io.Writer) int {
|
||||
fmt.Fprintln(out, "chub [start|list|stop|restart|events]")
|
||||
return 0
|
||||
}
|
||||
path, err := config.DefaultPath()
|
||||
store, err := openDefaultConfig()
|
||||
if err != nil {
|
||||
writeCLIError(errout, "system_error", err.Error())
|
||||
return 6
|
||||
}
|
||||
store, err := config.New(path)
|
||||
if err != nil {
|
||||
writeCLIError(errout, "system_error", err.Error())
|
||||
writeCLIError(errout, "system_error", "default configuration is unavailable")
|
||||
return 6
|
||||
}
|
||||
switch command {
|
||||
@@ -157,32 +154,35 @@ func runWindow(logger *slog.Logger) {
|
||||
return "", errors.New("不支持的搜索字段")
|
||||
}
|
||||
}, window.Invalidate)
|
||||
if path, err := config.DefaultPath(); err == nil {
|
||||
if store, err := config.New(path); err == nil {
|
||||
if saved, err := store.Load(); err == nil {
|
||||
shell.SetSettings(ui.SettingsState{ChromePath: saved.Settings.ChromePath, EdgePath: saved.Settings.EdgePath, DefaultDir: saved.Settings.DefaultDir, LogDir: saved.Settings.LogDir, RemoteDebugStartPort: saved.Settings.RemoteDebugStartPort, CloseOnExit: saved.Settings.CloseOnExit})
|
||||
proxies.Set(saved.Proxies)
|
||||
shell.SetProxies(proxyOptions(saved.Proxies))
|
||||
rows := make([]ui.InstanceRow, 0, len(saved.Instances))
|
||||
for _, item := range saved.Instances {
|
||||
rows = append(rows, ui.InstanceRow{ID: item.ID, Name: item.Name, Browser: browserLabel(item.Launch.Kind), UserDataDir: item.Launch.UserDataDir, TargetURL: item.Launch.TargetURL, ProxyID: item.ProxyID, PreferredRemoteDebugPort: item.PreferredRemoteDebugPort, Status: "已退出"})
|
||||
}
|
||||
shell.SetInstances(rows)
|
||||
shell.OnSave(func(value ui.SettingsState) {
|
||||
saved.Settings = config.Settings{ChromePath: value.ChromePath, EdgePath: value.EdgePath, DefaultDir: value.DefaultDir, LogDir: value.LogDir, RemoteDebugStartPort: value.RemoteDebugStartPort, CloseOnExit: value.CloseOnExit}
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
shell.OnInstancesChanged(func(rows []ui.InstanceRow) {
|
||||
saved.Instances = mergeInstanceConfig(saved.Instances, rows)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
shell.OnProxiesChanged(func(options []ui.ProxyOption) {
|
||||
saved.Proxies = mergeProxyConfig(saved.Proxies, options)
|
||||
proxies.Set(saved.Proxies)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
}
|
||||
store, err := openDefaultConfig()
|
||||
if err != nil {
|
||||
logger.Error("open default configuration", "error", err)
|
||||
shell.ReportStartupIssue("程序目录中的 config.json 无法使用;请检查目录权限或恢复旧配置。")
|
||||
} else if saved, err := store.Load(); err != nil {
|
||||
logger.Error("load default configuration", "error", err)
|
||||
shell.ReportStartupIssue("程序目录中的 config.json 无法读取;请恢复有效配置后重试。")
|
||||
} else {
|
||||
shell.SetSettings(ui.SettingsState{ChromePath: saved.Settings.ChromePath, EdgePath: saved.Settings.EdgePath, DefaultDir: saved.Settings.DefaultDir, LogDir: saved.Settings.LogDir, RemoteDebugStartPort: saved.Settings.RemoteDebugStartPort, CloseOnExit: saved.Settings.CloseOnExit})
|
||||
proxies.Set(saved.Proxies)
|
||||
shell.SetProxies(proxyOptions(saved.Proxies))
|
||||
rows := make([]ui.InstanceRow, 0, len(saved.Instances))
|
||||
for _, item := range saved.Instances {
|
||||
rows = append(rows, ui.InstanceRow{ID: item.ID, Name: item.Name, Browser: browserLabel(item.Launch.Kind), UserDataDir: item.Launch.UserDataDir, TargetURL: item.Launch.TargetURL, ProxyID: item.ProxyID, PreferredRemoteDebugPort: item.PreferredRemoteDebugPort, Status: "已退出"})
|
||||
}
|
||||
shell.SetInstances(rows)
|
||||
shell.OnSave(func(value ui.SettingsState) {
|
||||
saved.Settings = config.Settings{ChromePath: value.ChromePath, EdgePath: value.EdgePath, DefaultDir: value.DefaultDir, LogDir: value.LogDir, RemoteDebugStartPort: value.RemoteDebugStartPort, CloseOnExit: value.CloseOnExit}
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
shell.OnInstancesChanged(func(rows []ui.InstanceRow) {
|
||||
saved.Instances = mergeInstanceConfig(saved.Instances, rows)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
shell.OnProxiesChanged(func(options []ui.ProxyOption) {
|
||||
saved.Proxies = mergeProxyConfig(saved.Proxies, options)
|
||||
proxies.Set(saved.Proxies)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
}
|
||||
var ops op.Ops
|
||||
for {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -21,6 +22,33 @@ func TestRunCLIRejectsUnknownCommandWithStableCode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCLIUsesPortableDefaultStore(t *testing.T) {
|
||||
store, err := config.New(filepath.Join(t.TempDir(), "config.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := store.Save(config.File{Instances: []config.Instance{{ID: "portable", Name: "便携实例", PreferredRemoteDebugPort: 9666}}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
restore := openDefaultConfig
|
||||
openDefaultConfig = func() (*config.Store, error) { return store, nil }
|
||||
t.Cleanup(func() { openDefaultConfig = restore })
|
||||
var out bytes.Buffer
|
||||
if code := runCLI([]string{"list"}, &out, &out); code != 0 || !strings.Contains(out.String(), `"portable"`) {
|
||||
t.Fatalf("code=%d output=%s", code, out.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCLIReportsUnavailablePortableConfigWithoutDetails(t *testing.T) {
|
||||
restore := openDefaultConfig
|
||||
openDefaultConfig = func() (*config.Store, error) { return nil, config.ErrDefaultConfigUnavailable }
|
||||
t.Cleanup(func() { openDefaultConfig = restore })
|
||||
var out bytes.Buffer
|
||||
if code := runCLI([]string{"list"}, &out, &out); code != 6 || !strings.Contains(out.String(), `"default configuration is unavailable"`) {
|
||||
t.Fatalf("code=%d output=%s", code, out.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstanceStarterBuildsLaunchSpecFromInstanceAndSettings(t *testing.T) {
|
||||
launcher := &fakeProcessLauncher{handle: fakeProcessHandle{pid: 4242}}
|
||||
resolver := &fakeExecutableResolver{path: `C:\Browser\msedge.exe`}
|
||||
|
||||
Reference in New Issue
Block a user