362 lines
10 KiB
Go
362 lines
10 KiB
Go
|
|
// This package exports 2 Seekia static sites into two folders: ExportedWebsite_IPFS and ExportedWebsite_Server
|
|
|
|
// ExportedWebsite_IPFS contains the website that is deployed to the Seekia.eth IPFS domain.
|
|
// ExportedWebsite_Server contains the website that is deployed to Seekia's clearnet (.net) and Tor (.onion) domains.
|
|
|
|
package main
|
|
|
|
import "SeekiaWebsite/translation"
|
|
|
|
import "bytes"
|
|
import "errors"
|
|
import "log"
|
|
import "os"
|
|
import "strings"
|
|
import "text/template"
|
|
|
|
import goFilepath "path/filepath"
|
|
|
|
// This is the current Seekia release .tgz filename
|
|
const currentReleaseFilename = "Seekia-v0.50.tgz"
|
|
|
|
// This is the IPFS base32 CID for the current Seekia release .tgz file
|
|
const currentReleaseIpfsCID = "bafybeie6nkmucrvo3i7bonmlf77dlna65tjogsq5zmrcpqke7pvdkiumhy"
|
|
|
|
func main(){
|
|
|
|
//Inputs:
|
|
// -string: The folderpath to export the website to
|
|
// -bool: Use this to control if we are exporting the Seekia.eth IPFS site or not
|
|
exportWebsite := func(websiteFolderpath string, siteIsIPFS bool)error{
|
|
|
|
err := os.RemoveAll(websiteFolderpath)
|
|
if (err != nil){ return err }
|
|
|
|
err = os.Mkdir(websiteFolderpath, os.ModePerm)
|
|
if (err != nil) { return err }
|
|
|
|
//TODO: Add more languages
|
|
//allLanguageCodesList := []string{"en", "es"}
|
|
|
|
allLanguageCodesList := []string{"en"}
|
|
|
|
// 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("assets")
|
|
if (err != nil) { return err }
|
|
|
|
err = copyFolder("memos")
|
|
if (err != nil) { return err }
|
|
|
|
err = copyFolder("signatures")
|
|
if (err != nil) { return err }
|
|
|
|
if (siteIsIPFS == false){
|
|
|
|
// For our IPFS site, we are using an IPFS link for the download
|
|
// For our non-IPFS site, we include the link on the same hosted site
|
|
// This is because when viewing an IPFS site, the user's browser downloads the entire website (usually?)
|
|
// This would take too long to download if we included the release with the site (several megabytes)
|
|
|
|
releaseFilepath := goFilepath.Join("./resources", "release", currentReleaseFilename)
|
|
|
|
releaseFileBytes, err := os.ReadFile(releaseFilepath)
|
|
if (err != nil) {
|
|
fileDoesNotExist := os.IsNotExist(err)
|
|
if (fileDoesNotExist == false){
|
|
return err
|
|
}
|
|
|
|
return errors.New("You must place the Seekia release .tgz file into the ./resources/release folder before exporting the website. This can be an empty file with the correct filename if you want. Error: " + err.Error())
|
|
}
|
|
|
|
releaseFileString := string(releaseFileBytes)
|
|
|
|
|
|
destinationFolderPath := goFilepath.Join(websiteFolderpath, "release")
|
|
|
|
err = os.Mkdir(destinationFolderPath, os.ModePerm)
|
|
if (err != nil) { return err }
|
|
|
|
destinationFilepath := goFilepath.Join(destinationFolderPath, currentReleaseFilename)
|
|
|
|
err = createFile(destinationFilepath, releaseFileString)
|
|
if (err != nil) { return err }
|
|
}
|
|
|
|
getTemplateDefinitionsMap := func(inputLanguageCode string)(map[string]string, error){
|
|
|
|
translationsMap, err := translation.GetTranslationsMap(inputLanguageCode)
|
|
if (err != nil){ return nil, err }
|
|
|
|
templateDefinitionsMap := translationsMap
|
|
|
|
// Now we add code snippets to the map
|
|
|
|
fileList, err := os.ReadDir("./resources/codeSnippets")
|
|
if (err != nil) { return nil, err }
|
|
|
|
for _, fileObject := range fileList{
|
|
|
|
fileName := fileObject.Name()
|
|
filePath := goFilepath.Join("./resources/codeSnippets/", fileName)
|
|
|
|
fileBytes, err := os.ReadFile(filePath)
|
|
if (err != nil) { return nil, err }
|
|
|
|
snippetString := string(fileBytes)
|
|
|
|
snippetName := strings.TrimSuffix(fileName, ".html")
|
|
|
|
codeSnippetKey := "CodeSnippet_" + snippetName
|
|
|
|
_, exists := templateDefinitionsMap[codeSnippetKey]
|
|
if (exists == true){
|
|
return nil, errors.New("Cannot export website: conflict found between translationsMap and codeSnippets")
|
|
}
|
|
|
|
templateDefinitionsMap[codeSnippetKey] = snippetString
|
|
}
|
|
|
|
// LanguageURLBase is empty for all files except /index.html
|
|
templateDefinitionsMap["LanguageURLBase"] = ""
|
|
|
|
return templateDefinitionsMap, nil
|
|
}
|
|
|
|
// We use this function to parse the .html files to replace the internal template values with actual values
|
|
// For example, {{.BeRaceAware}} will be replaced with "Be Race Aware", or the equivalent translated text in the website's current language version
|
|
// 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/replace any language fields
|
|
// 2. Then parse again to replace any language fields and instances of {{.LinkURLBase}} 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
|
|
}
|
|
|
|
{
|
|
// First we create /index.html
|
|
// Using a language code is optional for the main index of the site
|
|
// It is always in English
|
|
// For example, Seekia.eth/index.html
|
|
|
|
templateObject, err := template.ParseFiles("./resources/pages/index.html")
|
|
if (err != nil){ return err }
|
|
|
|
templateDefinitionsMap, err := getTemplateDefinitionsMap("en")
|
|
if (err != nil) { return err }
|
|
|
|
templateDefinitionsMap["BaseURL"] = "."
|
|
templateDefinitionsMap["LanguageURLBase"] = "en/"
|
|
|
|
indexPageString, err := parseTemplateObjectToStringTwice(templateObject, templateDefinitionsMap)
|
|
if (err != nil) { return err }
|
|
|
|
indexFilepath := goFilepath.Join(websiteFolderpath, "index.html")
|
|
|
|
err = createFile(indexFilepath, indexPageString)
|
|
if (err != nil) { return err }
|
|
}
|
|
|
|
// Now we create the rest of the pages for each language
|
|
// These pages exist behind a language code
|
|
// For example:
|
|
// seekia.eth/en/index.html
|
|
// seekia.eth/es/download.html
|
|
|
|
getDownloadSeekiaLink := func()string{
|
|
|
|
if (siteIsIPFS == false){
|
|
result := "../release/" + currentReleaseFilename
|
|
|
|
return result
|
|
}
|
|
|
|
// The IPFS site does not contain the Seekia release .tgz file
|
|
// This is because users (sometimes?) download the entire IPFS site when viewing it,
|
|
// so downloading many megabytes would take too long
|
|
|
|
result := "https://ipfs.io/ipfs/" + currentReleaseIpfsCID
|
|
|
|
return result
|
|
}
|
|
|
|
downloadSeekiaLink := getDownloadSeekiaLink()
|
|
|
|
for _, languageCode := range allLanguageCodesList{
|
|
|
|
// We create the language subfolder
|
|
|
|
languageSubfolderPath := goFilepath.Join(websiteFolderpath, languageCode)
|
|
|
|
err = os.Mkdir(languageSubfolderPath, os.ModePerm)
|
|
if (err != nil) { return err }
|
|
|
|
|
|
templateDefinitionsMap, err := getTemplateDefinitionsMap(languageCode)
|
|
if (err != nil) { return err }
|
|
|
|
templateDefinitionsMap["BaseURL"] = ".."
|
|
|
|
templateDefinitionsMap["DownloadSeekiaLink"] = downloadSeekiaLink
|
|
|
|
createPage := func(pageFilename string)error{
|
|
|
|
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(languageSubfolderPath, pageFilename)
|
|
|
|
err = createFile(pageFilepath, pageString)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
err = createPage("index.html")
|
|
if (err != nil){ return err }
|
|
|
|
//TODO: Add the Choose Language page and Choose Language banner bar
|
|
|
|
// err := createPage("chooseLanguage.html")
|
|
// if (err != nil){ return err }
|
|
|
|
err = createPage("download.html")
|
|
if (err != nil){ return err }
|
|
|
|
err = createPage("about.html")
|
|
if (err != nil){ return err }
|
|
|
|
err = createPage("contribute.html")
|
|
if (err != nil){ return err }
|
|
|
|
err = createPage("archive.html")
|
|
if (err != nil){ return err }
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err := exportWebsite("./ExportedWebsite_IPFS/", true)
|
|
if (err != nil){
|
|
log.Println(err)
|
|
return
|
|
}
|
|
|
|
err = exportWebsite("./ExportedWebsite_Server/", false)
|
|
if (err != nil){
|
|
log.Println(err)
|
|
return
|
|
}
|
|
|
|
log.Println("Seekia's websites have 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
|
|
}
|
|
|