diff --git a/.gitignore b/.gitignore index 16bccca..7a7d54f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ anna *.exe **/.DS_Store *.pprof +ssg/ +*.txt \ No newline at end of file diff --git a/TODO.md b/TODO.md index 126b196..0175629 100644 --- a/TODO.md +++ b/TODO.md @@ -50,3 +50,6 @@ pkg - [ ] tests for `main.go` - [x] Add status checks for PRs and fix netlify deploy preview - [ ] Minimum test coverage of 60% for all packages + - [ ] Minimum test coverage of 60% for `engine` + - [ ] Minimum test coverage of 60% for `helper` + - [x] Minimum test coverage of 60% for `parser` diff --git a/cmd/anna/profiler.go.temp b/cmd/anna/profiler.go similarity index 69% rename from cmd/anna/profiler.go.temp rename to cmd/anna/profiler.go index 978ecbe..0b8358f 100644 --- a/cmd/anna/profiler.go.temp +++ b/cmd/anna/profiler.go @@ -8,35 +8,6 @@ import ( "time" ) -// StartProfiling() -// startTime := time.Now() -// if prof { -// go func() { -// for { -// time.Sleep(5 * time.Second) //change as per needed -// PrintStats(time.Since(startTime)) -// } -// }() -// } -// generator.StartLiveReload(addr) -// } -// - -// if validateHTML { -// anna.ValidateHTMLContent() -// } -// // if prof { - -// generator.RenderSite("") - -// // elapsedTimesince := time.Since(startTime) //this didn't work for some reason and was giving negitive deviation -// // // elapsedTime := time.Now().Sub(startTime) - -// // PrintStats(elapsedTimesince) -// // // PrintStats(elapsedTime) -// // defer StopProfiling() -// // } - func PrintStats(elapsedTime time.Duration) { memStats := new(runtime.MemStats) runtime.ReadMemStats(memStats) @@ -44,7 +15,6 @@ func PrintStats(elapsedTime time.Duration) { log.Printf("Time Elapsed: %s", elapsedTime) cpuUsage := runtime.NumCPU() threads := runtime.GOMAXPROCS(0) - // memStats := new(runtime.MemStats) runtime.ReadMemStats(memStats) log.Printf("Threads: %d", threads) diff --git a/main.go b/main.go index 68c7174..9b1499e 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "log" + "time" "github.com/acmpesuecc/anna/cmd/anna" "github.com/spf13/cobra" @@ -29,7 +30,13 @@ func main() { } if prof { - cmd.Println("TODO: To be filled later") + startTime := time.Now() + go anna.StartProfiling() + + annaCmd.VanillaRender() + elapsedTime := time.Now().Sub(startTime) + go anna.PrintStats(elapsedTime) + defer anna.StopProfiling() } if validateHTML { diff --git a/pkg/engine/anna_engine.go b/pkg/engine/anna_engine.go index 0cc6500..209a9b9 100644 --- a/pkg/engine/anna_engine.go +++ b/pkg/engine/anna_engine.go @@ -3,9 +3,11 @@ package engine import ( "bytes" "cmp" + "fmt" "html/template" "os" "slices" + "sort" "strings" "time" @@ -66,13 +68,28 @@ func (e *Engine) GenerateSitemap(outFilePath string) { buffer.WriteString("\n") buffer.WriteString("\n") - // iterate over parsed markdown files + // Sorting templates by key + keys := make([]string, 0, len(e.Templates)) + for k := range e.Templates { + keys = append(keys, string(k)) + } + sort.Strings(keys) + + tempTemplates := make(map[template.URL]parser.TemplateData) + for _, templateURL := range keys { + tempTemplates[template.URL(templateURL)] = e.Templates[template.URL(templateURL)] + } + + e.Templates = tempTemplates + + fmt.Println(e.LayoutConfig.BaseURL) + // Iterate over parsed markdown files for _, templateData := range e.Templates { url := e.LayoutConfig.BaseURL + "/" + templateData.FilenameWithoutExtension + ".html" - buffer.WriteString(" \n") - buffer.WriteString(" " + url + "\n") - buffer.WriteString(" " + templateData.Frontmatter.Date + "\n") - buffer.WriteString(" \n") + buffer.WriteString("\t\n") + buffer.WriteString("\t\t" + url + "\n") + buffer.WriteString("\t\t" + templateData.Frontmatter.Date + "\n") + buffer.WriteString("\t\n") } buffer.WriteString("\n") // helpers.SiteDataPath is the DirPath diff --git a/pkg/engine/anna_engine_test.go b/pkg/engine/anna_engine_test.go index 6fb6a90..203e734 100644 --- a/pkg/engine/anna_engine_test.go +++ b/pkg/engine/anna_engine_test.go @@ -55,7 +55,7 @@ func TestRenderTags(t *testing.T) { }, } - templ, err := template.ParseFiles(TestDirPath+"engine/render_tags/tags_template.html", TestDirPath+"engine/render_tags/tags_subpage_template.html") + templ, err := template.ParseFiles(TestDirPath+"render_tags/tags_template.html", TestDirPath+"render_tags/tags_subpage_template.html") if err != nil { t.Errorf("%v", err) } @@ -63,12 +63,12 @@ func TestRenderTags(t *testing.T) { t.Run("render tag.html", func(t *testing.T) { - got_tags_file, err := os.ReadFile(TestDirPath + "engine/render_tags/rendered/tags.html") + got_tags_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags.html") if err != nil { t.Errorf("%v", err) } - want_tags_file, err := os.ReadFile(TestDirPath + "engine/render_tags/want_tags.html") + want_tags_file, err := os.ReadFile(TestDirPath + "render_tags/want_tags.html") if err != nil { t.Errorf("%v", err) } @@ -80,12 +80,12 @@ func TestRenderTags(t *testing.T) { t.Run("render tag-subpage.html", func(t *testing.T) { - got_blogs_file, err := os.ReadFile(TestDirPath + "engine/render_tags/rendered/tags/blogs.html") + got_blogs_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/blogs.html") if err != nil { t.Errorf("%v", err) } - want_blogs_file, err := os.ReadFile(TestDirPath + "engine/render_tags/want_blogs_tags.html") + want_blogs_file, err := os.ReadFile(TestDirPath + "render_tags/want_blogs_tags.html") if err != nil { t.Errorf("%v", err) } @@ -94,12 +94,12 @@ func TestRenderTags(t *testing.T) { t.Errorf("The expected and generated blogs.html tag-subpage can be found in test/engine/render_tags/rendered/tags/") } - got_tech_file, err := os.ReadFile(TestDirPath + "engine/render_tags/rendered/tags/tech.html") + got_tech_file, err := os.ReadFile(TestDirPath + "render_tags/rendered/tags/tech.html") if err != nil { t.Errorf("%v", err) } - want_tech_file, err := os.ReadFile(TestDirPath + "engine/render_tags/want_tech_tags.html") + want_tech_file, err := os.ReadFile(TestDirPath + "render_tags/want_tech_tags.html") if err != nil { t.Errorf("%v", err) } @@ -110,74 +110,72 @@ func TestRenderTags(t *testing.T) { }) } -// /* -// func TestGenerateSitemap(t *testing.T) { -// t.Run("render sitemap.xml", func(t *testing.T) { -// engine := engine.Engine{ -// Templates: make(map[template.URL]parser.TemplateData), -// TagsMap: make(map[string][]parser.TemplateData), -// ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), -// } - -// t1 := parser.TemplateData{ -// FilenameWithoutExtension: "index", -// Frontmatter: parser.Frontmatter{ -// Date: "2024-02-23", -// }, -// } - -// t2 := parser.TemplateData{ -// FilenameWithoutExtension: "about", -// Frontmatter: parser.Frontmatter{ -// Date: "2023-01-02", -// }, -// } - -// t3 := parser.TemplateData{ -// FilenameWithoutExtension: "research", -// Frontmatter: parser.Frontmatter{ -// Date: "2024-01-01", -// }, -// } - -// engine.LayoutConfig.BaseURL = "https://ssg-test-org.github.io" -// // setting up engine -// engine.Templates["index"] = t1 -// engine.Templates["about"] = t2 -// engine.Templates["research"] = t3 - -// engine.GenerateSitemap(TestDirPath + "layout/sitemap/got_sitemap.xml") - -// got_sitemap, err := os.ReadFile(TestDirPath + "layout/sitemap/got_sitemap.xml") -// if err != nil { -// t.Errorf("Error in reading the contents of got_sitemap.xml") -// } - -// want_sitemap, err := os.ReadFile(TestDirPath + "layout/sitemap/want_sitemap.xml") -// if err != nil { -// t.Errorf("Error in reading the contents of got_sitemap.xml") -// } - -// // remove spaces and whitespace characters -// /* -// got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), " ", "")) -// want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), " ", "")) -// // replace all tabs -// got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), "\t", "")) -// want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), "\t", "")) - -// got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), "\n", "")) -// want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), "\n", "")) - -// fmt.Println(string(got_sitemap)) -// fmt.Println(string(want_sitemap)) - -// fmt.Println(len(got_sitemap)) -// fmt.Println(len(want_sitemap)) - -// if !reflect.DeepEqual(got_sitemap, want_sitemap) { -// t.Errorf("The expected and generated sitemap can be found in test/layout/sitemap/") -// } -// }) -// } -// */ +/* +func TestGenerateSitemap(t *testing.T) { + t.Run("render sitemap.xml", func(t *testing.T) { + engine := engine.Engine{ + Templates: make(map[template.URL]parser.TemplateData), + TagsMap: make(map[string][]parser.TemplateData), + ErrorLogger: log.New(os.Stderr, "TEST ERROR\t", log.Ldate|log.Ltime|log.Lshortfile), + } + + t1 := parser.TemplateData{ + FilenameWithoutExtension: "index", + Frontmatter: parser.Frontmatter{ + Date: "2024-02-23", + }, + } + + t2 := parser.TemplateData{ + FilenameWithoutExtension: "about", + Frontmatter: parser.Frontmatter{ + Date: "2024-02-23", + }, + } + + t3 := parser.TemplateData{ + FilenameWithoutExtension: "research", + Frontmatter: parser.Frontmatter{ + Date: "2024-02-23", + }, + } + + engine.LayoutConfig.BaseURL = "example.org" + // setting up engine + engine.Templates["index"] = t1 + engine.Templates["about"] = t2 + engine.Templates["research"] = t3 + + engine.GenerateSitemap(TestDirPath + "sitemap/got_sitemap.xml") + + got_sitemap, err := os.ReadFile(TestDirPath + "sitemap/got_sitemap.xml") + if err != nil { + t.Errorf("Error in reading the contents of got_sitemap.xml") + } + + want_sitemap, err := os.ReadFile(TestDirPath + "sitemap/want_sitemap.xml") + if err != nil { + t.Errorf("Error in reading the contents of _sitemap.xml") + } + + // Remove spaces and whitespace characters + + // got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), " ", "")) + // want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), " ", "")) + // // Replace all tabs + // got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), "\t", "")) + // want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), "\t", "")) + + // got_sitemap = []byte(strings.ReplaceAll(string(got_sitemap), "\n", "")) + // want_sitemap = []byte(strings.ReplaceAll(string(want_sitemap), "\n", "")) + // got_sitemap_string := string(got_sitemap) + // strings.TrimFunc(got_sitemap_string, func(r rune) bool { + + // }) + + if strings.Compare(string(got_sitemap), string(want_sitemap)) != 0 { + t.Errorf("The expected and generated sitemap can be found in test/layout/sitemap/") + } + }) +} +*/ diff --git a/pkg/engine/engine_integration_test.go b/pkg/engine/engine_integration_test.go index 22c7b84..c427924 100644 --- a/pkg/engine/engine_integration_test.go +++ b/pkg/engine/engine_integration_test.go @@ -31,18 +31,18 @@ func TestRenderUserDefinedPages(t *testing.T) { t.Run("render a set of user defined pages", func(t *testing.T) { - templ, err := template.ParseFiles(TestDirPath + "engine/render_user_defined/template_input.html") + templ, err := template.ParseFiles(TestDirPath + "render_user_defined/template_input.html") if err != nil { t.Errorf("%v", err) } - engine.RenderUserDefinedPages(TestDirPath+"engine/render_user_defined/", templ) + engine.RenderUserDefinedPages(TestDirPath+"render_user_defined/", templ) - want_index_file, err := os.ReadFile(TestDirPath + "engine/render_user_defined/want_index.html") + want_index_file, err := os.ReadFile(TestDirPath + "render_user_defined/want_index.html") if err != nil { t.Errorf("%v", err) } - got_index_file, err := os.ReadFile(TestDirPath + "engine/render_user_defined/rendered/index.html") + got_index_file, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/index.html") if err != nil { t.Errorf("%v", err) } @@ -51,12 +51,12 @@ func TestRenderUserDefinedPages(t *testing.T) { t.Errorf("The expected and generated index.html can be found in test/engine/render_user_defined/rendered/") } - want_post_hello, err := os.ReadFile(TestDirPath + "engine/render_user_defined/want_post_hello.html") + want_post_hello, err := os.ReadFile(TestDirPath + "render_user_defined/want_post_hello.html") if err != nil { t.Errorf("%v", err) } - got_post_hello, err := os.ReadFile(TestDirPath + "engine/render_user_defined/rendered/posts/hello.html") + got_post_hello, err := os.ReadFile(TestDirPath + "render_user_defined/rendered/posts/hello.html") if err != nil { t.Errorf("%v", err) } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 396d3d5..a20bfb5 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -11,7 +11,7 @@ import ( "github.com/acmpesuecc/anna/pkg/parser" ) -const TestDirPath = "../../test/" +const TestDirPath = "../../test/engine/" func TestRenderPage(t *testing.T) { t.Run("render a single page while creating a new directory", func(t *testing.T) { @@ -41,19 +41,19 @@ func TestRenderPage(t *testing.T) { }, } - templ, err := template.ParseFiles(TestDirPath + "engine/render_page/template_input.html") + templ, err := template.ParseFiles(TestDirPath + "render_page/template_input.html") if err != nil { t.Errorf("%v", err) } engine.RenderPage(TestDirPath+"engine/render_page/", "posts/got.md", page, templ, "page") - got_file, err := os.ReadFile(TestDirPath + "engine/render_page/rendered/posts/got.html") + got_file, err := os.ReadFile(TestDirPath + "render_page/rendered/posts/got.html") if err != nil { t.Errorf("%v", err) } - want_file, err := os.ReadFile(TestDirPath + "engine/render_page/want.html") + want_file, err := os.ReadFile(TestDirPath + "render_page/want.html") if err != nil { t.Errorf("%v", err) } diff --git a/pkg/engine/user_engine.go b/pkg/engine/user_engine.go index 1eec286..4415ce1 100644 --- a/pkg/engine/user_engine.go +++ b/pkg/engine/user_engine.go @@ -4,6 +4,7 @@ import ( "bytes" "html/template" "os" + "runtime" "strings" "sync" @@ -40,33 +41,37 @@ func (e *Engine) RenderEngineGeneratedFiles(fileOutPath string, templ *template. } func (e *Engine) RenderUserDefinedPages(fileOutPath string, templ *template.Template) { + numCPU := runtime.NumCPU() + numTemplates := len(e.Templates) + concurrency := numCPU * 2 // Adjust the concurrency factor based on system hardware resources - var wg sync.WaitGroup - concurrency := 3 - // Each goroutine handles 3 files at a time - semaphore := make(chan struct{}, concurrency) + if numTemplates < concurrency { + concurrency = numTemplates + } - templateURLs := make([]string, 0, len(e.Templates)) + templateURLs := make([]string, 0, numTemplates) for templateURL := range e.Templates { templateURLs = append(templateURLs, string(templateURL)) } + var wg sync.WaitGroup + semaphore := make(chan struct{}, concurrency) + for _, templateURL := range templateURLs { wg.Add(1) - // Acquire semaphore semaphore <- struct{}{} - go func(file string) { + go func(templateURL string) { defer func() { - // Release semaphore <-semaphore wg.Done() }() templData := e.Templates[template.URL(templateURL)] - fileInPath, _ := strings.CutSuffix(string(templData.CompleteURL), ".html") + fileInPath := strings.TrimSuffix(string(templData.CompleteURL), ".html") e.RenderPage(fileOutPath, template.URL(fileInPath), templData, templ, "page") }(templateURL) } + wg.Wait() } diff --git a/pkg/engine/user_engine_test.go b/pkg/engine/user_engine_test.go index 28b5655..304d58a 100644 --- a/pkg/engine/user_engine_test.go +++ b/pkg/engine/user_engine_test.go @@ -48,19 +48,19 @@ func TestRenderEngineGeneratedFiles(t *testing.T) { } t.Run("test rendering of post.html", func(t *testing.T) { - templ, err := template.ParseFiles(TestDirPath + "engine/render_engine_generated/posts_template.html") + templ, err := template.ParseFiles(TestDirPath + "render_engine_generated/posts_template.html") if err != nil { t.Errorf("%v", err) } - engine.RenderEngineGeneratedFiles(TestDirPath+"engine/render_engine_generated/", templ) + engine.RenderEngineGeneratedFiles(TestDirPath+"render_engine_generated/", templ) - want_posts_file, err := os.ReadFile(TestDirPath + "engine/render_engine_generated/want_posts.html") + want_posts_file, err := os.ReadFile(TestDirPath + "render_engine_generated/want_posts.html") if err != nil { t.Errorf("%v", err) } - got_posts_file, err := os.ReadFile(TestDirPath + "engine/render_engine_generated/rendered/posts.html") + got_posts_file, err := os.ReadFile(TestDirPath + "render_engine_generated/rendered/posts.html") if err != nil { t.Errorf("%v", err) } diff --git a/search.go.temp b/search.go.temp new file mode 100644 index 0000000..a686f40 --- /dev/null +++ b/search.go.temp @@ -0,0 +1,41 @@ +package main + +import ( + "github.com/blevesearch/bleve" +) + +type Content struct { + Title string + Content string +} + +func indexSiteContent(contents []Content) (bleve.Index, error) { + // create a mapping + mapping := bleve.NewIndexMapping() + + index, err := bleve.New("example.bleve", mapping) + if err != nil { + return nil, err + } + + for _, content := range contents { + err = index.Index(content.Title, content) + if err != nil { + return nil, err + } + } + + return index, nil +} + +func searchContent(index bleve.Index, query string) (*bleve.SearchResult, error) { + query = bleve.NewMatchQuery(query) + search := bleve.NewSearchRequest(query) + + searchResults, err := index.Search(search) + if err != nil { + return nil, err + } + + return searchResults, nil +} diff --git a/site/content/posts/test_0.md b/site/content/posts/test_0.md deleted file mode 100644 index f117211..0000000 --- a/site/content/posts/test_0.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Chronological Test 2 -date: 2023-01-02 -draft: true -type: post -description: This is a test description -tags: - - test-post ---- diff --git a/site/content/posts/test_date.md b/site/content/posts/test_date.md deleted file mode 100644 index 7e163eb..0000000 --- a/site/content/posts/test_date.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Chronological Test -date: 2024-01-01 -draft: true -type: post ---- diff --git a/site/content/posts/test_nofrontmatter.md b/site/content/posts/test_nofrontmatter.md deleted file mode 100644 index eaca10c..0000000 --- a/site/content/posts/test_nofrontmatter.md +++ /dev/null @@ -1 +0,0 @@ -This is a file without frontmatter diff --git a/test/engine/engine/render_page/rendered/posts/got.html b/test/engine/engine/render_page/rendered/posts/got.html new file mode 100644 index 0000000..6cfcd99 --- /dev/null +++ b/test/engine/engine/render_page/rendered/posts/got.html @@ -0,0 +1,18 @@ + + + + +
+ +
+blog +
+ +
+thoughts +
+ +
+

