hugo 的模块管理

依赖 go mod

docsy-example为例子,在该repo下有go.mod文件:

go 1.12

require (
	github.com/FortAwesome/Font-Awesome v0.0.0-20230327165841-0698449d50f2 // indirect
	github.com/google/docsy v0.7.1 // indirect
	github.com/twbs/bootstrap v5.2.3+incompatible // indirect
)

在该目录下执行hugo命令,报下面错误:

Error: failed to load modules: failed to download modules: binary with name "go" not found

对应代码: hugo/modules/client.go

func (c *Client) listGoMods() (goModules, error) {
	if c.GoModulesFilename == "" || !c.moduleConfig.hasModuleImport() {
		return nil, nil
	}

	downloadModules := func(modules ...string) error {
		args := []string{"mod", "download"}
		args = append(args, modules...)
		out := io.Discard
		err := c.runGo(context.Background(), out, args...)
		if err != nil {
			return fmt.Errorf("failed to download modules: %w", err)
		}
		return nil
	}

}

默认下载依赖模块的路径为:/tmp/hugo_cache

tree -L 8
.
├── docsy-example
│   └── filecache
│       ├── getcsv
│       ├── getjson
│       └── getresource
└── modules
    └── filecache
        └── modules
            └── pkg
                └── mod
                    ├── cache
                    │   ├── download
                    │   │   └── github.com
                    │   └── vcs
                    │       ├── 452026f8ece4b6e04adce745be52bb14c2f2b65baffde3e5ebfe0112a044536d
                    │       ├── 452026f8ece4b6e04adce745be52bb14c2f2b65baffde3e5ebfe0112a044536d.info
                    │       ├── 452026f8ece4b6e04adce745be52bb14c2f2b65baffde3e5ebfe0112a044536d.lock
                    │       ├── 98f59a39bbbc2d4de9185a32a3d8790111161ae9778e3e5e32a90c95f026ac9b
                    │       ├── 98f59a39bbbc2d4de9185a32a3d8790111161ae9778e3e5e32a90c95f026ac9b.info
                    │       ├── 98f59a39bbbc2d4de9185a32a3d8790111161ae9778e3e5e32a90c95f026ac9b.lock
                    │       ├── a81254f0cf90f611158215d1cb50586eccc323b54ab825bb7e9c8b2580ac9fb3
                    │       ├── a81254f0cf90f611158215d1cb50586eccc323b54ab825bb7e9c8b2580ac9fb3.info
                    │       └── a81254f0cf90f611158215d1cb50586eccc323b54ab825bb7e9c8b2580ac9fb3.lock
                    └── github.com
                        ├── !fort!awesome
                        │   └── !font-!awesome@v0.0.0-20230327165841-0698449d50f2
                        ├── google
                        │   ├── docsy
                        │   └── docsy@v0.7.1
                        └── twbs
                            └── bootstrap@v5.2.3+incompatible

25 directories, 6 files

使用代码调用

docsy-example为例子,通过代码调用HugoAPI来生成html文件。

package main

import (
	"fmt"
	"log"

	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/config/allconfig"
	"github.com/gohugoio/hugo/deps"
	"github.com/gohugoio/hugo/hugofs"
	"github.com/gohugoio/hugo/hugolib"
	"github.com/spf13/afero"
)

const (
  workingDir = "/root/wl/docsy-example"
  // themesDir  = "/root/wl/docsy-example/themes"
)

func newCfg(withConfig ...func(cfg config.Provider) error) (*allconfig.Configs, *hugofs.Fs) {
  cfgP := config.New()
  cfgP.Set("defaultContentLanguageInSubdir", false)
  cfgP.Set("workingDir", workingDir)
  cfgP.Set("baseURL", "")
  cfgP.Set("Environment","development")

  fs := afero.NewOsFs()
  cfg, err := allconfig.LoadConfig(allconfig.ConfigSourceDescriptor{Fs: fs, Flags: cfgP})
  if err != nil {
    panic(err)
  }

  if err != nil && err != allconfig.ErrNoConfigFile {
    panic(err)
  }

  baseConf := config.BaseConfig{
    WorkingDir: workingDir,
    PublishDir: "public",
  }
  hugoFs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(fs), baseConf)

  return cfg, hugoFs
}

func main() {
  cfg, fs := newCfg()
  fmt.Printf("%-15s %s\n", "workingDir:", cfg.Base.WorkingDir)
  fmt.Printf("%-15s %s\n", "ContentDir:", cfg.Base.ContentDir)
  fmt.Printf("%-15s %s\n", "BaseURL:", cfg.Base.BaseURL)
  fmt.Printf("%-15s %s\n", "themesDir:", cfg.Base.ThemesDir)
  fmt.Printf("%-15s %s\n", "theme:", cfg.Base.Theme)
  fmt.Printf("%-15s %v\n", "buildDrafts:", cfg.Base.BuildDrafts)
  PublishDir, _ := fs.PublishDir.(*afero.BasePathFs).RealPath(".")
  fmt.Printf("%-15s %s\n", "PublishDir:", PublishDir)

  depsCfg := deps.DepsCfg{Fs: fs, Configs: cfg}
  buildCfg := hugolib.BuildCfg{NoBuildLock: true}

  sites, err := hugolib.NewWLHugoSites(depsCfg)
  if err != nil {
    log.Fatalf("failed to create sites: %s", err.Error())
  }
  fmt.Println(len(sites.Sites))

  buildCfg.NoBuildLock = true
  err = sites.Build(buildCfg)
  if err != nil {
    panic(err)
  }
  var s *hugolib.Site
  s = sites.Sites[0]
  fmt.Println(s.RegularPages())
}

