// This package exports Simon Sarasova's website into the ExportedWebsite folder // The website is deployed to the SimonSarasova.eth IPFS domain. package main import "bytes" import "errors" import "log" import "os" import "strings" import "text/template" import goFilepath "path/filepath" func main(){ exportWebsite := func()error{ websiteFolderpath := "./ExportedWebsite" err := os.RemoveAll(websiteFolderpath) if (err != nil){ return err } err = os.Mkdir(websiteFolderpath, os.ModePerm) if (err != nil) { return err } // We create the style.css file cssPageBytes, err := os.ReadFile("./resources/style.css") if (err != nil) { return err } cssPageString := string(cssPageBytes) cssFilepath := goFilepath.Join(websiteFolderpath, "style.css") err = createFile(cssFilepath, cssPageString) if (err != nil) { return err } // We copy various folders copyFolder := func(folderName string)error{ sourceFolderPath := goFilepath.Join("./resources/", folderName) destinationFolderPath := goFilepath.Join(websiteFolderpath, folderName) err := copyFolderRecursively(sourceFolderPath, destinationFolderPath) if (err != nil) { return err } return nil } err = copyFolder("images") if (err != nil) { return err } err = copyFolder("memos") if (err != nil) { return err } templateDefinitionsMap := make(map[string]string) // We add code snippets to the templateDefinitionsMap fileList, err := os.ReadDir("./resources/codeSnippets") if (err != nil) { return err } for _, fileObject := range fileList{ fileName := fileObject.Name() filePath := goFilepath.Join("./resources/codeSnippets/", fileName) fileBytes, err := os.ReadFile(filePath) if (err != nil) { return err } snippetString := string(fileBytes) snippetName := strings.TrimSuffix(fileName, ".html") codeSnippetKey := "CodeSnippet_" + snippetName _, exists := templateDefinitionsMap[codeSnippetKey] if (exists == true){ return errors.New("Cannot export website: name conflict found within codeSnippets") } templateDefinitionsMap[codeSnippetKey] = snippetString } // We use this function to parse the .html files to replace the internal template values with actual values // For example, {{.BaseURL}} will be replaced with either "." or ".." // We have to parse twice for the web pages. // Code snippets have fields that need to be parsed // So to process the code snippets, we have to: // 1. First parse the html page files to add the code snippets // 2. Then parse again to replace any instances of fields such as {{.BaseURL}} within the code snippets we just added // parseTemplateObjectToStringTwice := func(templateObject *template.Template, definitionsMap map[string]string)(string, error){ parseTemplateObjectToString := func(inputTemplateObject *template.Template)(string, error){ inputTemplateObject.Option("missingkey=error") parsedTemplateBuffer := new(bytes.Buffer) err = inputTemplateObject.Execute(parsedTemplateBuffer, definitionsMap) if (err != nil){ return "", err } parsedTemplateString := parsedTemplateBuffer.String() return parsedTemplateString, nil } parsedTemplateString_Round1, err := parseTemplateObjectToString(templateObject) if (err != nil) { return "", err } templateObject2 := template.New("Round2") _, err = templateObject2.Parse(parsedTemplateString_Round1) if (err != nil) { return "", err } parsedTemplateString_Round2, err := parseTemplateObjectToString(templateObject2) if (err != nil) { return "", err } return parsedTemplateString_Round2, nil } templateDefinitionsMap["BaseURL"] = "." pageFilenamesList := []string{ "index.html", "blog.html", "blog-archive.html", "contact.html", "donate.html", "keys.html", "links.html", "proof.html", "posts.html", "posts-archive.html", } for _, pageFilename := range pageFilenamesList{ pageTemplateFilepath := goFilepath.Join("./resources/pages/", pageFilename) pageTemplateObject, err := template.ParseFiles(pageTemplateFilepath) if (err != nil){ return err } pageString, err := parseTemplateObjectToStringTwice(pageTemplateObject, templateDefinitionsMap) if (err != nil) { return err } pageFilepath := goFilepath.Join(websiteFolderpath, pageFilename) err = createFile(pageFilepath, pageString) if (err != nil) { return err } } // Now we create the blog post pages blogPostsFolderpath := goFilepath.Join(websiteFolderpath, "blog") err = os.Mkdir(blogPostsFolderpath, os.ModePerm) if (err != nil) { return err } templateDefinitionsMap["BaseURL"] = ".." blogPostPageFilenamesList := []string{ "hello-world.html", "why-race-extinction-matters.html", "beauty-extinction-is-unlikely.html", "de-emphasizing-race.html", } for _, pageFilename := range blogPostPageFilenamesList{ pageTemplateFilepath := goFilepath.Join("./resources/pages/blog", pageFilename) pageTemplateObject, err := template.ParseFiles(pageTemplateFilepath) if (err != nil){ return err } pageString, err := parseTemplateObjectToStringTwice(pageTemplateObject, templateDefinitionsMap) if (err != nil) { return err } pageFilepath := goFilepath.Join(blogPostsFolderpath, pageFilename) err = createFile(pageFilepath, pageString) if (err != nil) { return err } } return nil } err := exportWebsite() if (err != nil){ log.Println("Failed to export website: " + err.Error()) return } log.Println("Simon Sarasova's website has been exported!") } // This function will copy a folder and its subfolders func copyFolderRecursively(sourceFolderPath string, destinationFolderPath string)error{ err := os.Mkdir(destinationFolderPath, os.ModePerm) if (err != nil) { return err } filesystemPathsList, err := os.ReadDir(sourceFolderPath) if (err != nil) { return err } for _, filesystemObject := range filesystemPathsList{ pathName := filesystemObject.Name() sourcePathName := goFilepath.Join(sourceFolderPath, pathName) destinationPathName := goFilepath.Join(destinationFolderPath, pathName) isDirectory := filesystemObject.IsDir() if (isDirectory == true){ err := copyFolderRecursively(sourcePathName, destinationPathName) if (err != nil) { return err } } else { fileBytes, err := os.ReadFile(sourcePathName) if (err != nil) { return err } fileString := string(fileBytes) err = createFile(destinationPathName, fileString) if (err != nil) { return err } } } return nil } func createFile(filePath string, fileContents string)error{ newFile, err := os.Create(filePath) _, err = newFile.WriteString(fileContents) if (err != nil) { return err } newFile.Close() return nil }