Repository: gohugoio/hugo (language: go)

Issue:
Dev server is broken in 0.99 when using the Multilingual Multihost mode
The dev mode for Multilingual Multihost seems to be broken in 0.99. It is not broken in 0.98. Here are the steps to reproduce.
* Create a new site:
  ```sh
  hugo new site quickstart
  ```
* Edit config.toml:
  ```toml
  defaultContentLanguage = 'en'
  [languages]
    [languages.en]
      baseURL = 'https://example.com'
      title = 'My blog'
      weight = 1
    [languages.fr]
      baseURL = 'https://example.fr'
      title = 'Mon blogue'
      weight = 2
  ```
* Run:
  ```sh
  hugo server
  ```
  resulting in:
  <pre>panic: runtime error: index out of range [1] with length 1
  
  goroutine 1 [running]:
  github.com/gohugoio/hugo/commands.(*serverCmd).server.func1(0xc000301770)
          /root/project/hugo/commands/server.go:222 +0x6e5
  github.com/gohugoio/hugo/commands.(*commandeer).loadConfig(0xc000301770)
          /root/project/hugo/commands/commandeer.go:390 +0x702
  github.com/gohugoio/hugo/commands.newCommandeer(0x1, 0x1, 0x1, 0xc000301590, {0x2874040?, 0xc000370bc0}, 0xc0003dd9a0, {0x0, 0x0, 0x0})
          /root/project/hugo/commands/commandeer.go:226 +0x310
  github.com/gohugoio/hugo/commands.initializeConfig(0x0?, 0x0?, 0x0?, 0x22fabba?, {0x2874040?, 0xc000370bc0?}, 0x1d0?)
          /root/project/hugo/commands/hugo.go:125 +0x31
  github.com/gohugoio/hugo/commands.(*serverCmd).server(0xc000370bc0, 0xc000213900, {0xc00024c500?, 0xa56e40?, 0xc0007ffd00?})
          /root/project/hugo/commands/server.go:249 +0x1cd
  github.com/gohugoio/hugo/commands.(*commandsBuilder).newServerCmdSignaled.func1(0xc000213900?, {0x39fa650?, 0x0?, 0x0?})
          /root/project/hugo/commands/server.go:96 +0x36
  github.com/spf13/cobra.(*Command).execute(0xc000213900, {0x39fa650, 0x0, 0x0})
          /go/pkg/mod/github.com/spf13/cobra@v1.4.0/command.go:856 +0x67c
  github.com/spf13/cobra.(*Command).ExecuteC(0xc00084f400)
          /go/pkg/mod/github.com/spf13/cobra@v1.4.0/command.go:974 +0x3b4
  github.com/gohugoio/hugo/commands.Execute({0xc00003c050, 0x1, 0x1})
          /root/project/hugo/commands/hugo.go:92 +0xb4
  main.main()
          /root/project/hugo/main.go:23 +0x57</pre>

If you remove the `baseURL` fields, the `hugo server` command seems to work as expected.

### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.99.0-1de333e7a3fc863672ec6d6cd53ba66dbcdd2305+extended linux/amd64 BuildDate=2022-05-16T08:10:56Z VendorInfo=gohugoio
</pre>

### Does this issue reproduce with the latest release?

It does with 0.99. The problem is not there in 0.98.



