Repository: gohugoio/hugo (language: go)

Issue:
Running hugo without config file should throw error
Change into an empty directory...

#### v0.111.3

```text
$ hugo

Error: Unable to locate config file or config directory. Perhaps you need to create a new site.
       Run `hugo help new` for details.
```

It also creates a `.hugo_build.lock` file.


#### v0.112.3

```text
$ hugo

hugo v0.112.3-ba6f74e40420d76f15fc8c2358be90f7aca98e0e+extended linux/amd64 BuildDate=2023-05-24T14:42:50Z VendorInfo=gohugoio
WARN 2023/05/24 17:37:09 found no layout file for "html" for kind "home": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN 2023/05/24 17:37:09 found no layout file for "html" for kind "taxonomy": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN 2023/05/24 17:37:09 found no layout file for "html" for kind "taxonomy": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
```

It also generates the following:

```text
./
├── public/
│   ├── categories/
│   │   └── index.xml
│   ├── tags/
│   │   └── index.xml
│   ├── index.xml
│   └── sitemap.xml
├── resources/
│   └── _gen/
│       ├── assets/
│       └── images/
└── .hugo_build.lock

```


Consider removing the deprecation of .Language.Params

https://discourse.gohugo.io/t/confused-about-multilang-parameters-site-params-in-new-0-112-3/44562
https://raw.githubusercontent.com/letsencrypt/website/main/layouts/partials/langs.html


Discussion / hints:
Thanks. I'm going to let these relatively minor things sit for a few days and just fix them all in one patch release.

This release was bound to create some waves/bugs with the massive amount of code changes. I probably got a little tired at the end there and just wanted to get it out the door. But after fixing these recent bugs in the `commands` package of Hugo I can say that it has become a pleasure to code in (esp. with the new `testscripts` setup). The previous version I think I was the only one who dared to make changes to ...

/cc @jmooring 
Second thought, I think not -- both the example is easy to rewrite.

Fix patch:
diff --git a/commands/commandeer.go b/commands/commandeer.go
index 08f959579b0..7b0c416522e 100644
--- a/commands/commandeer.go
+++ b/commands/commandeer.go
@@ -108,9 +108,6 @@ type rootCommand struct {
 	buildWatch  bool
 	environment string
 
-	// File format to read or write (TOML, YAML, JSON).
-	format string
-
 	// Common build flags.
 	baseURL              string
 	gc                   bool
@@ -408,12 +405,6 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
 	if err != nil {
 		return err
 	}
-	switch r.format {
-	case "json", "toml", "yaml":
-		// OK
-	default:
-		return fmt.Errorf("unsupported format %q; must be one of json, toml or yaml", r.format)
-	}
 
 	loggers.PanicOnWarning.Store(r.panicOnWarning)
 	r.commonConfigs = lazycache.New[int32, *commonConfig](lazycache.Options{MaxEntries: 5})
@@ -485,7 +476,6 @@ Complete documentation is available at https://gohugo.io/.`
 
 	// Configure persistent flags
 	cmd.PersistentFlags().StringVarP(&r.source, "source", "s", "", "filesystem path to read files relative from")
-	cmd.PersistentFlags().StringVar(&r.format, "format", "toml", "preferred file format (toml, yaml or json)")
 	cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
 	cmd.PersistentFlags().StringP("destination", "d", "", "filesystem path to write files to")
 	cmd.PersistentFlags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
diff --git a/commands/config.go b/commands/config.go
index ce3ad04fa74..5cbcdff2ae0 100644
--- a/commands/config.go
+++ b/commands/config.go
@@ -17,6 +17,7 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"fmt"
 	"os"
 	"strings"
 	"time"
@@ -40,6 +41,8 @@ func newConfigCommand() *configCommand {
 type configCommand struct {
 	r *rootCommand
 
+	format string
+
 	commands []simplecobra.Commander
 }
 
@@ -67,7 +70,7 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
 		return err
 	}
 
-	format := strings.ToLower(c.r.format)
+	format := strings.ToLower(c.format)
 
 	switch format {
 	case "json":
@@ -83,6 +86,8 @@ func (c *configCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, arg
 			return parser.InterfaceToConfig(m, metadecoders.YAML, os.Stdout)
 		case "toml":
 			return parser.InterfaceToConfig(m, metadecoders.TOML, os.Stdout)
+		default:
+			return fmt.Errorf("unsupported format: %q", format)
 		}
 	}
 
@@ -93,6 +98,8 @@ func (c *configCommand) Init(cd *simplecobra.Commandeer) error {
 	cmd := cd.CobraCommand
 	cmd.Short = "Print the site configuration"
 	cmd.Long = `Print the site configuration, both default and custom settings.`
+	cmd.Flags().StringVar(&c.format, "format", "toml", "preferred file format (toml, yaml or json)")
+
 	return nil
 }
 
diff --git a/commands/hugobuilder.go b/commands/hugobuilder.go
index fa194e00069..95dbb1ca898 100644
--- a/commands/hugobuilder.go
+++ b/commands/hugobuilder.go
@@ -1019,6 +1019,10 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
 		return err
 	}
 
