Пример #1
0
func TestPageCount(t *testing.T) {
	testCommonResetState()
	hugofs.InitMemFs()

	viper.Set("uglyURLs", false)
	viper.Set("paginate", 10)
	s := &Site{
		Source:   &source.InMemorySource{ByteSource: urlFakeSource},
		Language: helpers.NewDefaultLanguage(),
	}

	if err := buildAndRenderSite(s, "indexes/blue.html", indexTemplate); err != nil {
		t.Fatalf("Failed to build site: %s", err)
	}
	_, err := hugofs.Destination().Open("public/blue")
	if err != nil {
		t.Errorf("No indexed rendered.")
	}

	for _, s := range []string{
		"public/sd1/foo/index.html",
		"public/sd2/index.html",
		"public/sd3/index.html",
		"public/sd4.html",
	} {
		if _, err := hugofs.Destination().Open(filepath.FromSlash(s)); err != nil {
			t.Errorf("No alias rendered: %s", s)
		}
	}
}
Пример #2
0
func TestPageCount(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	hugofs.InitMemFs()

	viper.Set("uglyurls", false)
	viper.Set("paginate", 10)
	s := &Site{
		Source: &source.InMemorySource{ByteSource: urlFakeSource},
	}
	s.initializeSiteInfo()
	s.prepTemplates("indexes/blue.html", indexTemplate)

	if err := s.createPages(); err != nil {
		t.Errorf("Unable to create pages: %s", err)
	}
	if err := s.buildSiteMeta(); err != nil {
		t.Errorf("Unable to build site metadata: %s", err)
	}

	if err := s.renderSectionLists(); err != nil {
		t.Errorf("Unable to render section lists: %s", err)
	}

	if err := s.renderAliases(); err != nil {
		t.Errorf("Unable to render site lists: %s", err)
	}

	_, err := hugofs.Destination().Open("blue")
	if err != nil {
		t.Errorf("No indexed rendered.")
	}

	//expected := ".."
	//if string(blueIndex) != expected {
	//t.Errorf("Index template does not match expected: %q, got: %q", expected, string(blueIndex))
	//}

	for _, s := range []string{
		"sd1/foo/index.html",
		"sd2/index.html",
		"sd3/index.html",
		"sd4.html",
	} {
		if _, err := hugofs.Destination().Open(filepath.FromSlash(s)); err != nil {
			t.Errorf("No alias rendered: %s", s)
		}
	}
}
Пример #3
0
func copyStatic() error {
	publishDir := helpers.AbsPathify(viper.GetString("publishDir")) + helpers.FilePathSeparator

	// If root, remove the second '/'
	if publishDir == "//" {
		publishDir = helpers.FilePathSeparator
	}

	// Includes both theme/static & /static
	staticSourceFs := getStaticSourceFs()

	if staticSourceFs == nil {
		jww.WARN.Println("No static directories found to sync")
		return nil
	}

	syncer := fsync.NewSyncer()
	syncer.NoTimes = viper.GetBool("notimes")
	syncer.SrcFs = staticSourceFs
	syncer.DestFs = hugofs.Destination()
	// Now that we are using a unionFs for the static directories
	// We can effectively clean the publishDir on initial sync
	syncer.Delete = viper.GetBool("cleanDestinationDir")
	if syncer.Delete {
		jww.INFO.Println("removing all files from destination that don't exist in static dirs")
	}
	jww.INFO.Println("syncing static files to", publishDir)

	// because we are using a baseFs (to get the union right).
	// set sync src to root
	return syncer.Sync(publishDir, helpers.FilePathSeparator)
}
Пример #4
0
func destinationExists(filename string) bool {
	b, err := helpers.Exists(filename, hugofs.Destination())
	if err != nil {
		panic(err)
	}
	return b
}
Пример #5
0
func serve(port int) {
	if renderToDisk {
		jww.FEEDBACK.Println("Serving pages from " + helpers.AbsPathify(viper.GetString("publishDir")))
	} else {
		jww.FEEDBACK.Println("Serving pages from memory")
	}

	httpFs := afero.NewHttpFs(hugofs.Destination())
	fs := filesOnlyFs{httpFs.Dir(helpers.AbsPathify(viper.GetString("publishDir")))}
	fileserver := http.FileServer(fs)

	// We're only interested in the path
	u, err := url.Parse(viper.GetString("baseURL"))
	if err != nil {
		jww.ERROR.Fatalf("Invalid baseURL: %s", err)
	}
	if u.Path == "" || u.Path == "/" {
		http.Handle("/", fileserver)
	} else {
		http.Handle(u.Path, http.StripPrefix(u.Path, fileserver))
	}

	jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", u.String(), serverInterface)
	fmt.Println("Press Ctrl+C to stop")

	endpoint := net.JoinHostPort(serverInterface, strconv.Itoa(port))
	err = http.ListenAndServe(endpoint, nil)
	if err != nil {
		jww.ERROR.Printf("Error: %s\n", err.Error())
		os.Exit(1)
	}
}
Пример #6
0
func (h *HTMLRedirectAlias) Publish(path string, permalink string, page interface{}) (err error) {
	if path, err = h.Translate(path); err != nil {
		jww.ERROR.Printf("%s, skipping.", err)
		return nil
	}

	t := "alias"
	if strings.HasSuffix(path, ".xhtml") {
		t = "alias-xhtml"
	}

	template := defaultAliasTemplates
	if h.Templates != nil {
		template = h.Templates
		t = "alias.html"
	}

	buffer := new(bytes.Buffer)
	err = template.ExecuteTemplate(buffer, t, &AliasNode{permalink, page})
	if err != nil {
		return
	}

	return helpers.WriteToDisk(path, buffer, hugofs.Destination())
}
Пример #7
0
func TestDefaultHandler(t *testing.T) {
	testCommonResetState()

	hugofs.InitMemFs()
	sources := []source.ByteSource{
		{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
		{Name: filepath.FromSlash("sect/doc2.html"), Content: []byte("<!doctype html><html><body>more content</body></html>")},
		{Name: filepath.FromSlash("sect/doc3.md"), Content: []byte("# doc3\n*some* content")},
		{Name: filepath.FromSlash("sect/doc4.md"), Content: []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")},
		{Name: filepath.FromSlash("sect/doc3/img1.png"), Content: []byte("‰PNG  ��� IHDR����������:~›U��� IDATWcø��ZMo��IEND®B`‚")},
		{Name: filepath.FromSlash("sect/img2.gif"), Content: []byte("GIF89a��€��ÿÿÿ���,�������D�;")},
		{Name: filepath.FromSlash("sect/img2.spf"), Content: []byte("****FAKE-FILETYPE****")},
		{Name: filepath.FromSlash("doc7.html"), Content: []byte("<html><body>doc7 content</body></html>")},
		{Name: filepath.FromSlash("sect/doc8.html"), Content: []byte("---\nmarkup: md\n---\n# title\nsome *content*")},
	}

	viper.Set("DefaultExtension", "html")
	viper.Set("verbose", true)

	s := &Site{
		Source:   &source.InMemorySource{ByteSource: sources},
		targets:  targetList{page: &target.PagePub{UglyURLs: true, PublishDir: "public"}},
		Language: helpers.NewLanguage("en"),
	}

	if err := buildAndRenderSite(s,
		"_default/single.html", "{{.Content}}",
		"head", "<head><script src=\"script.js\"></script></head>",
		"head_abs", "<head><script src=\"/script.js\"></script></head>"); err != nil {
		t.Fatalf("Failed to render site: %s", err)
	}

	tests := []struct {
		doc      string
		expected string
	}{
		{filepath.FromSlash("public/sect/doc1.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
		{filepath.FromSlash("public/sect/doc2.html"), "<!doctype html><html><body>more content</body></html>"},
		{filepath.FromSlash("public/sect/doc3.html"), "\n\n<h1 id=\"doc3\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
		{filepath.FromSlash("public/sect/doc3/img1.png"), string([]byte("‰PNG  ��� IHDR����������:~›U��� IDATWcø��ZMo��IEND®B`‚"))},
		{filepath.FromSlash("public/sect/img2.gif"), string([]byte("GIF89a��€��ÿÿÿ���,�������D�;"))},
		{filepath.FromSlash("public/sect/img2.spf"), string([]byte("****FAKE-FILETYPE****"))},
		{filepath.FromSlash("public/doc7.html"), "<html><body>doc7 content</body></html>"},
		{filepath.FromSlash("public/sect/doc8.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
	}

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.doc)
		if err != nil {
			t.Fatalf("Did not find %s in target.", test.doc)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
		}
	}

}
Пример #8
0
func TestRobotsTXTOutput(t *testing.T) {
	testCommonResetState()

	hugofs.InitMemFs()

	viper.Set("baseurl", "http://auth/bub/")
	viper.Set("enableRobotsTXT", true)

	s := &Site{
		Source:   &source.InMemorySource{ByteSource: weightedSources},
		Language: helpers.NewDefaultLanguage(),
	}

	if err := buildAndRenderSite(s, "robots.txt", robotTxtTemplate); err != nil {
		t.Fatalf("Failed to build site: %s", err)
	}

	robotsFile, err := hugofs.Destination().Open("public/robots.txt")

	if err != nil {
		t.Fatalf("Unable to locate: robots.txt")
	}

	robots := helpers.ReaderToBytes(robotsFile)
	if !bytes.HasPrefix(robots, []byte("User-agent: Googlebot")) {
		t.Errorf("Robots file should start with 'User-agentL Googlebot'. %s", robots)
	}
}
Пример #9
0
func TestSkipRender(t *testing.T) {
	testCommonResetState()

	hugofs.InitMemFs()
	sources := []source.ByteSource{
		{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
		{Name: filepath.FromSlash("sect/doc2.html"), Content: []byte("<!doctype html><html><body>more content</body></html>")},
		{Name: filepath.FromSlash("sect/doc3.md"), Content: []byte("# doc3\n*some* content")},
		{Name: filepath.FromSlash("sect/doc4.md"), Content: []byte("---\ntitle: doc4\n---\n# doc4\n*some content*")},
		{Name: filepath.FromSlash("sect/doc5.html"), Content: []byte("<!doctype html><html>{{ template \"head\" }}<body>body5</body></html>")},
		{Name: filepath.FromSlash("sect/doc6.html"), Content: []byte("<!doctype html><html>{{ template \"head_abs\" }}<body>body5</body></html>")},
		{Name: filepath.FromSlash("doc7.html"), Content: []byte("<html><body>doc7 content</body></html>")},
		{Name: filepath.FromSlash("sect/doc8.html"), Content: []byte("---\nmarkup: md\n---\n# title\nsome *content*")},
	}

	viper.Set("defaultExtension", "html")
	viper.Set("verbose", true)
	viper.Set("canonifyURLs", true)
	viper.Set("baseURL", "http://auth/bub")
	s := &Site{
		Source:   &source.InMemorySource{ByteSource: sources},
		targets:  targetList{page: &target.PagePub{UglyURLs: true}},
		Language: helpers.NewDefaultLanguage(),
	}

	if err := buildAndRenderSite(s,
		"_default/single.html", "{{.Content}}",
		"head", "<head><script src=\"script.js\"></script></head>",
		"head_abs", "<head><script src=\"/script.js\"></script></head>"); err != nil {
		t.Fatalf("Failed to build site: %s", err)
	}

	tests := []struct {
		doc      string
		expected string
	}{
		{filepath.FromSlash("sect/doc1.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
		{filepath.FromSlash("sect/doc2.html"), "<!doctype html><html><body>more content</body></html>"},
		{filepath.FromSlash("sect/doc3.html"), "\n\n<h1 id=\"doc3\">doc3</h1>\n\n<p><em>some</em> content</p>\n"},
		{filepath.FromSlash("sect/doc4.html"), "\n\n<h1 id=\"doc4\">doc4</h1>\n\n<p><em>some content</em></p>\n"},
		{filepath.FromSlash("sect/doc5.html"), "<!doctype html><html><head><script src=\"script.js\"></script></head><body>body5</body></html>"},
		{filepath.FromSlash("sect/doc6.html"), "<!doctype html><html><head><script src=\"http://auth/bub/script.js\"></script></head><body>body5</body></html>"},
		{filepath.FromSlash("doc7.html"), "<html><body>doc7 content</body></html>"},
		{filepath.FromSlash("sect/doc8.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
	}

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.doc)
		if err != nil {
			t.Fatalf("Did not find %s in target.", test.doc)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
		}
	}
}
Пример #10
0
func (fs *Filesystem) Publish(path string, r io.Reader) (err error) {
	translated, err := fs.Translate(path)
	if err != nil {
		return
	}

	return helpers.WriteToDisk(translated, r, hugofs.Destination())
}
Пример #11
0
func TestAbsURLify(t *testing.T) {
	testCommonResetState()

	viper.Set("defaultExtension", "html")

	hugofs.InitMemFs()
	sources := []source.ByteSource{
		{Name: filepath.FromSlash("sect/doc1.html"), Content: []byte("<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>")},
		{Name: filepath.FromSlash("blue/doc2.html"), Content: []byte("---\nf: t\n---\n<!doctype html><html><body>more content</body></html>")},
	}
	for _, baseURL := range []string{"http://auth/bub", "http://base", "//base"} {
		for _, canonify := range []bool{true, false} {
			viper.Set("canonifyURLs", canonify)
			viper.Set("baseURL", baseURL)
			s := &Site{
				Source:   &source.InMemorySource{ByteSource: sources},
				targets:  targetList{page: &target.PagePub{UglyURLs: true}},
				Language: helpers.NewDefaultLanguage(),
			}
			t.Logf("Rendering with baseURL %q and canonifyURLs set %v", viper.GetString("baseURL"), canonify)

			if err := buildAndRenderSite(s, "blue/single.html", templateWithURLAbs); err != nil {
				t.Fatalf("Failed to build site: %s", err)
			}

			tests := []struct {
				file, expected string
			}{
				{"blue/doc2.html", "<a href=\"%s/foobar.jpg\">Going</a>"},
				{"sect/doc1.html", "<!doctype html><html><head></head><body><a href=\"#frag1\">link</a></body></html>"},
			}

			for _, test := range tests {

				file, err := hugofs.Destination().Open(filepath.FromSlash(test.file))
				if err != nil {
					t.Fatalf("Unable to locate rendered content: %s", test.file)
				}

				content := helpers.ReaderToString(file)

				expected := test.expected

				if strings.Contains(expected, "%s") {
					expected = fmt.Sprintf(expected, baseURL)
				}

				if !canonify {
					expected = strings.Replace(expected, baseURL, "", -1)
				}

				if content != expected {
					t.Errorf("AbsURLify with baseURL %q content expected:\n%q\ngot\n%q", baseURL, expected, content)
				}
			}
		}
	}
}
Пример #12
0
func (pp *PagePub) Publish(path string, r io.Reader) (err error) {

	translated, err := pp.Translate(path)
	if err != nil {
		return
	}

	return helpers.WriteToDisk(translated, r, hugofs.Destination())
}
Пример #13
0
func TestRobotsTXTOutput(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	hugofs.InitMemFs()

	viper.Set("baseurl", "http://auth/bub/")
	viper.Set("enableRobotsTXT", true)

	s := &Site{
		Source: &source.InMemorySource{ByteSource: weightedSources},
	}

	s.initializeSiteInfo()

	s.prepTemplates("robots.txt", robotTxtTemplate)

	if err := s.createPages(); err != nil {
		t.Fatalf("Unable to create pages: %s", err)
	}

	if err := s.buildSiteMeta(); err != nil {
		t.Fatalf("Unable to build site metadata: %s", err)
	}

	if err := s.renderHomePage(); err != nil {
		t.Fatalf("Unable to RenderHomePage: %s", err)
	}

	if err := s.renderSitemap(); err != nil {
		t.Fatalf("Unable to RenderSitemap: %s", err)
	}

	if err := s.renderRobotsTXT(); err != nil {
		t.Fatalf("Unable to RenderRobotsTXT :%s", err)
	}

	robotsFile, err := hugofs.Destination().Open("robots.txt")

	if err != nil {
		t.Fatalf("Unable to locate: robots.txt")
	}

	robots := helpers.ReaderToBytes(robotsFile)
	if !bytes.HasPrefix(robots, []byte("User-agent: Googlebot")) {
		t.Errorf("Robots file should start with 'User-agentL Googlebot'. %s", robots)
	}
}
Пример #14
0
func TestRenderThingOrDefault(t *testing.T) {
	tests := []struct {
		missing  bool
		template string
		expected string
	}{
		{true, templateTitle, HTML("simple template")},
		{true, templateFunc, HTML("simple-template")},
		{false, templateTitle, HTML("simple template")},
		{false, templateFunc, HTML("simple-template")},
	}

	hugofs.InitMemFs()

	for i, test := range tests {

		s := &Site{}

		p, err := NewPageFrom(strings.NewReader(pageSimpleTitle), "content/a/file.md")
		if err != nil {
			t.Fatalf("Error parsing buffer: %s", err)
		}
		templateName := fmt.Sprintf("default%d", i)

		s.prepTemplates(templateName, test.template)

		var err2 error

		if test.missing {
			err2 = s.renderAndWritePage("name", "out", p, "missing", templateName)
		} else {
			err2 = s.renderAndWritePage("name", "out", p, templateName, "missing_default")
		}

		if err2 != nil {
			t.Errorf("Unable to render html: %s", err)
		}

		file, err := hugofs.Destination().Open(filepath.FromSlash("out/index.html"))
		if err != nil {
			t.Errorf("Unable to open html: %s", err)
		}
		if helpers.ReaderToString(file) != test.expected {
			t.Errorf("Content does not match. Expected '%s', got '%s'", test.expected, helpers.ReaderToString(file))
		}
	}
}
Пример #15
0
func TestSitemapOutput(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	hugofs.InitMemFs()

	viper.Set("baseurl", "http://auth/bub/")

	s := &Site{
		Source: &source.InMemorySource{ByteSource: weightedSources},
	}

	s.initializeSiteInfo()

	s.prepTemplates("sitemap.xml", SITEMAP_TEMPLATE)

	if err := s.createPages(); err != nil {
		t.Fatalf("Unable to create pages: %s", err)
	}

	if err := s.buildSiteMeta(); err != nil {
		t.Fatalf("Unable to build site metadata: %s", err)
	}

	if err := s.renderHomePage(); err != nil {
		t.Fatalf("Unable to RenderHomePage: %s", err)
	}

	if err := s.renderSitemap(); err != nil {
		t.Fatalf("Unable to RenderSitemap: %s", err)
	}

	if err := s.renderRobotsTXT(); err != nil {
		t.Fatalf("Unable to RenderRobotsTXT :%s", err)
	}

	sitemapFile, err := hugofs.Destination().Open("sitemap.xml")

	if err != nil {
		t.Fatalf("Unable to locate: sitemap.xml")
	}

	sitemap := helpers.ReaderToBytes(sitemapFile)
	if !bytes.HasPrefix(sitemap, []byte("<?xml")) {
		t.Errorf("Sitemap file should start with <?xml. %s", sitemap)
	}
}
Пример #16
0
func TestRSSOutput(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	rssURI := "customrss.xml"
	viper.Set("baseurl", "http://auth/bub/")
	viper.Set("RSSUri", rssURI)

	hugofs.InitMemFs()
	s := &Site{
		Source: &source.InMemorySource{ByteSource: weightedSources},
	}
	s.initializeSiteInfo()
	s.prepTemplates("rss.xml", rssTemplate)

	if err := s.createPages(); err != nil {
		t.Fatalf("Unable to create pages: %s", err)
	}

	if err := s.buildSiteMeta(); err != nil {
		t.Fatalf("Unable to build site metadata: %s", err)
	}

	if err := s.renderHomePage(); err != nil {
		t.Fatalf("Unable to RenderHomePage: %s", err)
	}

	file, err := hugofs.Destination().Open(rssURI)

	if err != nil {
		t.Fatalf("Unable to locate: %s", rssURI)
	}

	rss := helpers.ReaderToBytes(file)
	if !bytes.HasPrefix(rss, []byte("<?xml")) {
		t.Errorf("rss feed should start with <?xml. %s", rss)
	}
}
Пример #17
0
func doTestSectionNaming(t *testing.T, canonify, uglify, pluralize bool) {
	hugofs.InitMemFs()
	viper.Reset()
	defer viper.Reset()
	viper.Set("baseurl", "http://auth/sub/")
	viper.Set("DefaultExtension", "html")
	viper.Set("UglyURLs", uglify)
	viper.Set("PluralizeListTitles", pluralize)
	viper.Set("CanonifyURLs", canonify)

	var expectedPathSuffix string

	if uglify {
		expectedPathSuffix = ".html"
	} else {
		expectedPathSuffix = "/index.html"
	}

	sources := []source.ByteSource{
		{filepath.FromSlash("sect/doc1.html"), []byte("doc1")},
		{filepath.FromSlash("Fish and Chips/doc2.html"), []byte("doc2")},
		{filepath.FromSlash("ラーメン/doc3.html"), []byte("doc3")},
	}

	s := &Site{
		Source:  &source.InMemorySource{ByteSource: sources},
		targets: targetList{page: &target.PagePub{UglyURLs: uglify}},
	}

	s.initializeSiteInfo()
	s.prepTemplates(
		"_default/single.html", "{{.Content}}",
		"_default/list.html", "{{ .Title }}")

	createAndRenderPages(t, s)
	s.renderSectionLists()

	tests := []struct {
		doc         string
		pluralAware bool
		expected    string
	}{
		{filepath.FromSlash(fmt.Sprintf("sect/doc1%s", expectedPathSuffix)), false, "doc1"},
		{filepath.FromSlash(fmt.Sprintf("sect%s", expectedPathSuffix)), true, "Sect"},
		{filepath.FromSlash(fmt.Sprintf("fish-and-chips/doc2%s", expectedPathSuffix)), false, "doc2"},
		{filepath.FromSlash(fmt.Sprintf("fish-and-chips%s", expectedPathSuffix)), true, "Fish and Chips"},
		{filepath.FromSlash(fmt.Sprintf("ラーメン/doc3%s", expectedPathSuffix)), false, "doc3"},
		{filepath.FromSlash(fmt.Sprintf("ラーメン%s", expectedPathSuffix)), true, "ラーメン"},
	}

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.doc)
		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.doc, err)
		}

		content := helpers.ReaderToString(file)

		if test.pluralAware && pluralize {
			test.expected = inflect.Pluralize(test.expected)
		}

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
		}
	}

}
Пример #18
0
func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) {
	viper.Reset()
	defer viper.Reset()

	viper.Set("DefaultExtension", "html")
	viper.Set("verbose", true)
	viper.Set("baseurl", "http://auth/bub")
	viper.Set("DisableSitemap", false)
	viper.Set("DisableRSS", false)
	viper.Set("RSSUri", "index.xml")
	viper.Set("blackfriday",
		map[string]interface{}{
			"plainIDAnchors": true})

	viper.Set("UglyURLs", uglyURLs)

	sources := []source.ByteSource{
		{filepath.FromSlash("sect/doc1.md"), []byte("---\nmarkup: markdown\n---\n# title\nsome *content*")},
		{filepath.FromSlash("sect/doc2.md"), []byte("---\nurl: /ugly.html\nmarkup: markdown\n---\n# title\ndoc2 *content*")},
	}

	s := &Site{
		Source:  &source.InMemorySource{ByteSource: sources},
		targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs}},
	}

	s.initializeSiteInfo()

	s.prepTemplates(
		"index.html", "Home Sweet {{ if.IsHome  }}Home{{ end }}.",
		"_default/single.html", "{{.Content}}{{ if.IsHome  }}This is not home!{{ end }}",
		"404.html", "Page Not Found.{{ if.IsHome  }}This is not home!{{ end }}",
		"rss.xml", "<root>RSS</root>",
		"sitemap.xml", "<root>SITEMAP</root>")

	createAndRenderPages(t, s)
	s.renderHomePage()
	s.renderSitemap()

	var expectedPagePath string
	if uglyURLs {
		expectedPagePath = "sect/doc1.html"
	} else {
		expectedPagePath = "sect/doc1/index.html"
	}

	tests := []struct {
		doc      string
		expected string
	}{
		{filepath.FromSlash("index.html"), "Home Sweet Home."},
		{filepath.FromSlash(expectedPagePath), "\n\n<h1 id=\"title\">title</h1>\n\n<p>some <em>content</em></p>\n"},
		{filepath.FromSlash("404.html"), "Page Not Found."},
		{filepath.FromSlash("index.xml"), "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n<root>RSS</root>"},
		{filepath.FromSlash("sitemap.xml"), "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n<root>SITEMAP</root>"},
		// Issue #1923
		{filepath.FromSlash("ugly.html"), "\n\n<h1 id=\"title\">title</h1>\n\n<p>doc2 <em>content</em></p>\n"},
	}

	for _, p := range s.Pages {
		assert.False(t, p.IsHome)
	}

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.doc)
		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.doc, err)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
		}
	}

}
Пример #19
0
func doTestCrossrefs(t *testing.T, relative, uglyURLs bool) {
	viper.Reset()
	defer viper.Reset()

	baseURL := "http://foo/bar"
	viper.Set("DefaultExtension", "html")
	viper.Set("baseurl", baseURL)
	viper.Set("UglyURLs", uglyURLs)
	viper.Set("verbose", true)

	var refShortcode string
	var expectedBase string
	var expectedURLSuffix string
	var expectedPathSuffix string

	if relative {
		refShortcode = "relref"
		expectedBase = "/bar"
	} else {
		refShortcode = "ref"
		expectedBase = baseURL
	}

	if uglyURLs {
		expectedURLSuffix = ".html"
		expectedPathSuffix = ".html"
	} else {
		expectedURLSuffix = "/"
		expectedPathSuffix = "/index.html"
	}

	sources := []source.ByteSource{
		{filepath.FromSlash("sect/doc1.md"),
			[]byte(fmt.Sprintf(`Ref 2: {{< %s "sect/doc2.md" >}}`, refShortcode))},
		// Issue #1148: Make sure that no P-tags is added around shortcodes.
		{filepath.FromSlash("sect/doc2.md"),
			[]byte(fmt.Sprintf(`**Ref 1:** 

{{< %s "sect/doc1.md" >}}

THE END.`, refShortcode))},
		// Issue #1753: Should not add a trailing newline after shortcode.
		{filepath.FromSlash("sect/doc3.md"),
			[]byte(fmt.Sprintf(`**Ref 1:**{{< %s "sect/doc3.md" >}}.`, refShortcode))},
	}

	s := &Site{
		Source:  &source.InMemorySource{ByteSource: sources},
		targets: targetList{page: &target.PagePub{UglyURLs: uglyURLs}},
	}

	s.initializeSiteInfo()

	s.prepTemplates("_default/single.html", "{{.Content}}")

	createAndRenderPages(t, s)

	tests := []struct {
		doc      string
		expected string
	}{
		{filepath.FromSlash(fmt.Sprintf("sect/doc1%s", expectedPathSuffix)), fmt.Sprintf("<p>Ref 2: %s/sect/doc2%s</p>\n", expectedBase, expectedURLSuffix)},
		{filepath.FromSlash(fmt.Sprintf("sect/doc2%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong></p>\n\n%s/sect/doc1%s\n\n<p>THE END.</p>\n", expectedBase, expectedURLSuffix)},
		{filepath.FromSlash(fmt.Sprintf("sect/doc3%s", expectedPathSuffix)), fmt.Sprintf("<p><strong>Ref 1:</strong>%s/sect/doc3%s.</p>\n", expectedBase, expectedURLSuffix)},
	}

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.doc)

		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.doc, err)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.doc, test.expected, content)
		}
	}

}
Пример #20
0
func TestShortcodesInSite(t *testing.T) {
	testCommonResetState()

	baseURL := "http://foo/bar"
	viper.Set("DefaultExtension", "html")
	viper.Set("DefaultContentLanguage", "en")
	viper.Set("baseurl", baseURL)
	viper.Set("UglyURLs", false)
	viper.Set("verbose", true)

	viper.Set("pygmentsuseclasses", true)
	viper.Set("pygmentscodefences", true)

	tests := []struct {
		contentPath string
		content     string
		outFile     string
		expected    string
	}{
		{"sect/doc1.md", `a{{< b >}}c`,
			filepath.FromSlash("sect/doc1/index.html"), "<p>abc</p>\n"},
		// Issue #1642: Multiple shortcodes wrapped in P
		// Deliberately forced to pass even if they maybe shouldn't.
		{"sect/doc2.md", `a

{{< b >}}		
{{< c >}}
{{< d >}}

e`,
			filepath.FromSlash("sect/doc2/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc\nd</p>\n\n<p>e</p>\n"},
		{"sect/doc3.md", `a

{{< b >}}		
{{< c >}}

{{< d >}}

e`,
			filepath.FromSlash("sect/doc3/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc</p>\n\nd\n\n<p>e</p>\n"},
		{"sect/doc4.md", `a
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}










`,
			filepath.FromSlash("sect/doc4/index.html"),
			"<p>a\nb\nb\nb\nb\nb</p>\n"},
		// #2192 #2209: Shortcodes in markdown headers
		{"sect/doc5.md", `# {{< b >}}	
## {{% c %}}`,
			filepath.FromSlash("sect/doc5/index.html"), "\n\n<h1 id=\"hahahugoshortcode-1hbhb\">b</h1>\n\n<h2 id=\"hahahugoshortcode-2hbhb\">c</h2>\n"},
		// #2223 pygments
		{"sect/doc6.md", "\n```bash\nb: {{< b >}} c: {{% c %}}\n```\n",
			filepath.FromSlash("sect/doc6/index.html"),
			"b: b c: c\n</code></pre></div>\n"},
		// #2249
		{"sect/doc7.ad", `_Shortcodes:_ *b: {{< b >}} c: {{% c %}}*`,
			filepath.FromSlash("sect/doc7/index.html"),
			"<div class=\"paragraph\">\n<p><em>Shortcodes:</em> <strong>b: b c: c</strong></p>\n</div>\n"},
		{"sect/doc8.rst", `**Shortcodes:** *b: {{< b >}} c: {{% c %}}*`,
			filepath.FromSlash("sect/doc8/index.html"),
			"<div class=\"document\">\n\n\n<p><strong>Shortcodes:</strong> <em>b: b c: c</em></p>\n</div>"},
		{"sect/doc9.mmark", `
---
menu:
  main:
    parent: 'parent'
---
**Shortcodes:** *b: {{< b >}} c: {{% c %}}*`,
			filepath.FromSlash("sect/doc9/index.html"),
			"<p><strong>Shortcodes:</strong> <em>b: b c: c</em></p>\n"},
		// Issue #1229: Menus not available in shortcode.
		{"sect/doc10.md", `---
menu:
  main:
    identifier: 'parent'
tags:
- Menu
---
**Menus:** {{< menu >}}`,
			filepath.FromSlash("sect/doc10/index.html"),
			"<p><strong>Menus:</strong> 1</p>\n"},
		// Issue #2323: Taxonomies not available in shortcode.
		{"sect/doc11.md", `---
tags:
- Bugs
---
**Tags:** {{< tags >}}`,
			filepath.FromSlash("sect/doc11/index.html"),
			"<p><strong>Tags:</strong> 2</p>\n"},
	}

	sources := make([]source.ByteSource, len(tests))

	for i, test := range tests {
		sources[i] = source.ByteSource{Name: filepath.FromSlash(test.contentPath), Content: []byte(test.content)}
	}

	s := &Site{
		Source:   &source.InMemorySource{ByteSource: sources},
		targets:  targetList{page: &target.PagePub{UglyURLs: false}},
		Language: helpers.NewDefaultLanguage(),
	}

	addTemplates := func(templ tpl.Template) error {
		templ.AddTemplate("_default/single.html", "{{.Content}}")

		templ.AddInternalShortcode("b.html", `b`)
		templ.AddInternalShortcode("c.html", `c`)
		templ.AddInternalShortcode("d.html", `d`)
		templ.AddInternalShortcode("menu.html", `{{ len (index .Page.Menus "main").Children }}`)
		templ.AddInternalShortcode("tags.html", `{{ len .Page.Site.Taxonomies.tags }}`)

		return nil

	}

	sites, err := newHugoSites(s)

	if err != nil {
		t.Fatalf("Failed to build site: %s", err)
	}

	if err = sites.Build(BuildCfg{withTemplate: addTemplates}); err != nil {
		t.Fatalf("Failed to build site: %s", err)
	}

	for _, test := range tests {
		if strings.HasSuffix(test.contentPath, ".ad") && !helpers.HasAsciidoc() {
			fmt.Println("Skip Asciidoc test case as no Asciidoc present.")
			continue
		} else if strings.HasSuffix(test.contentPath, ".rst") && !helpers.HasRst() {
			fmt.Println("Skip Rst test case as no rst2html present.")
			continue
		} else if strings.Contains(test.expected, "code") && !helpers.HasPygments() {
			fmt.Println("Skip Pygments test case as no pygments present.")
			continue
		}

		file, err := hugofs.Destination().Open(test.outFile)

		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.outFile, err)
		}

		content := helpers.ReaderToString(file)

		if !strings.Contains(content, test.expected) {
			t.Fatalf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content)
		}
	}

}
Пример #21
0
func TestShortcodesInSite(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	baseURL := "http://foo/bar"
	viper.Set("DefaultExtension", "html")
	viper.Set("baseurl", baseURL)
	viper.Set("UglyURLs", false)
	viper.Set("verbose", true)

	tests := []struct {
		contentPath string
		content     string
		outFile     string
		expected    string
	}{
		{"sect/doc1.md", `a{{< b >}}c`,
			filepath.FromSlash("sect/doc1/index.html"), "<p>abc</p>\n"},
		// Issue #1642: Multiple shortcodes wrapped in P
		// Deliberately forced to pass even if they maybe shouldn't.
		{"sect/doc2.md", `a

{{< b >}}		
{{< c >}}
{{< d >}}

e`,
			filepath.FromSlash("sect/doc2/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc\nd</p>\n\n<p>e</p>\n"},
		{"sect/doc3.md", `a

{{< b >}}		
{{< c >}}

{{< d >}}

e`,
			filepath.FromSlash("sect/doc3/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc</p>\n\nd\n\n<p>e</p>\n"},
		{"sect/doc4.md", `a
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}










`,
			filepath.FromSlash("sect/doc4/index.html"),
			"<p>a\nb\nb\nb\nb\nb</p>\n"},
		// #2192 #2209: Shortcodes in markdown headers
		{"sect/doc5.md", `# {{< b >}}	
## {{% c %}}`,
			filepath.FromSlash("sect/doc5/index.html"), "\n\n<h1 id=\"hugoshortcode-1\">b</h1>\n\n<h2 id=\"hugoshortcode-2\">c</h2>\n"},
		{"sect/doc6.md", "\n```bash\n{{< b >}}\n{{% c %}}\n```\n",
			filepath.FromSlash("sect/doc6/index.html"),
			"<pre><code class=\"language-bash\">b\nc\n</code></pre>\n"},
		// #2249
		{"sect/doc7.ad", `_Shortcodes:_ *b: {{< b >}} c: {{% c %}}*`,
			filepath.FromSlash("sect/doc7/index.html"),
			"<div class=\"paragraph\">\n<p><em>Shortcodes:</em> <strong>b: b c: c</strong></p>\n</div>\n"},
	}

	sources := make([]source.ByteSource, len(tests))

	for i, test := range tests {
		sources[i] = source.ByteSource{Name: filepath.FromSlash(test.contentPath), Content: []byte(test.content)}
	}

	s := &Site{
		Source:  &source.InMemorySource{ByteSource: sources},
		targets: targetList{page: &target.PagePub{UglyURLs: false}},
	}

	s.initializeSiteInfo()

	s.loadTemplates()

	s.Tmpl.AddTemplate("_default/single.html", "{{.Content}}")

	s.Tmpl.AddInternalShortcode("b.html", `b`)
	s.Tmpl.AddInternalShortcode("c.html", `c`)
	s.Tmpl.AddInternalShortcode("d.html", `d`)

	s.Tmpl.MarkReady()

	createAndRenderPages(t, s)

	for _, test := range tests {
		if strings.HasSuffix(test.contentPath, ".ad") && !helpers.HasAsciidoc() {
			fmt.Println("Skip Asciidoc test case as no Asciidoc present.")
			continue
		}
		file, err := hugofs.Destination().Open(test.outFile)

		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.outFile, err)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content)
		}
	}

}
Пример #22
0
func readDestination(t *testing.T, filename string) string {
	return readFileFromFs(t, hugofs.Destination(), filename)
}
Пример #23
0
func TestMultiSitesRebuild(t *testing.T) {
	defer leaktest.Check(t)()
	testCommonResetState()
	siteConfig := testSiteConfig{DefaultContentLanguage: "fr"}
	sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate)
	cfg := BuildCfg{Watching: true}

	err := sites.Build(cfg)

	if err != nil {
		t.Fatalf("Failed to build sites: %s", err)
	}

	_, err = hugofs.Destination().Open("public/en/sect/doc2/index.html")

	if err != nil {
		t.Fatalf("Unable to locate file")
	}

	enSite := sites.Sites[0]
	frSite := sites.Sites[1]

	assert.Len(t, enSite.Pages, 3)
	assert.Len(t, frSite.Pages, 3)

	// Verify translations
	docEn := readDestination(t, "public/en/sect/doc1-slug/index.html")
	assert.True(t, strings.Contains(docEn, "Hello"), "No Hello")
	docFr := readDestination(t, "public/fr/sect/doc1/index.html")
	assert.True(t, strings.Contains(docFr, "Bonjour"), "No Bonjour")

	// check single page content
	assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour")
	assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello")

	for i, this := range []struct {
		preFunc    func(t *testing.T)
		events     []fsnotify.Event
		assertFunc func(t *testing.T)
	}{
		// * Remove doc
		// * Add docs existing languages
		// (Add doc new language: TODO(bep) we should load config.toml as part of these so we can add languages).
		// * Rename file
		// * Change doc
		// * Change a template
		// * Change language file
		{
			nil,
			[]fsnotify.Event{{Name: "content/sect/doc2.en.md", Op: fsnotify.Remove}},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 2, "1 en removed")

				// Check build stats
				assert.Equal(t, 1, enSite.draftCount, "Draft")
				assert.Equal(t, 1, enSite.futureCount, "Future")
				assert.Equal(t, 1, enSite.expiredCount, "Expired")
				assert.Equal(t, 0, frSite.draftCount, "Draft")
				assert.Equal(t, 1, frSite.futureCount, "Future")
				assert.Equal(t, 1, frSite.expiredCount, "Expired")
			},
		},
		{
			func(t *testing.T) {
				writeNewContentFile(t, "new_en_1", "2016-07-31", "content/new1.en.md", -5)
				writeNewContentFile(t, "new_en_2", "1989-07-30", "content/new2.en.md", -10)
				writeNewContentFile(t, "new_fr_1", "2016-07-30", "content/new1.fr.md", 10)
			},
			[]fsnotify.Event{
				{Name: "content/new1.en.md", Op: fsnotify.Create},
				{Name: "content/new2.en.md", Op: fsnotify.Create},
				{Name: "content/new1.fr.md", Op: fsnotify.Create},
			},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4)
				assert.Len(t, enSite.AllPages, 10)
				assert.Len(t, frSite.Pages, 4)
				assert.Equal(t, "new_fr_1", frSite.Pages[3].Title)
				assert.Equal(t, "new_en_2", enSite.Pages[0].Title)
				assert.Equal(t, "new_en_1", enSite.Pages[1].Title)

				rendered := readDestination(t, "public/en/new1/index.html")
				assert.True(t, strings.Contains(rendered, "new_en_1"), rendered)
			},
		},
		{
			func(t *testing.T) {
				p := "content/sect/doc1.en.md"
				doc1 := readSource(t, p)
				doc1 += "CHANGED"
				writeSource(t, p, doc1)
			},
			[]fsnotify.Event{{Name: "content/sect/doc1.en.md", Op: fsnotify.Write}},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4)
				doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html")
				assert.True(t, strings.Contains(doc1, "CHANGED"), doc1)

			},
		},
		// Rename a file
		{
			func(t *testing.T) {
				if err := hugofs.Source().Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil {
					t.Fatalf("Rename failed: %s", err)
				}
			},
			[]fsnotify.Event{
				{Name: "content/new1renamed.en.md", Op: fsnotify.Rename},
				{Name: "content/new1.en.md", Op: fsnotify.Rename},
			},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4, "Rename")
				assert.Equal(t, "new_en_1", enSite.Pages[1].Title)
				rendered := readDestination(t, "public/en/new1renamed/index.html")
				assert.True(t, strings.Contains(rendered, "new_en_1"), rendered)
			}},
		{
			// Change a template
			func(t *testing.T) {
				template := "layouts/_default/single.html"
				templateContent := readSource(t, template)
				templateContent += "{{ print \"Template Changed\"}}"
				writeSource(t, template, templateContent)
			},
			[]fsnotify.Event{{Name: "layouts/_default/single.html", Op: fsnotify.Write}},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4)
				assert.Len(t, enSite.AllPages, 10)
				assert.Len(t, frSite.Pages, 4)
				doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html")
				assert.True(t, strings.Contains(doc1, "Template Changed"), doc1)
			},
		},
		{
			// Change a language file
			func(t *testing.T) {
				languageFile := "i18n/fr.yaml"
				langContent := readSource(t, languageFile)
				langContent = strings.Replace(langContent, "Bonjour", "Salut", 1)
				writeSource(t, languageFile, langContent)
			},
			[]fsnotify.Event{{Name: "i18n/fr.yaml", Op: fsnotify.Write}},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4)
				assert.Len(t, enSite.AllPages, 10)
				assert.Len(t, frSite.Pages, 4)
				docEn := readDestination(t, "public/en/sect/doc1-slug/index.html")
				assert.True(t, strings.Contains(docEn, "Hello"), "No Hello")
				docFr := readDestination(t, "public/fr/sect/doc1/index.html")
				assert.True(t, strings.Contains(docFr, "Salut"), "No Salut")

				homeEn := enSite.getNode("home-0")
				require.NotNil(t, homeEn)
				require.Len(t, homeEn.Translations(), 3)
				require.Equal(t, "fr", homeEn.Translations()[0].Lang())

			},
		},
		// Change a shortcode
		{
			func(t *testing.T) {
				writeSource(t, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}")
			},
			[]fsnotify.Event{
				{Name: "layouts/shortcodes/shortcode.html", Op: fsnotify.Write},
			},
			func(t *testing.T) {
				assert.Len(t, enSite.Pages, 4)
				assert.Len(t, enSite.AllPages, 10)
				assert.Len(t, frSite.Pages, 4)
				assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Modified Shortcode: Salut")
				assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Modified Shortcode: Hello")
			},
		},
	} {

		if this.preFunc != nil {
			this.preFunc(t)
		}
		err = sites.Rebuild(cfg, this.events...)

		if err != nil {
			t.Fatalf("[%d] Failed to rebuild sites: %s", i, err)
		}

		this.assertFunc(t)
	}

	// Check that the drafts etc. are not built/processed/rendered.
	assertShouldNotBuild(t, sites)

}
Пример #24
0
// NewWatcher creates a new watcher to watch filesystem events.
func NewWatcher(port int) error {
	if runtime.GOOS == "darwin" {
		tweakLimit()
	}

	watcher, err := watcher.New(1 * time.Second)
	var wg sync.WaitGroup

	if err != nil {
		return err
	}

	defer watcher.Close()

	wg.Add(1)

	for _, d := range getDirList() {
		if d != "" {
			_ = watcher.Add(d)
		}
	}

	go func() {
		for {
			select {
			case evs := <-watcher.Events:
				jww.INFO.Println("Received System Events:", evs)

				staticEvents := []fsnotify.Event{}
				dynamicEvents := []fsnotify.Event{}

				for _, ev := range evs {
					ext := filepath.Ext(ev.Name)
					baseName := filepath.Base(ev.Name)
					istemp := strings.HasSuffix(ext, "~") ||
						(ext == ".swp") || // vim
						(ext == ".swx") || // vim
						(ext == ".tmp") || // generic temp file
						(ext == ".DS_Store") || // OSX Thumbnail
						baseName == "4913" || // vim
						strings.HasPrefix(ext, ".goutputstream") || // gnome
						strings.HasSuffix(ext, "jb_old___") || // intelliJ
						strings.HasSuffix(ext, "jb_tmp___") || // intelliJ
						strings.HasSuffix(ext, "jb_bak___") || // intelliJ
						strings.HasPrefix(ext, ".sb-") || // byword
						strings.HasPrefix(baseName, ".#") || // emacs
						strings.HasPrefix(baseName, "#") // emacs
					if istemp {
						continue
					}
					// Sometimes during rm -rf operations a '"": REMOVE' is triggered. Just ignore these
					if ev.Name == "" {
						continue
					}

					// Write and rename operations are often followed by CHMOD.
					// There may be valid use cases for rebuilding the site on CHMOD,
					// but that will require more complex logic than this simple conditional.
					// On OS X this seems to be related to Spotlight, see:
					// https://github.com/go-fsnotify/fsnotify/issues/15
					// A workaround is to put your site(s) on the Spotlight exception list,
					// but that may be a little mysterious for most end users.
					// So, for now, we skip reload on CHMOD.
					// We do have to check for WRITE though. On slower laptops a Chmod
					// could be aggregated with other important events, and we still want
					// to rebuild on those
					if ev.Op&(fsnotify.Chmod|fsnotify.Write|fsnotify.Create) == fsnotify.Chmod {
						continue
					}

					walkAdder := func(path string, f os.FileInfo, err error) error {
						if f.IsDir() {
							jww.FEEDBACK.Println("adding created directory to watchlist", path)
							watcher.Add(path)
						}
						return nil
					}

					// recursively add new directories to watch list
					// When mkdir -p is used, only the top directory triggers an event (at least on OSX)
					if ev.Op&fsnotify.Create == fsnotify.Create {
						if s, err := hugofs.Source().Stat(ev.Name); err == nil && s.Mode().IsDir() {
							helpers.SymbolicWalk(hugofs.Source(), ev.Name, walkAdder)
						}
					}

					isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(helpers.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, helpers.GetThemesDirPath()))

					if isstatic {
						staticEvents = append(staticEvents, ev)
					} else {
						dynamicEvents = append(dynamicEvents, ev)
					}
				}

				if len(staticEvents) > 0 {
					publishDir := helpers.AbsPathify(viper.GetString("PublishDir")) + helpers.FilePathSeparator

					// If root, remove the second '/'
					if publishDir == "//" {
						publishDir = helpers.FilePathSeparator
					}

					jww.FEEDBACK.Println("\nStatic file changes detected")
					const layout = "2006-01-02 15:04 -0700"
					fmt.Println(time.Now().Format(layout))

					if viper.GetBool("ForceSyncStatic") {
						jww.FEEDBACK.Printf("Syncing all static files\n")
						err := copyStatic()
						if err != nil {
							utils.StopOnErr(err, fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))
						}
					} else {
						staticSourceFs := getStaticSourceFs()

						if staticSourceFs == nil {
							jww.WARN.Println("No static directories found to sync")
							return
						}

						syncer := fsync.NewSyncer()
						syncer.NoTimes = viper.GetBool("notimes")
						syncer.SrcFs = staticSourceFs
						syncer.DestFs = hugofs.Destination()

						// prevent spamming the log on changes
						logger := helpers.NewDistinctFeedbackLogger()

						for _, ev := range staticEvents {
							// Due to our approach of layering both directories and the content's rendered output
							// into one we can't accurately remove a file not in one of the source directories.
							// If a file is in the local static dir and also in the theme static dir and we remove
							// it from one of those locations we expect it to still exist in the destination
							//
							// If Hugo generates a file (from the content dir) over a static file
							// the content generated file should take precedence.
							//
							// Because we are now watching and handling individual events it is possible that a static
							// event that occupies the same path as a content generated file will take precedence
							// until a regeneration of the content takes places.
							//
							// Hugo assumes that these cases are very rare and will permit this bad behavior
							// The alternative is to track every single file and which pipeline rendered it
							// and then to handle conflict resolution on every event.

							fromPath := ev.Name

							// If we are here we already know the event took place in a static dir
							relPath, err := helpers.MakeStaticPathRelative(fromPath)
							if err != nil {
								fmt.Println(err)
								continue
							}

							// Remove || rename is harder and will require an assumption.
							// Hugo takes the following approach:
							// If the static file exists in any of the static source directories after this event
							// Hugo will re-sync it.
							// If it does not exist in all of the static directories Hugo will remove it.
							//
							// This assumes that Hugo has not generated content on top of a static file and then removed
							// the source of that static file. In this case Hugo will incorrectly remove that file
							// from the published directory.
							if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
								if _, err := staticSourceFs.Stat(relPath); os.IsNotExist(err) {
									// If file doesn't exist in any static dir, remove it
									toRemove := filepath.Join(publishDir, relPath)
									logger.Println("File no longer exists in static dir, removing", toRemove)
									hugofs.Destination().RemoveAll(toRemove)
								} else if err == nil {
									// If file still exists, sync it
									logger.Println("Syncing", relPath, "to", publishDir)
									if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
										jww.ERROR.Println(err)
									}
								} else {
									jww.ERROR.Println(err)
								}

								continue
							}

							// For all other event operations Hugo will sync static.
							logger.Println("Syncing", relPath, "to", publishDir)
							if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
								jww.ERROR.Println(err)
							}
						}
					}

					if !buildWatch && !viper.GetBool("DisableLiveReload") {
						// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized

						// force refresh when more than one file
						if len(staticEvents) > 0 {
							for _, ev := range staticEvents {
								path, _ := helpers.MakeStaticPathRelative(ev.Name)
								livereload.RefreshPath(path)
							}

						} else {
							livereload.ForceRefresh()
						}
					}
				}

				if len(dynamicEvents) > 0 {
					fmt.Print("\nChange detected, rebuilding site\n")
					const layout = "2006-01-02 15:04 -0700"
					fmt.Println(time.Now().Format(layout))

					rebuildSite(dynamicEvents)

					if !buildWatch && !viper.GetBool("DisableLiveReload") {
						// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
						livereload.ForceRefresh()
					}
				}
			case err := <-watcher.Errors:
				if err != nil {
					fmt.Println("error:", err)
				}
			}
		}
	}()

	if port > 0 {
		if !viper.GetBool("DisableLiveReload") {
			livereload.Initialize()
			http.HandleFunc("/livereload.js", livereload.ServeJS)
			http.HandleFunc("/livereload", livereload.Handler)
		}

		go serve(port)
	}

	wg.Wait()
	return nil
}
Пример #25
0
func TestShortcodesInSite(t *testing.T) {
	viper.Reset()
	defer viper.Reset()

	baseURL := "http://foo/bar"
	viper.Set("DefaultExtension", "html")
	viper.Set("baseurl", baseURL)
	viper.Set("UglyURLs", false)
	viper.Set("verbose", true)

	tests := []struct {
		contentPath string
		content     string
		outFile     string
		expected    string
	}{
		{"sect/doc1.md", `a{{< b >}}c`,
			filepath.FromSlash("sect/doc1/index.html"), "<p>abc</p>\n"},
		// Issue #1642: Multiple shortcodes wrapped in P
		// Deliberately forced to pass even if they maybe shouldn't.
		{"sect/doc2.md", `a

{{< b >}}		
{{< c >}}
{{< d >}}

e`,
			filepath.FromSlash("sect/doc2/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc\nd</p>\n\n<p>e</p>\n"},
		{"sect/doc3.md", `a

{{< b >}}		
{{< c >}}

{{< d >}}

e`,
			filepath.FromSlash("sect/doc3/index.html"),
			"<p>a</p>\n\n<p>b<br />\nc</p>\n\nd\n\n<p>e</p>\n"},
		{"sect/doc4.md", `a
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}
{{< b >}}










`,
			filepath.FromSlash("sect/doc4/index.html"),
			"<p>a\nb\nb\nb\nb\nb</p>\n"},
	}

	sources := make([]source.ByteSource, len(tests))

	for i, test := range tests {
		sources[i] = source.ByteSource{Name: filepath.FromSlash(test.contentPath), Content: []byte(test.content)}
	}

	s := &Site{
		Source:  &source.InMemorySource{ByteSource: sources},
		targets: targetList{page: &target.PagePub{UglyURLs: false}},
	}

	s.initializeSiteInfo()

	s.loadTemplates()

	s.Tmpl.AddTemplate("_default/single.html", "{{.Content}}")

	s.Tmpl.AddInternalShortcode("b.html", `b`)
	s.Tmpl.AddInternalShortcode("c.html", `c`)
	s.Tmpl.AddInternalShortcode("d.html", `d`)

	s.Tmpl.MarkReady()

	createAndRenderPages(t, s)

	for _, test := range tests {
		file, err := hugofs.Destination().Open(test.outFile)

		if err != nil {
			t.Fatalf("Did not find %s in target: %s", test.outFile, err)
		}

		content := helpers.ReaderToString(file)

		if content != test.expected {
			t.Errorf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content)
		}
	}

}