From fe83dc1f33586cad5a22b499c55bf7a513b07b42 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Wed, 19 Mar 2025 21:58:39 +0100 Subject: [PATCH] feat: add config and structured logging --- cmd/jws/main.go | 27 ++++++++++- go.mod | 16 +++++-- go.sum | 42 ++++++++++++++--- internal/config/config.go | 75 +++++++++++++++++++++++++++++++ internal/dependency/dependency.go | 41 +++++++++++++---- internal/gui/gui.go | 4 ++ internal/logger/logger.go | 54 ++++++++++++++++++++++ internal/os/osinfo.go | 12 ++++- internal/project/project.go | 35 ++++++++++----- 9 files changed, 275 insertions(+), 31 deletions(-) create mode 100644 internal/config/config.go create mode 100644 internal/logger/logger.go diff --git a/cmd/jws/main.go b/cmd/jws/main.go index 8588067..e5fa0b2 100644 --- a/cmd/jws/main.go +++ b/cmd/jws/main.go @@ -5,10 +5,14 @@ import ( "embed" "encoding/json" "fmt" + "jws/internal/config" "jws/internal/dependency" "jws/internal/gui" + "jws/internal/logger" "jws/internal/project" + "log/slog" "os" + "path/filepath" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" @@ -26,6 +30,24 @@ var ( ) func main() { + config, err := config.LoadConfig() + if err != nil { + fmt.Printf("Error loading config: %v\n", err) + os.Exit(1) + } + + logLevel := slog.LevelInfo + if config.LogLevel == "debug" { + logLevel = slog.LevelDebug + } + + err = logger.Init(config.LogFilePath, logLevel) + if err != nil { + fmt.Printf("Error initializing logger: %v\n", err) + os.Exit(1) + } + + logger.Logger.Info("Applikation started") a := app.New() mainWindow = a.NewWindow("JakartaEE & Spring Boot Starter") mainWindow.Resize(fyne.NewSize(600, 600)) @@ -62,7 +84,7 @@ func main() { } // Load additional projects from projects.json - pluginProjects, err := loadProjects("projects.json") + pluginProjects, err := loadProjects(filepath.Join(config.ProjectsPath, "projects.json")) if err != nil { dialog.ShowError(fmt.Errorf("error loading projects: %v", err), mainWindow) return @@ -70,8 +92,9 @@ func main() { projects = append(standartProjects, pluginProjects...) - // Initialize GUI package + // Initialize packages gui.Init(mainWindow, dependencies, projects, projectsFS) + project.Init(projects, config) // Check dependencies dependency.CheckDependencies(dependencies) diff --git a/go.mod b/go.mod index 2188dfe..d0b4ede 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.5 require ( fyne.io/fyne/v2 v2.6.0-alpha1 fyne.io/tools v1.0.0-alpha1 + github.com/spf13/viper v1.20.0 ) require ( @@ -12,7 +13,7 @@ require ( github.com/BurntSushi/toml v1.4.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fredbi/uri v1.1.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fyne-io/gl-js v0.1.0 // indirect github.com/fyne-io/glfw-js v0.1.0 // indirect github.com/fyne-io/image v0.1.0 // indirect @@ -20,20 +21,29 @@ require ( github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect github.com/go-text/render v0.2.0 // indirect github.com/go-text/typesetting v0.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 // indirect github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect - github.com/kr/text v0.2.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rymdport/portal v0.3.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect github.com/stretchr/testify v1.10.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/yuin/goldmark v1.7.8 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect golang.org/x/image v0.24.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a92ba16..02e6c16 100644 --- a/go.sum +++ b/go.sum @@ -6,15 +6,17 @@ fyne.io/tools v1.0.0-alpha1 h1:350eF+LVPbIHNgYPCoP04yCsQSFQ3aupATx33ClZjZk= fyne.io/tools v1.0.0-alpha1/go.mod h1:7gcHTl85tD/yLcGcU2bJGECAwSVAWrr99Ngmgrz/s54= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8= github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fyne-io/gl-js v0.1.0 h1:8luJzNs0ntEAJo+8x8kfUOXujUlP8gB3QMOxO2mUdpM= github.com/fyne-io/gl-js v0.1.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI= github.com/fyne-io/glfw-js v0.1.0 h1:RGGMmVjcsG17Oifl3X2UJ5vH3PgS4B1UY3ASeN5BXbI= @@ -31,14 +33,20 @@ github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc= github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o= github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M= github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= @@ -47,24 +55,48 @@ github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rymdport/portal v0.3.0 h1:QRHcwKwx3kY5JTQcsVhmhC3TGqGQb9LFghVNUy8AdB8= github.com/rymdport/portal v0.3.0/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= +github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..18b5db4 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,75 @@ +package config + +import ( + "os" + "path/filepath" + + "github.com/spf13/viper" +) + +type Config struct { + ProjectsPath string `mapstructure:"projects_path"` + LogLevel string `mapstructure:"log_level"` + LogFilePath string `mapstructure:"log_file_path"` + DeploymentPath string `mapstructure:"deployment_path"` +} + +func LoadConfig() (*Config, error) { + configDir, err := os.UserConfigDir() + if err != nil { + return nil, err + } + configPath := filepath.Join(configDir, "jws_gui") + viper.SetConfigName("config") + viper.SetConfigType("toml") + viper.AddConfigPath(configPath) + + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + // Config file not found, create default config + return createDefaultConfig(configPath) + } + return nil, err + } + + var config Config + if err := viper.Unmarshal(&config); err != nil { + return nil, err + } + + return &config, nil +} + +func createDefaultConfig(configPath string) (*Config, error) { + configDir, err := os.UserConfigDir() + if err != nil { + return nil, err + } + homeDir, err := os.UserHomeDir() + if err != nil { + return nil, err + } + + defaultConfig := Config{ + ProjectsPath: filepath.Join(configDir, "jws_gui", "projects"), + DeploymentPath: filepath.Join(homeDir, "Projects"), + LogLevel: "info", + LogFilePath: filepath.Join(configDir, "jws_gui", "logs", "jws_gui.log"), + } + + if err := os.MkdirAll(configPath, 0755); err != nil { + return nil, err + } + + viper.Set("projects_path", defaultConfig.ProjectsPath) + viper.Set("deployment_path", defaultConfig.DeploymentPath) + viper.Set("log_file_path", defaultConfig.LogFilePath) + viper.Set("log_level", defaultConfig.LogLevel) + + if err := viper.WriteConfigAs(filepath.Join(configPath, "config.toml")); err != nil { + return nil, err + } + + return &defaultConfig, nil + // ... (Rest der Funktion bleibt gleich) +} diff --git a/internal/dependency/dependency.go b/internal/dependency/dependency.go index 1a5ab38..cb4bb1d 100644 --- a/internal/dependency/dependency.go +++ b/internal/dependency/dependency.go @@ -2,9 +2,10 @@ package dependency import ( "fmt" + "jws/internal/logger" osinfo "jws/internal/os" "jws/pkg/download" - "log" + "log/slog" "os" "os/exec" "path/filepath" @@ -17,6 +18,12 @@ import ( "fyne.io/tools" ) +var log *slog.Logger + +func init() { + log = logger.GetChildLogger("dependency") +} + type Dependency struct { Name string Installed bool @@ -24,6 +31,7 @@ type Dependency struct { } func CheckDependencies(dependencies []Dependency) { + log.Info("Checking dependencies") // Check VSCode dependencies[0].Installed = checkVSCode() @@ -100,7 +108,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency wslInstallCmd := tools.CommandInShell("wsl", "--install") err = wslInstallCmd.Run() if err != nil { - dialog.ShowError(fmt.Errorf("error: installing WSL: %v", err), mainWindow) + errMsg := fmt.Errorf("error: installing WSL: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } dialog.ShowInformation("WSL wird installiert", "WSL wird installiert. Bitte warten Sie, bis die Installation abgeschlossen ist und starten Sie die Anwendung neu.", mainWindow) @@ -117,7 +127,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency brewInstallCmd := tools.CommandInShell("bin/bash", "-c", "\"$(curl -fsSl https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"") err := brewInstallCmd.Run() if err != nil { - dialog.ShowError(fmt.Errorf("error: installing homebrew falied: %v", err), mainWindow) + errMsg := fmt.Errorf("error: installing homebrew falied: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) } } switch index { @@ -129,7 +141,7 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency case "linux": osInfo, err := osinfo.GetLinuxDistribution() if err != nil { - log.Println(err) + log.Error(err.Error()) dialog.ShowError(fmt.Errorf("error getting OS info: %v", err), mainWindow) return } @@ -162,6 +174,7 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency progressDialog.Hide() if err != nil { + log.Error(err.Error()) dialog.ShowError(err, mainWindow) return } @@ -182,7 +195,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency output, err := cmd.CombinedOutput() if err != nil { - dialog.ShowError(fmt.Errorf("installation failed:\n%s", output), mainWindow) + errMsg := fmt.Errorf("installation failed:\n%s", output) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } else { dialog.ShowInformation("Erfolg", "VSCode erfolgreich installiert!", mainWindow) @@ -198,7 +213,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency osInfo, err := osinfo.GetLinuxDistribution() if err != nil { progressDialog.Hide() - dialog.ShowError(fmt.Errorf("error getting os infos: %v", err), mainWindow) + errMsg := fmt.Errorf("error getting os infos: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } @@ -268,7 +285,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency if output, err := command.CombinedOutput(); err != nil { progressDialog.Hide() - dialog.ShowError(fmt.Errorf("error at %s:\n%s", cmd, output), mainWindow) + errMsg := fmt.Errorf("error at %s:\n%s", cmd, output) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } @@ -282,7 +301,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency if output, err := command.CombinedOutput(); err != nil { progressDialog.Hide() - dialog.ShowError(fmt.Errorf("cleanup error at %s:\n%s", cmd, output), mainWindow) + errMsg := fmt.Errorf("cleanup error at %s:\n%s", cmd, output) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } @@ -306,7 +327,9 @@ func InstallDependency(index int, sudoPassword string, dependencies []Dependency if cmd != nil { err = cmd.Start() if err != nil { - dialog.ShowError(fmt.Errorf("error starting installation process: %v", err), mainWindow) + errMsg := fmt.Errorf("error starting installation process: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) } else { dialog.ShowInformation("Installation started", fmt.Sprintf("Installation of %s was started", depName), mainWindow) diff --git a/internal/gui/gui.go b/internal/gui/gui.go index be2ff2a..d286cb9 100644 --- a/internal/gui/gui.go +++ b/internal/gui/gui.go @@ -3,7 +3,9 @@ package gui import ( "embed" "jws/internal/dependency" + "jws/internal/logger" "jws/internal/project" + "log/slog" "fyne.io/fyne/v2" "fyne.io/fyne/v2/data/binding" @@ -17,10 +19,12 @@ var ( dependencies []dependency.Dependency projects []project.Project projectsFS embed.FS + log *slog.Logger ) // Init initializes the GUI package with required dependencies func Init(window fyne.Window, deps []dependency.Dependency, projs []project.Project, fs embed.FS) { + log = logger.GetChildLogger("gui") mainWindow = window dependencies = deps projects = projs diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..9e01358 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,54 @@ +package logger + +import ( + "fmt" + "log/slog" + "os" + "path/filepath" + "sync" +) + +var ( + Logger *slog.Logger + once sync.Once +) + +func Init(logFilePath string, logLevel slog.Level) error { + logDir := filepath.Dir(logFilePath) + if _, err := os.Stat(logDir); os.IsNotExist(err) { + err := os.MkdirAll(logDir, 0755) + if err != nil { + return err + } + } + + logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return err + } + + opts := &slog.HandlerOptions{ + Level: logLevel, + } + + fileHandler := slog.NewJSONHandler(logFile, opts) + Logger = slog.New(fileHandler) + + return nil +} + +func GetChildLogger(name string) *slog.Logger { + once.Do(func() { + configDir, err := os.UserConfigDir() + if err != nil { + fmt.Printf("error getting User Condfig Dir: %v\n", err) + } + logDir := filepath.Join(configDir, "jws_gui", "logs") + if Logger == nil { + defaultLogFilePath := filepath.Join(logDir, "jws_gui.log") + defaultLogLevel := slog.LevelInfo + Init(defaultLogFilePath, defaultLogLevel) + } + }) + return Logger.With("package", name) +} diff --git a/internal/os/osinfo.go b/internal/os/osinfo.go index e5f54da..80c83f4 100644 --- a/internal/os/osinfo.go +++ b/internal/os/osinfo.go @@ -2,7 +2,8 @@ package os import ( "fmt" - "log" + "jws/internal/logger" + "log/slog" "os" "os/exec" "strings" @@ -15,6 +16,12 @@ type OS struct { PackageManager string } +var log *slog.Logger + +func init() { + log = logger.GetChildLogger("os") +} + func GetLinuxDistribution() (*OS, error) { _, err := os.Stat("/etc/os-release") if os.IsNotExist(err) { @@ -49,7 +56,8 @@ func parseOsRelease(osRelease string) *OS { } err := result.getPackageManager() if err != nil { - log.Fatal(err) + log.Error(err.Error()) + os.Exit(1) } return &result } diff --git a/internal/project/project.go b/internal/project/project.go index 6e7dd9b..d7f6dd0 100644 --- a/internal/project/project.go +++ b/internal/project/project.go @@ -4,6 +4,9 @@ import ( "embed" "fmt" "io/fs" + "jws/internal/config" + "jws/internal/logger" + "log/slog" "os" "os/exec" "path/filepath" @@ -20,16 +23,22 @@ type Project struct { FolderName string `json:"folderName"` } +var ( + log *slog.Logger + projects []Project + conf config.Config +) + +func Init(projs []Project, config *config.Config) { + log = logger.GetChildLogger("project") + projects = projs + conf = *config +} + func DeployProject(index int, projects []Project, projectsFS embed.FS, mainWindow fyne.Window) { project := projects[index] - homeDir, err := os.UserHomeDir() - if err != nil { - dialog.ShowError(fmt.Errorf("error getting home directory: %v", err), mainWindow) - return - } - - projectPath := filepath.Join(homeDir, "Projects", project.FolderName) + projectPath := filepath.Join(conf.DeploymentPath, project.FolderName) confirmDialog := dialog.NewConfirm( "deploying project", @@ -47,14 +56,18 @@ func DeployProject(index int, projects []Project, projectsFS embed.FS, mainWindo progress.SetValue(0.1) err := os.MkdirAll(projectPath, 0755) if err != nil { - dialog.ShowError(fmt.Errorf("error creating directory: %v", err), mainWindow) + errMsg := fmt.Errorf("error creating directory: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } progress.SetValue(0.3) err = CopyEmbeddedProject(projectsFS, project.FolderName, projectPath) if err != nil { - dialog.ShowError(fmt.Errorf("error copying project files: %v", err), mainWindow) + errMsg := fmt.Errorf("error copying project files: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } @@ -74,7 +87,9 @@ func DeployProject(index int, projects []Project, projectsFS embed.FS, mainWindo progress.SetValue(0.9) err = openCmd.Run() if err != nil { - dialog.ShowError(fmt.Errorf("error opening VS Code: %v", err), mainWindow) + errMsg := fmt.Errorf("error opening VS Code: %v", err) + dialog.ShowError(errMsg, mainWindow) + log.Error(errMsg.Error()) return } }