mirror of
https://github.com/go-task/task.git
synced 2026-09-01 19:50:16 +02:00
feat(templater): report template deprecations through the verbose logger
sprout logs its deprecation notices to stdout by default, which would corrupt the JSON and group output styles. Route them to the Executor's logger at verbose level instead, deduplicated so that a single deprecated call is not reported once per compilation pass.
This commit is contained in:
@@ -63,7 +63,7 @@ var legacySprigAliases = sprout.FunctionAliasMap{
|
||||
|
||||
func init() {
|
||||
handler := sprout.New(
|
||||
sprout.WithLogger(slog.New(slog.DiscardHandler)),
|
||||
sprout.WithLogger(slog.New(noticeHandler{})),
|
||||
sprout.WithRegistries(
|
||||
taskfuncs.NewRegistry(),
|
||||
backward.NewRegistry(),
|
||||
|
||||
57
internal/templater/notices.go
Normal file
57
internal/templater/notices.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package templater
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// NoticeFunc receives the deprecation notices that sprout emits when a
|
||||
// template calls a deprecated function name or uses a deprecated argument
|
||||
// order.
|
||||
type NoticeFunc func(format string, args ...any)
|
||||
|
||||
// noticeSink is set once the Executor has built its logger. Until then — and
|
||||
// the function map is built in an init(), long before that — notices are
|
||||
// dropped rather than written to sprout's default stdout handler, which would
|
||||
// corrupt the JSON and group output styles.
|
||||
var noticeSink atomic.Pointer[NoticeFunc]
|
||||
|
||||
// SetNoticeSink installs the destination for template deprecation notices.
|
||||
// Passing nil silences them again.
|
||||
func SetNoticeSink(fn NoticeFunc) {
|
||||
noticeSeen.Clear()
|
||||
if fn == nil {
|
||||
noticeSink.Store(nil)
|
||||
return
|
||||
}
|
||||
noticeSink.Store(&fn)
|
||||
}
|
||||
|
||||
type noticeHandler struct{}
|
||||
|
||||
func (noticeHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
return level >= slog.LevelWarn && noticeSink.Load() != nil
|
||||
}
|
||||
|
||||
// noticeSeen keeps each distinct notice to a single line. Task renders the
|
||||
// same templates several times per run — once per compilation pass — so
|
||||
// without this a lone deprecated call would be reported over and over.
|
||||
var noticeSeen sync.Map
|
||||
|
||||
func (noticeHandler) Handle(_ context.Context, record slog.Record) error {
|
||||
fn := noticeSink.Load()
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
if _, dup := noticeSeen.LoadOrStore(record.Message, struct{}{}); dup {
|
||||
return nil
|
||||
}
|
||||
(*fn)("task: %s\n", record.Message)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h noticeHandler) WithAttrs([]slog.Attr) slog.Handler { return h }
|
||||
|
||||
func (h noticeHandler) WithGroup(string) slog.Handler { return h }
|
||||
4
setup.go
4
setup.go
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/internal/version"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
@@ -192,6 +193,9 @@ func (e *Executor) setupLogger() {
|
||||
AssumeYes: e.AssumeYes,
|
||||
AssumeTerm: e.AssumeTerm,
|
||||
}
|
||||
templater.SetNoticeSink(func(format string, args ...any) {
|
||||
e.Logger.VerboseErrf(logger.Yellow, format, args...)
|
||||
})
|
||||
}
|
||||
|
||||
func (e *Executor) setupOutput() error {
|
||||
|
||||
Reference in New Issue
Block a user