注意:

  • 不要指定theme : cfgP.Set("theme","docsy") hugo会根据依赖找使用的主题。 如果指定了theme会报下面错误:
    panic: failed to load modules: module "docsy" not found in 
    "/root/wl/docsy-example/themes/docsy"; either add it as a Hugo Module or store 
    it in "/root/wl/docsy-example/themes".: module does not exist
    
  • themesDir的配置也就可有可无。

hugo 模块配置说明

docsy-example为例,在文件go.mod中定义依赖的模块:

go 1.12

require (
	github.com/FortAwesome/Font-Awesome v0.0.0-20230327165841-0698449d50f2 // indirect
	github.com/google/docsy v0.7.1 // indirect
	github.com/twbs/bootstrap v5.2.3+incompatible // indirect
)

hugo.toml配置依赖模块

hugo mod命令是根据hugo.toml的配置文件中配的依赖模块来生成go.mod的。

[module]
  # uncomment line below for temporary local development of module
  # replacements = "github.com/google/docsy -> ../../docsy"
  [module.hugoVersion]
    extended = true
    min = "0.110.0"
  [[module.imports]]
    path = "github.com/google/docsy"
    disable = false
  [[module.imports]]
    path = "github.com/google/docsy/dependencies"
    disable = false

如何使用hugo mod命令建立模块依赖

命令说明:

./hugo help mod

输出:
Usage:
  hugo mod [command]

Available Commands:
  clean       Delete the Hugo Module cache for the current project.
  get         Resolves dependencies in your current Hugo Project.
  graph       Print a module dependency graph.
  init        Initialize this project as a Hugo Module.
  npm         Various npm helpers.
  tidy        Remove unused entries in go.mod and go.sum.
  vendor      Vendor all module dependencies into the _vendor directory.
  verify      Verify dependencies.

Flags:
  -h, --help   help for mod

Global Flags:
      --clock string               set the clock used by Hugo, e.g. --clock 2021-11-06T22:30:00.00+09:00
      --config string              config file (default is hugo.yaml|json|toml)
      --configDir string           config dir (default "config")
      --debug                      debug output
  -d, --destination string         filesystem path to write files to
  -e, --environment string         build environment
      --ignoreVendorPaths string   ignores any _vendor for module paths matching the given Glob pattern
      --logLevel string            log level (debug|info|warn|error)
      --quiet                      build in quiet mode
  -s, --source string              filesystem path to read files relative from
      --themesDir string           filesystem path to themes directory
  -v, --verbose                    verbose output

Use "hugo mod [command] --help" for more information about a command.

初始化

使用hugo mod init初始化:

mkdir t
cd t
./hugo mod init test

生成go.mod 文件:

module test

go 1.19

添加依赖

在配置文件hugo.toml中配置依赖的模块:

[module]
  # uncomment line below for temporary local development of module
  # replacements = "github.com/google/docsy -> ../../docsy"
  [module.hugoVersion]
    extended = true
    min = "0.110.0"
  [[module.imports]]
    path = "github.com/google/docsy"
    disable = false

然后执行./hugo mod tidy生成并下载依赖,输出:

go: no module dependencies to download
hugo: downloading modules ??
go: downloading github.com/google/docsy v0.7.1
go: added github.com/google/docsy v0.7.1
hugo: collected modules in 36745 ms

更改后的go.mod:

module test

go 1.19

require github.com/google/docsy v0.7.1 // indirect

并生成go.sum文件:

github.com/google/docsy v0.7.1 h1:DUriA7Nr3lJjNi9Ulev1SfiG1sUYmvyDeU4nTp7uDxY=
github.com/google/docsy v0.7.1/go.mod h1:JCmE+c+izhE0Rvzv3y+AzHhz1KdwlA9Oj5YBMklJcfc=

更新依赖

在hugo.toml中再添加依赖:

  [[module.imports]]
    path = "github.com/google/docsy/dependencies"
    disable = false

通过命令/hugo mod get更新,生成go.mod文件:

module test

go 1.19

require (
	github.com/google/docsy v0.7.1 // indirect
	github.com/google/docsy/dependencies v0.7.1 // indirect
)

go.sum文件:

github.com/FortAwesome/Font-Awesome v0.0.0-20230327165841-0698449d50f2/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo=
github.com/google/docsy v0.7.1 h1:DUriA7Nr3lJjNi9Ulev1SfiG1sUYmvyDeU4nTp7uDxY=
github.com/google/docsy v0.7.1/go.mod h1:JCmE+c+izhE0Rvzv3y+AzHhz1KdwlA9Oj5YBMklJcfc=
github.com/google/docsy/dependencies v0.7.1 h1:NbzYKJYMin2q50xdWSUzR2c9gCp7zR/XHDBcxklEcTQ=
github.com/google/docsy/dependencies v0.7.1/go.mod h1:gihhs5gmgeO+wuoay4FwOzob+jYJVyQbNaQOh788lD4=
github.com/twbs/bootstrap v5.2.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0=