Hello World

+ + diff --git a/test/engine/render_user_defined/rendered/.html b/test/engine/render_user_defined/rendered/.html index 3dd0104..c3dcf98 100644 --- a/test/engine/render_user_defined/rendered/.html +++ b/test/engine/render_user_defined/rendered/.html @@ -8,4 +8,3 @@

Index Page

- diff --git a/test/engine/sitemap/got_sitemap.xml b/test/engine/sitemap/got_sitemap.xml new file mode 100644 index 0000000..03e81a4 --- /dev/null +++ b/test/engine/sitemap/got_sitemap.xml @@ -0,0 +1,15 @@ + + + + example.org/about.html + 2024-02-23 + + + example.org/index.html + 2024-02-23 + + + example.org/research.html + 2024-02-23 + + diff --git a/test/engine/sitemap/want_sitemap.xml b/test/engine/sitemap/want_sitemap.xml new file mode 100644 index 0000000..5578525 --- /dev/null +++ b/test/engine/sitemap/want_sitemap.xml @@ -0,0 +1,15 @@ + + + + example.org/about.html + 2024-02-23 + + + example.org/index.html + 2024-02-23 + + + example.org/research.html + 2024-02-23 + + diff --git a/test/engine/want_sitemap.xml b/test/engine/want_sitemap.xml new file mode 100644 index 0000000..5578525 --- /dev/null +++ b/test/engine/want_sitemap.xml @@ -0,0 +1,15 @@ + + + + example.org/about.html + 2024-02-23 + + + example.org/index.html + 2024-02-23 + + + example.org/research.html + 2024-02-23 + + diff --git a/test/parser/layout/sitemap/got_sitemap.xml b/test/parser/layout/sitemap/got_sitemap.xml deleted file mode 100644 index 2a52a7b..0000000 --- a/test/parser/layout/sitemap/got_sitemap.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - https://ssg-test-org.github.io/about.html - 2023-01-02 - - - https://ssg-test-org.github.io/research.html - 2024-01-01 - - - https://ssg-test-org.github.io/index.html - 2024-02-23 - - diff --git a/test/parser/layout/sitemap/want_sitemap.xml b/test/parser/layout/sitemap/want_sitemap.xml deleted file mode 100644 index c308690..0000000 --- a/test/parser/layout/sitemap/want_sitemap.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - https://ssg-test-org.github.io/index.html - 2024-02-23 - - - https://ssg-test-org.github.io/about.html - 2023-01-02 - - - https://ssg-test-org.github.io/research.html - 2024-01-01 - -