Discussion / hints:
Happening to me as well with [my repo](https://github.com/rodrigoalcarazdelaosa/fisiquimicamente), which built without issues with v0.98. I (and Netlify too) can build my site correctly running `hugo` even with v0.99 though, so the problem is only with `hugo server`.

Fix patch:
diff --git a/commands/server.go b/commands/server.go
index a1605e97cf1..ff8fe4cd294 100644
--- a/commands/server.go
+++ b/commands/server.go
@@ -168,6 +168,14 @@ func (sc *serverCmd) server(cmd *cobra.Command, args []string) error {
 			c.Set("watch", true)
 		}
 
+		// TODO(bep) see issue 9901
+		// cfgInit is called twice, before and after the languages have been initialized.
+		// The servers (below) can not be initialized before we
+		// know if we're configured in a multihost setup.
+		if len(c.languages) == 0 {
+			return nil
+		}
+
 		// We can only do this once.
 		serverCfgInit.Do(func() {
 			c.serverPorts = make([]serverPortListener, 1)


Test patch:
diff --git a/commands/server_test.go b/commands/server_test.go
index c2aa0dfd5d7..56d3949ee83 100644
--- a/commands/server_test.go
+++ b/commands/server_test.go
@@ -41,7 +41,7 @@ func TestServerPanicOnConfigError(t *testing.T) {
 linenos='table'
 `
 
-	r := runServerTest(c, false, config)
+	r := runServerTest(c, 0, config)
 
 	c.Assert(r.err, qt.IsNotNil)
 	c.Assert(r.err.Error(), qt.Contains, "cannot parse 'Highlight.LineNos' as bool:")
@@ -52,7 +52,7 @@ func TestServerFlags(t *testing.T) {
 
 	assertPublic := func(c *qt.C, r serverTestResult, renderStaticToDisk bool) {
 		c.Assert(r.err, qt.IsNil)
-		c.Assert(r.homeContent, qt.Contains, "Environment: development")
+		c.Assert(r.homesContent[0], qt.Contains, "Environment: development")
 		c.Assert(r.publicDirnames["myfile.txt"], qt.Equals, renderStaticToDisk)
 
 	}
@@ -81,7 +81,7 @@ baseURL="https://example.org"
 				args = strings.Split(test.flag, "=")
 			}
 
-			r := runServerTest(c, true, config, args...)
+			r := runServerTest(c, 1, config, args...)
 
 			test.assert(c, r)
 
@@ -95,30 +95,52 @@ func TestServerBugs(t *testing.T) {
 	c := qt.New(t)
 
 	for _, test := range []struct {
-		name   string
-		flag   string
-		assert func(c *qt.C, r serverTestResult)
+		name       string
+		config     string
+		flag       string
+		numservers int
+		assert     func(c *qt.C, r serverTestResult)
 	}{
 		// Issue 9788
-		{"PostProcess, memory", "", func(c *qt.C, r serverTestResult) {
+		{"PostProcess, memory", "", "", 1, func(c *qt.C, r serverTestResult) {
 			c.Assert(r.err, qt.IsNil)
-			c.Assert(r.homeContent, qt.Contains, "PostProcess: /foo.min.css")
+			c.Assert(r.homesContent[0], qt.Contains, "PostProcess: /foo.min.css")
 		}},
-		{"PostProcess, disk", "--renderToDisk", func(c *qt.C, r serverTestResult) {
+		{"PostProcess, disk", "", "--renderToDisk", 1, func(c *qt.C, r serverTestResult) {
 			c.Assert(r.err, qt.IsNil)
-			c.Assert(r.homeContent, qt.Contains, "PostProcess: /foo.min.css")
+			c.Assert(r.homesContent[0], qt.Contains, "PostProcess: /foo.min.css")
+		}},
+		// Isue 9901
+		{"Multihost", `
+defaultContentLanguage = 'en'
+[languages]
+[languages.en]
+baseURL = 'https://example.com'
+title = 'My blog'
+weight = 1
+[languages.fr]
+baseURL = 'https://example.fr'
+title = 'Mon blogue'
+weight = 2
+`, "", 2, func(c *qt.C, r serverTestResult) {
+			c.Assert(r.err, qt.IsNil)
+			for i, s := range []string{"My blog", "Mon blogue"} {
+				c.Assert(r.homesContent[i], qt.Contains, s)
+			}
 		}},
 	} {
 		c.Run(test.name, func(c *qt.C) {
-			config := `
+			if test.config == "" {
+				test.config = `
 baseURL="https://example.org"
 `
+			}
 
 			var args []string
 			if test.flag != "" {
 				args = strings.Split(test.flag, "=")
 			}
-			r := runServerTest(c, true, config, args...)
+			r := runServerTest(c, test.numservers, test.config, args...)
 			test.assert(c, r)
 
 		})
@@ -129,11 +151,11 @@ baseURL="https://example.org"
 
 type serverTestResult struct {
 	err            error
-	homeContent    string
+	homesContent   []string
 	publicDirnames map[string]bool
 }
 
-func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result serverTestResult) {
+func runServerTest(c *qt.C, getNumHomes int, config string, args ...string) (result serverTestResult) {
 	dir := createSimpleTestSite(c, testSiteConfig{configTOML: config})
 
 	sp, err := helpers.FindAvailablePort()
@@ -162,16 +184,21 @@ func runServerTest(c *qt.C, getHome bool, config string, args ...string) (result
 		return err
 	})
 
-	if getHome {
+	if getNumHomes > 0 {
 		// Esp. on slow CI machines, we need to wait a little before the web
 		// server is ready.
 		time.Sleep(567 * time.Millisecond)
-		resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port))
-		c.Check(err, qt.IsNil)
-		c.Check(resp.StatusCode, qt.Equals, http.StatusOK)
-		if err == nil {
-			defer resp.Body.Close()
-			result.homeContent = helpers.ReaderToString(resp.Body)
+		result.homesContent = make([]string, getNumHomes)
+		for i := 0; i < getNumHomes; i++ {
+			func() {
+				resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port+i))
+				c.Check(err, qt.IsNil)
+				c.Check(resp.StatusCode, qt.Equals, http.StatusOK)
+				if err == nil {
+					defer resp.Body.Close()
+					result.homesContent[i] = helpers.ReaderToString(resp.Body)
+				}
+			}()
 		}
 	}