+	if len(conf.configs.LoadingInfo.ConfigFiles) == 0 {
+		return errors.New("Unable to locate config file or config directory. Perhaps you need to create a new site.\nRun `hugo help new` for details.")
+	}
+
 	c.conf = conf
 	if c.onConfigLoaded != nil {
 		if err := c.onConfigLoaded(false); err != nil {
diff --git a/commands/new.go b/commands/new.go
index 8a2b0229348..fc9a0bd8c16 100644
--- a/commands/new.go
+++ b/commands/new.go
@@ -36,6 +36,7 @@ func newNewCommand() *newCommand {
 	var (
 		force       bool
 		contentType string
+		format      string
 	)
 
 	var c *newCommand
@@ -67,6 +68,8 @@ func newNewCommand() *newCommand {
 					cmd.Flags().StringVarP(&contentType, "kind", "k", "", "content type to create")
 					cmd.Flags().String("editor", "", "edit new content with this editor, if provided")
 					cmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite file if it already exists")
+					cmd.Flags().StringVar(&format, "format", "toml", "preferred file format (toml, yaml or json)")
+
 				},
 			},
 			&simpleCommand{
@@ -118,7 +121,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
 							return errors.New(createpath + " already exists and is not empty. See --force.")
 
 						case !isEmpty && force:
-							all := append(dirs, filepath.Join(createpath, "hugo."+r.format))
+							all := append(dirs, filepath.Join(createpath, "hugo."+format))
 							for _, path := range all {
 								if exists, _ := helpers.Exists(path, sourceFs); exists {
 									return errors.New(path + " already exists")
@@ -133,7 +136,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
 						}
 					}
 
-					c.newSiteCreateConfig(sourceFs, createpath, r.format)
+					c.newSiteCreateConfig(sourceFs, createpath, format)
 
 					// Create a default archetype file.
 					helpers.SafeWriteToDisk(filepath.Join(archeTypePath, "default.md"),
@@ -145,7 +148,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`,
 					return nil
 				},
 				withc: func(cmd *cobra.Command) {
-					cmd.Flags().BoolVar(&force, "force", false, "init inside non-empty directory")
+					cmd.Flags().BoolVarP(&force, "force", "f", false, "init inside non-empty directory")
 				},
 			},
 			&simpleCommand{
diff --git a/commands/server.go b/commands/server.go
index ad432037cc7..4669cf0b4ed 100644
--- a/commands/server.go
+++ b/commands/server.go
@@ -288,7 +288,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
 					}
 					var fs afero.Fs
 					f.c.withConf(func(conf *commonConfig) {
-						fs = conf.fs.PublishDir
+						fs = conf.fs.PublishDirServer
 					})
 
 					fi, err := fs.Stat(path)
diff --git a/hugolib/site_new.go b/hugolib/site_new.go
index e5398ba8d3d..4b3a28bddf1 100644
--- a/hugolib/site_new.go
+++ b/hugolib/site_new.go
@@ -361,10 +361,7 @@ func (s *Site) Config() page.SiteConfig {
 }
 
 func (s *Site) LanguageCode() string {
-	if s.conf.LanguageCode != "" {
-		return s.conf.LanguageCode
-	}
-	return s.language.Lang
+	return s.Language().LanguageCode()
 }
 
 // Returns all Sites for all languages.
diff --git a/langs/config.go b/langs/config.go
index 3c72783881f..15c0bedbc42 100644
--- a/langs/config.go
+++ b/langs/config.go
@@ -24,6 +24,9 @@ type LanguageConfig struct {
 	// The language name, e.g. "English".
 	LanguageName string
 
+	// The language code, e.g. "en-US".
+	LanguageCode string
+
 	// The language title. When set, this will
 	// override site.Title for this language.
 	Title string
diff --git a/langs/language.go b/langs/language.go
index 232331cae88..4e089606c7b 100644
--- a/langs/language.go
+++ b/langs/language.go
@@ -98,10 +98,19 @@ See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120
 // Note that this is the same as the Site.Params, but we keep it here for legacy reasons.
 // Deprecated: Use the site.Params instead.
 func (l *Language) Params() maps.Params {
-	DeprecationFunc(".Language.Params", paramsDeprecationWarning, false)
+	// TODO(bep) Remove this for now as it created a little too much noise. Need to think about this.
+	// See https://github.com/gohugoio/hugo/issues/11025
+	//DeprecationFunc(".Language.Params", paramsDeprecationWarning, false)
 	return l.params
 }
 
+func (l *Language) LanguageCode() string {
+	if l.LanguageConfig.LanguageCode != "" {
+		return l.LanguageConfig.LanguageCode
+	}
+	return l.Lang
+}
+
 func (l *Language) loadLocation(tzStr string) error {
 	location, err := time.LoadLocation(tzStr)
 	if err != nil {
diff --git a/resources/page/site.go b/resources/page/site.go
index da97dfe6e54..ccc36a4eebb 100644
--- a/resources/page/site.go
+++ b/resources/page/site.go
@@ -65,6 +65,7 @@ type Site interface {
 	Title() string
 
 	// Returns the configured language code for this Site.
+	// Deprecated: Use .Language.LanguageCode instead.
 	LanguageCode() string
 
 	// Returns the configured copyright information for this Site.


Test patch:
diff --git a/hugolib/config_test.go b/hugolib/config_test.go
index 2f9c6e3f678..f742eb862f1 100644
--- a/hugolib/config_test.go
+++ b/hugolib/config_test.go
@@ -824,6 +824,7 @@ baseURL = "https://example.com"
 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT"]
 [languages]
 [languages.en]
+languageCode = "en-US"
 title = "English Title"
 [languages.en.params]
 myparam = "enParamValue"
@@ -840,6 +841,7 @@ title: "My English Section"
 title: "My Swedish Section"
 ---
 -- layouts/index.html --
+LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Language.LanguageCode }}|
 {{ range $i, $e := (slice site .Site) }}
 {{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
 {{ end }}
@@ -863,10 +865,12 @@ Sections: true|
 Param: enParamValue	
 Param: enParamValue	
 IsMultiLingual: true
+LanguageCode: true|en-US|
 `)
 
 	b.AssertFileContent("public/sv/index.html", `
-Param: svParamValue	
+Param: svParamValue
+LanguageCode: true|sv|
 
 `)
 
diff --git a/testscripts/commands/hugo__configdir.txt b/testscripts/commands/hugo__configdir.txt
new file mode 100644
index 00000000000..4da62ade595
--- /dev/null
+++ b/testscripts/commands/hugo__configdir.txt
@@ -0,0 +1,6 @@
+
+hugo
+! stderr .
+
+-- config/_default/hugo.toml --
+baseURL = "https://example.com/"
\ No newline at end of file
diff --git a/testscripts/commands/hugo__flags.txt b/testscripts/commands/hugo__flags.txt
index c2ea92c9564..ad4591322af 100644
--- a/testscripts/commands/hugo__flags.txt
+++ b/testscripts/commands/hugo__flags.txt
@@ -11,6 +11,8 @@ grep '<body>Home' newpublic/index.html
 hugo --quiet
 ! stdout .
 
+-- hugo.toml --
+title = "Hugo Test"
 -- myconfig.toml --
 baseURL = "http://example.org/"
 disableKinds = ["RSS", "sitemap", "robotsTXT", "404", "taxonomy", "term"]
diff --git a/testscripts/commands/hugo__noconfig.txt b/testscripts/commands/hugo__noconfig.txt
new file mode 100644
index 00000000000..c3a6f658879
--- /dev/null
+++ b/testscripts/commands/hugo__noconfig.txt
@@ -0,0 +1,4 @@
+
+! hugo
+
+stderr 'Unable to locate config file or config directory'
\ No newline at end of file
diff --git a/testscripts/commands/new.txt b/testscripts/commands/new.txt
index 11fe753b910..aeebba66d0c 100644
--- a/testscripts/commands/new.txt
+++ b/testscripts/commands/new.txt
@@ -2,7 +2,7 @@
 
 hugo new site -h
 stdout 'Create a new site in the provided directory'
-hugo new site mysite
+hugo new site mysite -f
 stdout 'Congratulations! Your new Hugo site is created in'
 cd mysite
 checkfile hugo.toml
diff --git a/testscripts/commands/server_render_static_to_disk.txt b/testscripts/commands/server_render_static_to_disk.txt
index f2f10e78fc1..b0e76e318ce 100644
--- a/testscripts/commands/server_render_static_to_disk.txt
+++ b/testscripts/commands/server_render_static_to_disk.txt
@@ -6,6 +6,7 @@ hugo server --renderStaticToDisk &
 waitServer
 
 httpget $HUGOTEST_BASEURL_0 'Title: Hugo Server Test' $HUGOTEST_BASEURL_0
+httpget ${HUGOTEST_BASEURL_0}mystatic.txt 'This is a static file.'
 
 ! exists public/index.html
 exists public/mystatic.txt