mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
923419d7fd
commit
f2e7b49acf
12 changed files with 167 additions and 9 deletions
|
@ -306,6 +306,7 @@ func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
|
cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
|
||||||
cmd.Flags().BoolP("printI18nWarnings", "", false, "print missing translations")
|
cmd.Flags().BoolP("printI18nWarnings", "", false, "print missing translations")
|
||||||
cmd.Flags().BoolP("printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
|
cmd.Flags().BoolP("printPathWarnings", "", false, "print warnings on duplicate target paths etc.")
|
||||||
|
cmd.Flags().BoolP("printUnusedTemplates", "", false, "print warnings on unused templates.")
|
||||||
cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
|
cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`")
|
||||||
cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`")
|
cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`")
|
||||||
cmd.Flags().BoolVarP(&cc.printm, "printMemoryUsage", "", false, "print memory usage to screen at intervals")
|
cmd.Flags().BoolVarP(&cc.printm, "printMemoryUsage", "", false, "print memory usage to screen at intervals")
|
||||||
|
|
|
@ -197,6 +197,7 @@ func TestFlags(t *testing.T) {
|
||||||
"--renderToDisk",
|
"--renderToDisk",
|
||||||
"--source=mysource",
|
"--source=mysource",
|
||||||
"--printPathWarnings",
|
"--printPathWarnings",
|
||||||
|
"--printUnusedTemplates",
|
||||||
},
|
},
|
||||||
check: func(c *qt.C, sc *serverCmd) {
|
check: func(c *qt.C, sc *serverCmd) {
|
||||||
c.Assert(sc, qt.Not(qt.IsNil))
|
c.Assert(sc, qt.Not(qt.IsNil))
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs/files"
|
"github.com/gohugoio/hugo/hugofs/files"
|
||||||
|
"github.com/gohugoio/hugo/tpl"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
|
||||||
|
@ -217,6 +218,7 @@ func initializeFlags(cmd *cobra.Command, cfg config.Provider) {
|
||||||
"force",
|
"force",
|
||||||
"gc",
|
"gc",
|
||||||
"printI18nWarnings",
|
"printI18nWarnings",
|
||||||
|
"printUnusedTemplates",
|
||||||
"invalidateCDN",
|
"invalidateCDN",
|
||||||
"layoutDir",
|
"layoutDir",
|
||||||
"logFile",
|
"logFile",
|
||||||
|
@ -501,7 +503,6 @@ func (c *commandeer) build() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bep) Feedback?
|
|
||||||
if !c.h.quiet {
|
if !c.h.quiet {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
c.hugo().PrintProcessingStats(os.Stdout)
|
c.hugo().PrintProcessingStats(os.Stdout)
|
||||||
|
@ -513,6 +514,11 @@ func (c *commandeer) build() error {
|
||||||
c.logger.Warnln("Duplicate target paths:", dupes)
|
c.logger.Warnln("Duplicate target paths:", dupes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unusedTemplates := c.hugo().Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
|
||||||
|
for _, unusedTemplate := range unusedTemplates {
|
||||||
|
c.logger.Warnf("Template %s is unused, source file %s", unusedTemplate.Name(), unusedTemplate.Filename())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.h.buildWatch {
|
if c.h.buildWatch {
|
||||||
|
|
|
@ -53,6 +53,7 @@ hugo [flags]
|
||||||
--printI18nWarnings print missing translations
|
--printI18nWarnings print missing translations
|
||||||
--printMemoryUsage print memory usage to screen at intervals
|
--printMemoryUsage print memory usage to screen at intervals
|
||||||
--printPathWarnings print warnings on duplicate target paths etc.
|
--printPathWarnings print warnings on duplicate target paths etc.
|
||||||
|
--printUnusedTemplates print warnings on unused templates.
|
||||||
--quiet build in quiet mode
|
--quiet build in quiet mode
|
||||||
--renderToMemory render to memory (only useful for benchmark testing)
|
--renderToMemory render to memory (only useful for benchmark testing)
|
||||||
-s, --source string filesystem path to read files relative from
|
-s, --source string filesystem path to read files relative from
|
||||||
|
|
|
@ -49,6 +49,7 @@ See https://gohugo.io/hugo-modules/ for more information.
|
||||||
--printI18nWarnings print missing translations
|
--printI18nWarnings print missing translations
|
||||||
--printMemoryUsage print memory usage to screen at intervals
|
--printMemoryUsage print memory usage to screen at intervals
|
||||||
--printPathWarnings print warnings on duplicate target paths etc.
|
--printPathWarnings print warnings on duplicate target paths etc.
|
||||||
|
--printUnusedTemplates print warnings on unused templates.
|
||||||
--templateMetrics display metrics about template executions
|
--templateMetrics display metrics about template executions
|
||||||
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
||||||
-t, --theme strings themes to use (located in /themes/THEMENAME/)
|
-t, --theme strings themes to use (located in /themes/THEMENAME/)
|
||||||
|
|
|
@ -50,6 +50,7 @@ hugo new [path] [flags]
|
||||||
--printI18nWarnings print missing translations
|
--printI18nWarnings print missing translations
|
||||||
--printMemoryUsage print memory usage to screen at intervals
|
--printMemoryUsage print memory usage to screen at intervals
|
||||||
--printPathWarnings print warnings on duplicate target paths etc.
|
--printPathWarnings print warnings on duplicate target paths etc.
|
||||||
|
--printUnusedTemplates print warnings on unused templates.
|
||||||
--templateMetrics display metrics about template executions
|
--templateMetrics display metrics about template executions
|
||||||
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
||||||
-t, --theme strings themes to use (located in /themes/THEMENAME/)
|
-t, --theme strings themes to use (located in /themes/THEMENAME/)
|
||||||
|
|
|
@ -63,6 +63,7 @@ hugo server [flags]
|
||||||
--printI18nWarnings print missing translations
|
--printI18nWarnings print missing translations
|
||||||
--printMemoryUsage print memory usage to screen at intervals
|
--printMemoryUsage print memory usage to screen at intervals
|
||||||
--printPathWarnings print warnings on duplicate target paths etc.
|
--printPathWarnings print warnings on duplicate target paths etc.
|
||||||
|
--printUnusedTemplates print warnings on unused templates.
|
||||||
--renderToDisk render to Destination path (default is render to memory & serve from there)
|
--renderToDisk render to Destination path (default is render to memory & serve from there)
|
||||||
--templateMetrics display metrics about template executions
|
--templateMetrics display metrics about template executions
|
||||||
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
--templateMetricsHints calculate some improvement hints when combined with --templateMetrics
|
||||||
|
|
|
@ -44,6 +44,11 @@ type TemplateFinder interface {
|
||||||
TemplateLookupVariant
|
TemplateLookupVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnusedTemplatesProvider lists unused templates if the build is configured to track those.
|
||||||
|
type UnusedTemplatesProvider interface {
|
||||||
|
UnusedTemplates() []FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
// TemplateHandler finds and executes templates.
|
// TemplateHandler finds and executes templates.
|
||||||
type TemplateHandler interface {
|
type TemplateHandler interface {
|
||||||
TemplateFinder
|
TemplateFinder
|
||||||
|
|
|
@ -27,6 +27,11 @@ type Info interface {
|
||||||
identity.Provider
|
identity.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileInfo interface {
|
||||||
|
Name() string
|
||||||
|
Filename() string
|
||||||
|
}
|
||||||
|
|
||||||
type InfoManager interface {
|
type InfoManager interface {
|
||||||
ParseInfo() ParseInfo
|
ParseInfo() ParseInfo
|
||||||
|
|
||||||
|
@ -65,10 +70,6 @@ func (info ParseInfo) IsZero() bool {
|
||||||
return info.Config.Version == 0
|
return info.Config.Version == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info holds some info extracted from a parsed template.
|
|
||||||
type Info1 struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParseConfig struct {
|
type ParseConfig struct {
|
||||||
Version int
|
Version int
|
||||||
}
|
}
|
||||||
|
|
61
tpl/tplimpl/integration_test.go
Normal file
61
tpl/tplimpl/integration_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package tplimpl_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/hugolib"
|
||||||
|
"github.com/gohugoio/hugo/tpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPrintUnusedTemplates(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- config.toml --
|
||||||
|
baseURL = 'http://example.com/'
|
||||||
|
printUnusedTemplates=true
|
||||||
|
-- content/p1.md --
|
||||||
|
---
|
||||||
|
title: "P1"
|
||||||
|
---
|
||||||
|
{{< usedshortcode >}}
|
||||||
|
-- layouts/baseof.html --
|
||||||
|
{{ block "main" . }}{{ end }}
|
||||||
|
-- layouts/baseof.json --
|
||||||
|
{{ block "main" . }}{{ end }}
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ define "main" }}FOO{{ end }}
|
||||||
|
-- layouts/_default/single.json --
|
||||||
|
-- layouts/_default/single.html --
|
||||||
|
{{ define "main" }}MAIN{{ end }}
|
||||||
|
-- layouts/post/single.html --
|
||||||
|
{{ define "main" }}MAIN{{ end }}
|
||||||
|
-- layouts/partials/usedpartial.html --
|
||||||
|
-- layouts/partials/unusedpartial.html --
|
||||||
|
-- layouts/shortcodes/usedshortcode.html --
|
||||||
|
{{ partial "usedpartial.html" }}
|
||||||
|
-- layouts/shortcodes/unusedshortcode.html --
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
b := hugolib.NewIntegrationTestBuilder(
|
||||||
|
hugolib.IntegrationTestConfig{
|
||||||
|
T: t,
|
||||||
|
TxtarString: files,
|
||||||
|
NeedsOsFS: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
b.Build()
|
||||||
|
|
||||||
|
unused := b.H.Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
|
||||||
|
|
||||||
|
var names []string
|
||||||
|
for _, tmpl := range unused {
|
||||||
|
names = append(names, tmpl.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Assert(names, qt.DeepEquals, []string{"_default/single.json", "baseof.json", "partials/unusedpartial.html", "post/single.html", "shortcodes/unusedshortcode.html"})
|
||||||
|
b.Assert(unused[0].Filename(), qt.Equals, filepath.Join(b.Cfg.WorkingDir, "layouts/_default/single.json"))
|
||||||
|
}
|
|
@ -71,6 +71,7 @@ var (
|
||||||
_ tpl.TemplateHandler = (*templateExec)(nil)
|
_ tpl.TemplateHandler = (*templateExec)(nil)
|
||||||
_ tpl.TemplateFuncGetter = (*templateExec)(nil)
|
_ tpl.TemplateFuncGetter = (*templateExec)(nil)
|
||||||
_ tpl.TemplateFinder = (*templateExec)(nil)
|
_ tpl.TemplateFinder = (*templateExec)(nil)
|
||||||
|
_ tpl.UnusedTemplatesProvider = (*templateExec)(nil)
|
||||||
|
|
||||||
_ tpl.Template = (*templateState)(nil)
|
_ tpl.Template = (*templateState)(nil)
|
||||||
_ tpl.Info = (*templateState)(nil)
|
_ tpl.Info = (*templateState)(nil)
|
||||||
|
@ -130,6 +131,11 @@ func newTemplateExec(d *deps.Deps) (*templateExec, error) {
|
||||||
funcMap[k] = v.Interface()
|
funcMap[k] = v.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var templateUsageTracker map[string]templateInfo
|
||||||
|
if d.Cfg.GetBool("printUnusedTemplates") {
|
||||||
|
templateUsageTracker = make(map[string]templateInfo)
|
||||||
|
}
|
||||||
|
|
||||||
h := &templateHandler{
|
h := &templateHandler{
|
||||||
nameBaseTemplateName: make(map[string]string),
|
nameBaseTemplateName: make(map[string]string),
|
||||||
transformNotFound: make(map[string]*templateState),
|
transformNotFound: make(map[string]*templateState),
|
||||||
|
@ -146,6 +152,8 @@ func newTemplateExec(d *deps.Deps) (*templateExec, error) {
|
||||||
layoutHandler: output.NewLayoutHandler(),
|
layoutHandler: output.NewLayoutHandler(),
|
||||||
layoutsFs: d.BaseFs.Layouts.Fs,
|
layoutsFs: d.BaseFs.Layouts.Fs,
|
||||||
layoutTemplateCache: make(map[layoutCacheKey]tpl.Template),
|
layoutTemplateCache: make(map[layoutCacheKey]tpl.Template),
|
||||||
|
|
||||||
|
templateUsageTracker: templateUsageTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.loadEmbedded(); err != nil {
|
if err := h.loadEmbedded(); err != nil {
|
||||||
|
@ -225,13 +233,72 @@ func (t *templateExec) Execute(templ tpl.Template, wr io.Writer, data interface{
|
||||||
defer t.Metrics.MeasureSince(templ.Name(), time.Now())
|
defer t.Metrics.MeasureSince(templ.Name(), time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.templateUsageTracker != nil {
|
||||||
|
if ts, ok := templ.(*templateState); ok {
|
||||||
|
t.templateUsageTrackerMu.Lock()
|
||||||
|
if _, found := t.templateUsageTracker[ts.Name()]; !found {
|
||||||
|
t.templateUsageTracker[ts.Name()] = ts.info
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ts.baseInfo.IsZero() {
|
||||||
|
if _, found := t.templateUsageTracker[ts.baseInfo.name]; !found {
|
||||||
|
t.templateUsageTracker[ts.baseInfo.name] = ts.baseInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.templateUsageTrackerMu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
execErr := t.executor.Execute(templ, wr, data)
|
execErr := t.executor.Execute(templ, wr, data)
|
||||||
if execErr != nil {
|
if execErr != nil {
|
||||||
execErr = t.addFileContext(templ, execErr)
|
execErr = t.addFileContext(templ, execErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return execErr
|
return execErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO1
|
||||||
|
func (t *templateExec) UnusedTemplates() []tpl.FileInfo {
|
||||||
|
if t.templateUsageTracker == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var unused []tpl.FileInfo
|
||||||
|
|
||||||
|
for _, ti := range t.needsBaseof {
|
||||||
|
if _, found := t.templateUsageTracker[ti.name]; !found {
|
||||||
|
unused = append(unused, ti)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ti := range t.baseof {
|
||||||
|
if _, found := t.templateUsageTracker[ti.name]; !found {
|
||||||
|
unused = append(unused, ti)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ts := range t.main.templates {
|
||||||
|
ti := ts.info
|
||||||
|
if strings.HasPrefix(ti.name, "_internal/") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(ti.name, "partials/inline/pagination") {
|
||||||
|
// TODO(bep) we need to fix this. These are internal partials, but
|
||||||
|
// they may also be defined in the project, which currently could
|
||||||
|
// lead to some false negatives.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, found := t.templateUsageTracker[ti.name]; !found {
|
||||||
|
unused = append(unused, ti)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(unused, func(i, j int) bool {
|
||||||
|
return unused[i].Name() < unused[j].Name()
|
||||||
|
})
|
||||||
|
|
||||||
|
return unused
|
||||||
|
}
|
||||||
|
|
||||||
func (t *templateExec) GetFunc(name string) (reflect.Value, bool) {
|
func (t *templateExec) GetFunc(name string) (reflect.Value, bool) {
|
||||||
v, found := t.funcs[name]
|
v, found := t.funcs[name]
|
||||||
return v, found
|
return v, found
|
||||||
|
@ -285,6 +352,10 @@ type templateHandler struct {
|
||||||
// Note that for shortcodes that same information is embedded in the
|
// Note that for shortcodes that same information is embedded in the
|
||||||
// shortcodeTemplates type.
|
// shortcodeTemplates type.
|
||||||
templateInfo map[string]tpl.Info
|
templateInfo map[string]tpl.Info
|
||||||
|
|
||||||
|
// May be nil.
|
||||||
|
templateUsageTracker map[string]templateInfo
|
||||||
|
templateUsageTrackerMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTemplate parses and adds a template to the collection.
|
// AddTemplate parses and adds a template to the collection.
|
||||||
|
|
|
@ -34,6 +34,14 @@ type templateInfo struct {
|
||||||
realFilename string
|
realFilename string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t templateInfo) Name() string {
|
||||||
|
return t.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t templateInfo) Filename() string {
|
||||||
|
return t.realFilename
|
||||||
|
}
|
||||||
|
|
||||||
func (t templateInfo) IsZero() bool {
|
func (t templateInfo) IsZero() bool {
|
||||||
return t.name == ""
|
return t.name == ""
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue