Refactoring complete: v0.4.0 architectural milestone (#1)
## Summary Completed Phase 5 refactoring and reached the target architecture. **Architectural milestone achieved:** - Service layer owns all state and is the sole writer - UI is a thin Fyne view, all widget updates marshaled via `fyne.Do` - Core engines are stateless and injectable - Domain types are pure (no `yaml:"-"` fields) - Full module builds and `go vet ./...` clean ## Changes - Bump version: 0.3.6 → 0.4.0 - Update CHANGELOG with Phase 5 summary - Add ROADMAP "Refactoring Follow-Ups" section ## Known follow-up work 1. **Linux test build broken** — `runner_test.go` needs `//go:build windows` tag 2. **File-size limits exceeded** — `operations.go` (486 lines), `jobs_view.go` (415 lines) See ROADMAP.md for details. --------- Co-authored-by: mixeme <mix.public@ya.ru> Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
// The config file stays beside the executable so the portable build behaves
|
||||
// predictably: moving the program folder moves its settings with it.
|
||||
ConfigFileName = "gosentry.yaml"
|
||||
// Older builds were named PySentry. Keep the old config name readable during
|
||||
// the rename window so portable installations can start once and rewrite the
|
||||
// settings to gosentry.yaml without manual file copying.
|
||||
LegacyConfigFileName = "pysentry.yaml"
|
||||
// Jobs are kept in a separate YAML file because the user can choose a
|
||||
// different jobs directory, while application settings remain local to the
|
||||
// installed/copied program.
|
||||
JobsFileName = "jobs.yaml"
|
||||
)
|
||||
|
||||
// Paths contains both the physical program location and the resolved runtime
|
||||
// storage locations. Keeping resolved paths in one struct prevents the GUI and
|
||||
// scheduler from interpreting relative directories differently.
|
||||
type Paths struct {
|
||||
ExecutablePath string
|
||||
AppDir string
|
||||
ConfigPath string
|
||||
JobsDir string
|
||||
JobsPath string
|
||||
LogsDir string
|
||||
DesktopIcon string
|
||||
}
|
||||
|
||||
func ResolvePaths() (Paths, error) {
|
||||
// os.Executable is used instead of the current working directory because GUI
|
||||
// apps are often launched from Explorer, a tray shortcut, or a desktop file.
|
||||
// In those cases the working directory can be surprising, but the executable
|
||||
// path is stable and matches the "portable app folder" storage model.
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
return Paths{}, err
|
||||
}
|
||||
|
||||
appDir := filepath.Dir(executable)
|
||||
configPath := filepath.Join(appDir, ConfigFileName)
|
||||
return Paths{
|
||||
ExecutablePath: executable,
|
||||
AppDir: appDir,
|
||||
ConfigPath: configPath,
|
||||
JobsDir: appDir,
|
||||
JobsPath: filepath.Join(appDir, JobsFileName),
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user