hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

mod.go (8124B)

    1 // Copyright 2020 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package commands
   15 
   16 import (
   17 	"errors"
   18 	"fmt"
   19 	"os"
   20 	"path/filepath"
   21 	"regexp"
   22 
   23 	"github.com/gohugoio/hugo/hugolib"
   24 
   25 	"github.com/gohugoio/hugo/modules"
   26 	"github.com/spf13/cobra"
   27 )
   28 
   29 var _ cmder = (*modCmd)(nil)
   30 
   31 type modCmd struct {
   32 	*baseBuilderCmd
   33 }
   34 
   35 func (c *modCmd) newVerifyCmd() *cobra.Command {
   36 	var clean bool
   37 
   38 	verifyCmd := &cobra.Command{
   39 		Use:   "verify",
   40 		Short: "Verify dependencies.",
   41 		Long: `Verify checks that the dependencies of the current module, which are stored in a local downloaded source cache, have not been modified since being downloaded.
   42 `,
   43 		RunE: func(cmd *cobra.Command, args []string) error {
   44 			return c.withModsClient(true, func(c *modules.Client) error {
   45 				return c.Verify(clean)
   46 			})
   47 		},
   48 	}
   49 
   50 	verifyCmd.Flags().BoolVarP(&clean, "clean", "", false, "delete module cache for dependencies that fail verification")
   51 
   52 	return verifyCmd
   53 }
   54 
   55 var moduleNotFoundRe = regexp.MustCompile("module.*not found")
   56 
   57 func (c *modCmd) newCleanCmd() *cobra.Command {
   58 	var pattern string
   59 	var all bool
   60 	cmd := &cobra.Command{
   61 		Use:   "clean",
   62 		Short: "Delete the Hugo Module cache for the current project.",
   63 		Long: `Delete the Hugo Module cache for the current project.
   64 
   65 Note that after you run this command, all of your dependencies will be re-downloaded next time you run "hugo".
   66 
   67 Also note that if you configure a positive maxAge for the "modules" file cache, it will also be cleaned as part of "hugo --gc".
   68  
   69 `,
   70 		RunE: func(cmd *cobra.Command, args []string) error {
   71 			if all {
   72 				com, err := c.initConfig(false)
   73 
   74 				if err != nil && com == nil {
   75 					return err
   76 				}
   77 
   78 				count, err := com.hugo().FileCaches.ModulesCache().Prune(true)
   79 				com.logger.Printf("Deleted %d files from module cache.", count)
   80 				return err
   81 			}
   82 			return c.withModsClient(true, func(c *modules.Client) error {
   83 				return c.Clean(pattern)
   84 			})
   85 		},
   86 	}
   87 
   88 	cmd.Flags().StringVarP(&pattern, "pattern", "", "", `pattern matching module paths to clean (all if not set), e.g. "**hugo*"`)
   89 	cmd.Flags().BoolVarP(&all, "all", "", false, "clean entire module cache")
   90 
   91 	return cmd
   92 }
   93 
   94 func (b *commandsBuilder) newModCmd() *modCmd {
   95 	c := &modCmd{}
   96 
   97 	const commonUsage = `
   98 Note that Hugo will always start out by resolving the components defined in the site
   99 configuration, provided by a _vendor directory (if no --ignoreVendorPaths flag provided),
  100 Go Modules, or a folder inside the themes directory, in that order.
  101 
  102 See https://gohugo.io/hugo-modules/ for more information.
  103 
  104 `
  105 
  106 	cmd := &cobra.Command{
  107 		Use:   "mod",
  108 		Short: "Various Hugo Modules helpers.",
  109 		Long: `Various helpers to help manage the modules in your project's dependency graph.
  110 
  111 Most operations here requires a Go version installed on your system (>= Go 1.12) and the relevant VCS client (typically Git).
  112 This is not needed if you only operate on modules inside /themes or if you have vendored them via "hugo mod vendor".
  113 
  114 ` + commonUsage,
  115 
  116 		RunE: nil,
  117 	}
  118 
  119 	cmd.AddCommand(newModNPMCmd(c))
  120 
  121 	cmd.AddCommand(
  122 		&cobra.Command{
  123 			Use:                "get",
  124 			DisableFlagParsing: true,
  125 			Short:              "Resolves dependencies in your current Hugo Project.",
  126 			Long: `
  127 Resolves dependencies in your current Hugo Project.
  128 
  129 Some examples:
  130 
  131 Install the latest version possible for a given module:
  132 
  133     hugo mod get github.com/gohugoio/testshortcodes
  134     
  135 Install a specific version:
  136 
  137     hugo mod get github.com/gohugoio/testshortcodes@v0.3.0
  138 
  139 Install the latest versions of all module dependencies:
  140 
  141     hugo mod get -u
  142     hugo mod get -u ./... (recursive)
  143 
  144 Run "go help get" for more information. All flags available for "go get" is also relevant here.
  145 ` + commonUsage,
  146 			RunE: func(cmd *cobra.Command, args []string) error {
  147 				// We currently just pass on the flags we get to Go and
  148 				// need to do the flag handling manually.
  149 				if len(args) == 1 && args[0] == "-h" {
  150 					return cmd.Help()
  151 				}
  152 
  153 				var lastArg string
  154 				if len(args) != 0 {
  155 					lastArg = args[len(args)-1]
  156 				}
  157 
  158 				if lastArg == "./..." {
  159 					args = args[:len(args)-1]
  160 					// Do a recursive update.
  161 					dirname, err := os.Getwd()
  162 					if err != nil {
  163 						return err
  164 					}
  165 
  166 					// Sanity check. We do recursive walking and want to avoid
  167 					// accidents.
  168 					if len(dirname) < 5 {
  169 						return errors.New("must not be run from the file system root")
  170 					}
  171 
  172 					filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
  173 						if info.IsDir() {
  174 							return nil
  175 						}
  176 
  177 						if info.Name() == "go.mod" {
  178 							// Found a module.
  179 							dir := filepath.Dir(path)
  180 							fmt.Println("Update module in", dir)
  181 							c.source = dir
  182 							err := c.withModsClient(false, func(c *modules.Client) error {
  183 								if len(args) == 1 && args[0] == "-h" {
  184 									return cmd.Help()
  185 								}
  186 								return c.Get(args...)
  187 							})
  188 							if err != nil {
  189 								return err
  190 							}
  191 
  192 						}
  193 
  194 						return nil
  195 					})
  196 
  197 					return nil
  198 				}
  199 
  200 				return c.withModsClient(false, func(c *modules.Client) error {
  201 					return c.Get(args...)
  202 				})
  203 			},
  204 		},
  205 		&cobra.Command{
  206 			Use:   "graph",
  207 			Short: "Print a module dependency graph.",
  208 			Long: `Print a module dependency graph with information about module status (disabled, vendored).
  209 Note that for vendored modules, that is the version listed and not the one from go.mod.
  210 `,
  211 			RunE: func(cmd *cobra.Command, args []string) error {
  212 				return c.withModsClient(true, func(c *modules.Client) error {
  213 					return c.Graph(os.Stdout)
  214 				})
  215 			},
  216 		},
  217 		&cobra.Command{
  218 			Use:   "init",
  219 			Short: "Initialize this project as a Hugo Module.",
  220 			Long: `Initialize this project as a Hugo Module.
  221 It will try to guess the module path, but you may help by passing it as an argument, e.g:
  222 
  223     hugo mod init github.com/gohugoio/testshortcodes
  224 
  225 Note that Hugo Modules supports multi-module projects, so you can initialize a Hugo Module
  226 inside a subfolder on GitHub, as one example.
  227 `,
  228 			RunE: func(cmd *cobra.Command, args []string) error {
  229 				var path string
  230 				if len(args) >= 1 {
  231 					path = args[0]
  232 				}
  233 				return c.withModsClient(false, func(c *modules.Client) error {
  234 					return c.Init(path)
  235 				})
  236 			},
  237 		},
  238 		&cobra.Command{
  239 			Use:   "vendor",
  240 			Short: "Vendor all module dependencies into the _vendor directory.",
  241 			Long: `Vendor all module dependencies into the _vendor directory.
  242 
  243 If a module is vendored, that is where Hugo will look for it's dependencies.
  244 `,
  245 			RunE: func(cmd *cobra.Command, args []string) error {
  246 				return c.withModsClient(true, func(c *modules.Client) error {
  247 					return c.Vendor()
  248 				})
  249 			},
  250 		},
  251 		c.newVerifyCmd(),
  252 		&cobra.Command{
  253 			Use:   "tidy",
  254 			Short: "Remove unused entries in go.mod and go.sum.",
  255 			RunE: func(cmd *cobra.Command, args []string) error {
  256 				return c.withModsClient(true, func(c *modules.Client) error {
  257 					return c.Tidy()
  258 				})
  259 			},
  260 		},
  261 		c.newCleanCmd(),
  262 	)
  263 
  264 	c.baseBuilderCmd = b.newBuilderCmd(cmd)
  265 
  266 	return c
  267 }
  268 
  269 func (c *modCmd) withModsClient(failOnMissingConfig bool, f func(*modules.Client) error) error {
  270 	com, err := c.initConfig(failOnMissingConfig)
  271 	if err != nil {
  272 		return err
  273 	}
  274 
  275 	return f(com.hugo().ModulesClient)
  276 }
  277 
  278 func (c *modCmd) withHugo(f func(*hugolib.HugoSites) error) error {
  279 	com, err := c.initConfig(true)
  280 	if err != nil {
  281 		return err
  282 	}
  283 
  284 	return f(com.hugo())
  285 }
  286 
  287 func (c *modCmd) initConfig(failOnNoConfig bool) (*commandeer, error) {
  288 	com, err := initializeConfig(failOnNoConfig, false, false, &c.hugoBuilderCommon, c, nil)
  289 	if err != nil {
  290 		return nil, err
  291 	}
  292 	return com, nil
  293 }