From 64792780a2eeaade35d3f2697da736cef2b85207 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 24 Aug 2025 14:05:09 +0200 Subject: [PATCH 1/3] fix: infer logger type in logger generics migration --- cmd/internal/migrations/lists.go | 1 + cmd/internal/migrations/v3/logger_generics.go | 73 ++++++++++++++++ .../migrations/v3/logger_generics_test.go | 86 +++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 cmd/internal/migrations/v3/logger_generics.go create mode 100644 cmd/internal/migrations/v3/logger_generics_test.go diff --git a/cmd/internal/migrations/lists.go b/cmd/internal/migrations/lists.go index 8ea4fb1..dd8ca56 100644 --- a/cmd/internal/migrations/lists.go +++ b/cmd/internal/migrations/lists.go @@ -43,6 +43,7 @@ var Migrations = []Migration{ v3migrations.MigrateAddMethod, v3migrations.MigrateMimeConstants, v3migrations.MigrateLoggerTags, + v3migrations.MigrateLoggerGenerics, v3migrations.MigrateStaticRoutes, v3migrations.MigrateTrustedProxyConfig, v3migrations.MigrateMount, diff --git a/cmd/internal/migrations/v3/logger_generics.go b/cmd/internal/migrations/v3/logger_generics.go new file mode 100644 index 0000000..96479a3 --- /dev/null +++ b/cmd/internal/migrations/v3/logger_generics.go @@ -0,0 +1,73 @@ +package v3 + +import ( + "fmt" + "regexp" + + semver "github.com/Masterminds/semver/v3" + "github.com/spf13/cobra" + + "github.com/gofiber/cli/cmd/internal" +) + +func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) error { + reAllLogger := regexp.MustCompile(`(\w+)\.AllLogger([^\w\[]|$)`) + reConfigurableLogger := regexp.MustCompile(`(\w+)\.ConfigurableLogger([^\w\[]|$)`) + reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\(\)`) + reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\(`) + reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\(`) + reLoggerType := regexp.MustCompile(`(?m)^func\s+(?:\(\w+\s+\*?\w+\)\s+)?Logger\(\)\s*(\*?\w+(?:\.\w+)*)\s*{`) + + changed, err := internal.ChangeFileContent(cwd, func(content string) string { + loggerType := "any" + if m := reLoggerType.FindStringSubmatch(content); len(m) == 2 { + loggerType = m[1] + } + + content = reAllLogger.ReplaceAllStringFunc(content, func(m string) string { + sub := reAllLogger.FindStringSubmatch(m) + if len(sub) != 3 { + return m + } + return fmt.Sprintf("%s.AllLogger[%s]%s", sub[1], loggerType, sub[2]) + }) + content = reConfigurableLogger.ReplaceAllStringFunc(content, func(m string) string { + sub := reConfigurableLogger.FindStringSubmatch(m) + if len(sub) != 3 { + return m + } + return fmt.Sprintf("%s.ConfigurableLogger[%s]%s", sub[1], loggerType, sub[2]) + }) + content = reDefaultLogger.ReplaceAllStringFunc(content, func(m string) string { + sub := reDefaultLogger.FindStringSubmatch(m) + if len(sub) != 2 { + return m + } + return fmt.Sprintf("%s.DefaultLogger[%s]()", sub[1], loggerType) + }) + content = reSetLogger.ReplaceAllStringFunc(content, func(m string) string { + sub := reSetLogger.FindStringSubmatch(m) + if len(sub) != 2 { + return m + } + return fmt.Sprintf("%s.SetLogger[%s](", sub[1], loggerType) + }) + content = reLoggerToWriter.ReplaceAllStringFunc(content, func(m string) string { + sub := reLoggerToWriter.FindStringSubmatch(m) + if len(sub) != 2 { + return m + } + return fmt.Sprintf("%s.LoggerToWriter[%s](", sub[1], loggerType) + }) + return content + }) + if err != nil { + return fmt.Errorf("failed to migrate logger generics: %w", err) + } + if !changed { + return nil + } + + cmd.Println("Migrating logger generics") + return nil +} diff --git a/cmd/internal/migrations/v3/logger_generics_test.go b/cmd/internal/migrations/v3/logger_generics_test.go new file mode 100644 index 0000000..048655d --- /dev/null +++ b/cmd/internal/migrations/v3/logger_generics_test.go @@ -0,0 +1,86 @@ +package v3_test + +import ( + "bytes" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/gofiber/cli/cmd/internal/migrations/v3" +) + +func Test_MigrateLoggerGenerics(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mloggenericstest") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file := writeTempFile(t, dir, `package main +import ( + fiberlog "github.com/gofiber/fiber/v2/log" +) +var _ fiberlog.AllLogger = (*customLogger)(nil) +var _ fiberlog.ConfigurableLogger = (*customLogger)(nil) +func main() { + logger := fiberlog.DefaultLogger() + fiberlog.SetLogger(logger) + _ = fiberlog.LoggerToWriter(logger, fiberlog.LevelInfo) +} +`) + + var buf bytes.Buffer + cmd := newCmd(&buf) + require.NoError(t, v3.MigrateLoggerGenerics(cmd, dir, nil, nil)) + + content := readFile(t, file) + assert.NotContains(t, content, "AllLogger =") + assert.NotContains(t, content, "ConfigurableLogger =") + assert.Contains(t, content, "AllLogger[any]") + assert.Contains(t, content, "ConfigurableLogger[any]") + assert.Contains(t, content, "DefaultLogger[any]()") + assert.Contains(t, content, "SetLogger[any](") + assert.Contains(t, content, "LoggerToWriter[any](") + assert.Contains(t, buf.String(), "Migrating logger generics") +} + +func Test_MigrateLoggerGenerics_Zap(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mloggenericstestzap") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file := writeTempFile(t, dir, `package main +import ( + fiberlog "github.com/gofiber/fiber/v2/log" + "go.uber.org/zap" +) +type customLogger struct{} +func (c *customLogger) Logger() *zap.Logger { return nil } +var _ fiberlog.AllLogger = (*customLogger)(nil) +var _ fiberlog.ConfigurableLogger = (*customLogger)(nil) +func main() { + logger := &customLogger{} + fiberlog.SetLogger(logger) + _ = fiberlog.LoggerToWriter(logger, fiberlog.LevelInfo) + _ = fiberlog.DefaultLogger().Logger() +} +`) + + var buf bytes.Buffer + cmd := newCmd(&buf) + require.NoError(t, v3.MigrateLoggerGenerics(cmd, dir, nil, nil)) + + content := readFile(t, file) + assert.NotContains(t, content, "AllLogger =") + assert.NotContains(t, content, "ConfigurableLogger =") + assert.Contains(t, content, "AllLogger[*zap.Logger]") + assert.Contains(t, content, "ConfigurableLogger[*zap.Logger]") + assert.Contains(t, content, "SetLogger[*zap.Logger](") + assert.Contains(t, content, "LoggerToWriter[*zap.Logger](") + assert.Contains(t, content, "DefaultLogger[*zap.Logger]()") + assert.Contains(t, buf.String(), "Migrating logger generics") +} From 276fd30ccbde5c1aa422050c60d0c1493a51bb65 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 24 Aug 2025 14:21:37 +0200 Subject: [PATCH 2/3] fix: restrict logger migration to fiber log --- cmd/internal/migrations/v3/logger_generics.go | 45 +++++++++++++++-- .../migrations/v3/logger_generics_test.go | 49 +++++++++++++++---- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/cmd/internal/migrations/v3/logger_generics.go b/cmd/internal/migrations/v3/logger_generics.go index 96479a3..6b9183e 100644 --- a/cmd/internal/migrations/v3/logger_generics.go +++ b/cmd/internal/migrations/v3/logger_generics.go @@ -2,7 +2,11 @@ package v3 import ( "fmt" + "go/parser" + "go/token" "regexp" + "strconv" + "strings" semver "github.com/Masterminds/semver/v3" "github.com/spf13/cobra" @@ -11,14 +15,45 @@ import ( ) func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) error { - reAllLogger := regexp.MustCompile(`(\w+)\.AllLogger([^\w\[]|$)`) - reConfigurableLogger := regexp.MustCompile(`(\w+)\.ConfigurableLogger([^\w\[]|$)`) - reDefaultLogger := regexp.MustCompile(`(\w+)\.DefaultLogger\(\)`) - reSetLogger := regexp.MustCompile(`(\w+)\.SetLogger\(`) - reLoggerToWriter := regexp.MustCompile(`(\w+)\.LoggerToWriter\(`) + fiberImport := regexp.MustCompile(`^github\.com/gofiber/fiber/v\d+/log$`) reLoggerType := regexp.MustCompile(`(?m)^func\s+(?:\(\w+\s+\*?\w+\)\s+)?Logger\(\)\s*(\*?\w+(?:\.\w+)*)\s*{`) changed, err := internal.ChangeFileContent(cwd, func(content string) string { + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, "", content, parser.ImportsOnly) + if err != nil { + return content + } + + aliases := make([]string, 0, len(file.Imports)) + for _, imp := range file.Imports { + path, err := strconv.Unquote(imp.Path.Value) + if err != nil { + continue + } + if !fiberImport.MatchString(path) { + continue + } + alias := "log" + if imp.Name != nil { + alias = imp.Name.Name + } else if idx := strings.LastIndex(path, "/"); idx != -1 { + alias = path[idx+1:] + } + aliases = append(aliases, regexp.QuoteMeta(alias)) + } + + if len(aliases) == 0 { + return content + } + + aliasPattern := strings.Join(aliases, "|") + reAllLogger := regexp.MustCompile(fmt.Sprintf("(%s)\\.AllLogger([^\\w\\[]|$)", aliasPattern)) + reConfigurableLogger := regexp.MustCompile(fmt.Sprintf("(%s)\\.ConfigurableLogger([^\\w\\[]|$)", aliasPattern)) + reDefaultLogger := regexp.MustCompile(fmt.Sprintf("(%s)\\.DefaultLogger\\(\\)", aliasPattern)) + reSetLogger := regexp.MustCompile(fmt.Sprintf("(%s)\\.SetLogger\\(", aliasPattern)) + reLoggerToWriter := regexp.MustCompile(fmt.Sprintf("(%s)\\.LoggerToWriter\\(", aliasPattern)) + loggerType := "any" if m := reLoggerType.FindStringSubmatch(content); len(m) == 2 { loggerType = m[1] diff --git a/cmd/internal/migrations/v3/logger_generics_test.go b/cmd/internal/migrations/v3/logger_generics_test.go index 048655d..da23d91 100644 --- a/cmd/internal/migrations/v3/logger_generics_test.go +++ b/cmd/internal/migrations/v3/logger_generics_test.go @@ -20,14 +20,14 @@ func Test_MigrateLoggerGenerics(t *testing.T) { file := writeTempFile(t, dir, `package main import ( - fiberlog "github.com/gofiber/fiber/v2/log" + "github.com/gofiber/fiber/v2/log" ) -var _ fiberlog.AllLogger = (*customLogger)(nil) -var _ fiberlog.ConfigurableLogger = (*customLogger)(nil) +var _ log.AllLogger = (*customLogger)(nil) +var _ log.ConfigurableLogger = (*customLogger)(nil) func main() { - logger := fiberlog.DefaultLogger() - fiberlog.SetLogger(logger) - _ = fiberlog.LoggerToWriter(logger, fiberlog.LevelInfo) + logger := log.DefaultLogger() + log.SetLogger(logger) + _ = log.LoggerToWriter(logger, log.LevelInfo) } `) @@ -40,9 +40,9 @@ func main() { assert.NotContains(t, content, "ConfigurableLogger =") assert.Contains(t, content, "AllLogger[any]") assert.Contains(t, content, "ConfigurableLogger[any]") - assert.Contains(t, content, "DefaultLogger[any]()") - assert.Contains(t, content, "SetLogger[any](") - assert.Contains(t, content, "LoggerToWriter[any](") + assert.Contains(t, content, "log.DefaultLogger[any]()") + assert.Contains(t, content, "log.SetLogger[any](") + assert.Contains(t, content, "log.LoggerToWriter[any](") assert.Contains(t, buf.String(), "Migrating logger generics") } @@ -84,3 +84,34 @@ func main() { assert.Contains(t, content, "DefaultLogger[*zap.Logger]()") assert.Contains(t, buf.String(), "Migrating logger generics") } + +func Test_MigrateLoggerGenerics_SkipNonFiber(t *testing.T) { + t.Parallel() + + dir, err := os.MkdirTemp("", "mloggenericstestskip") + require.NoError(t, err) + defer func() { require.NoError(t, os.RemoveAll(dir)) }() + + file := writeTempFile(t, dir, `package main +import ( + otherlog "example.com/other/log" +) +var _ otherlog.AllLogger = (*customLogger)(nil) +var _ otherlog.ConfigurableLogger = (*customLogger)(nil) +func main() { + logger := otherlog.DefaultLogger() + otherlog.SetLogger(logger) + _ = otherlog.LoggerToWriter(logger, otherlog.LevelInfo) +} +`) + + var buf bytes.Buffer + cmd := newCmd(&buf) + require.NoError(t, v3.MigrateLoggerGenerics(cmd, dir, nil, nil)) + + content := readFile(t, file) + assert.Contains(t, content, "otherlog.DefaultLogger()") + assert.NotContains(t, content, "AllLogger[") + assert.NotContains(t, content, "ConfigurableLogger[") + assert.NotContains(t, buf.String(), "Migrating logger generics") +} From 4ddaf50cf2387927d8dba1cd55fcdd1373084528 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 24 Aug 2025 14:31:54 +0200 Subject: [PATCH 3/3] refactor: consolidate logger migrator replacements --- cmd/internal/migrations/v3/logger_generics.go | 64 +++++++++---------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/cmd/internal/migrations/v3/logger_generics.go b/cmd/internal/migrations/v3/logger_generics.go index 6b9183e..9423aa8 100644 --- a/cmd/internal/migrations/v3/logger_generics.go +++ b/cmd/internal/migrations/v3/logger_generics.go @@ -59,41 +59,35 @@ func MigrateLoggerGenerics(cmd *cobra.Command, cwd string, _, _ *semver.Version) loggerType = m[1] } - content = reAllLogger.ReplaceAllStringFunc(content, func(m string) string { - sub := reAllLogger.FindStringSubmatch(m) - if len(sub) != 3 { - return m - } - return fmt.Sprintf("%s.AllLogger[%s]%s", sub[1], loggerType, sub[2]) - }) - content = reConfigurableLogger.ReplaceAllStringFunc(content, func(m string) string { - sub := reConfigurableLogger.FindStringSubmatch(m) - if len(sub) != 3 { - return m - } - return fmt.Sprintf("%s.ConfigurableLogger[%s]%s", sub[1], loggerType, sub[2]) - }) - content = reDefaultLogger.ReplaceAllStringFunc(content, func(m string) string { - sub := reDefaultLogger.FindStringSubmatch(m) - if len(sub) != 2 { - return m - } - return fmt.Sprintf("%s.DefaultLogger[%s]()", sub[1], loggerType) - }) - content = reSetLogger.ReplaceAllStringFunc(content, func(m string) string { - sub := reSetLogger.FindStringSubmatch(m) - if len(sub) != 2 { - return m - } - return fmt.Sprintf("%s.SetLogger[%s](", sub[1], loggerType) - }) - content = reLoggerToWriter.ReplaceAllStringFunc(content, func(m string) string { - sub := reLoggerToWriter.FindStringSubmatch(m) - if len(sub) != 2 { - return m - } - return fmt.Sprintf("%s.LoggerToWriter[%s](", sub[1], loggerType) - }) + type replacement struct { + re *regexp.Regexp + format string + expectedSubmatch int + } + + replacements := []replacement{ + {reAllLogger, "%s.AllLogger[%s]%s", 3}, + {reConfigurableLogger, "%s.ConfigurableLogger[%s]%s", 3}, + {reDefaultLogger, "%s.DefaultLogger[%s]()", 2}, + {reSetLogger, "%s.SetLogger[%s](", 2}, + {reLoggerToWriter, "%s.LoggerToWriter[%s](", 2}, + } + + for _, r := range replacements { + content = r.re.ReplaceAllStringFunc(content, func(m string) string { + sub := r.re.FindStringSubmatch(m) + if len(sub) != r.expectedSubmatch { + return m + } + + args := []any{sub[1], loggerType} + if len(sub) > 2 { + args = append(args, sub[2]) + } + + return fmt.Sprintf(r.format, args...) + }) + } return content }) if err != nil {