|
|
@@ -0,0 +1,141 @@ |
|
|
|
package main |
|
|
|
|
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
"io/ioutil" |
|
|
|
"time" |
|
|
|
"strconv" |
|
|
|
"text/template" |
|
|
|
"os" |
|
|
|
"bufio" |
|
|
|
"regexp" |
|
|
|
"flag" |
|
|
|
"encoding/json" |
|
|
|
) |
|
|
|
|
|
|
|
const entriesPath = "./entries/" |
|
|
|
const templatesPath = "./templates/" |
|
|
|
const outputPath = "./html/" |
|
|
|
const defaultTemplateFile = "log" |
|
|
|
|
|
|
|
type Entry struct { |
|
|
|
Date string |
|
|
|
Body []byte |
|
|
|
} |
|
|
|
|
|
|
|
func loadEntry(rawDate string) (*Entry, error) { |
|
|
|
filename := entriesPath + rawDate |
|
|
|
body, err := ioutil.ReadFile(filename) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
|
|
|
|
// Get raw date parts for formatting |
|
|
|
year := rawDate[:4] |
|
|
|
month, moErr := strconv.Atoi(rawDate[4:6]) |
|
|
|
if moErr != nil { |
|
|
|
return nil, moErr |
|
|
|
} |
|
|
|
date, dateErr := strconv.Atoi(rawDate[6:8]) |
|
|
|
if dateErr != nil { |
|
|
|
return nil, dateErr |
|
|
|
} |
|
|
|
|
|
|
|
formattedDate := fmt.Sprintf("%d %s %s", date, time.Month(month).String(), year) |
|
|
|
|
|
|
|
return &Entry{Date: formattedDate, Body: body}, nil |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
|
fmt.Println() |
|
|
|
fmt.Println(" ~log generator v1.0") |
|
|
|
fmt.Println() |
|
|
|
|
|
|
|
// Get any arguments |
|
|
|
templateFilePtr := flag.String("template", defaultTemplateFile, "Tildelog template file (defined name).") |
|
|
|
flag.Parse() |
|
|
|
|
|
|
|
c := configuration() |
|
|
|
if c = nil { |
|
|
|
c := configure() |
|
|
|
} |
|
|
|
|
|
|
|
if c != nil { |
|
|
|
templateFilePtr = c.TemplateFile |
|
|
|
} |
|
|
|
|
|
|
|
entryFiles := getEntries() |
|
|
|
entries := make([]Entry, len(*entryFiles)) |
|
|
|
i := 0 |
|
|
|
for _, file := range *entryFiles { |
|
|
|
entry, err := loadEntry(file) |
|
|
|
if err != nil { |
|
|
|
fmt.Printf("Error, skipping entry %s: %s\n", file, err) |
|
|
|
continue |
|
|
|
} |
|
|
|
fmt.Printf("Adding entry %s...\n", file) |
|
|
|
entries[i] = *entry |
|
|
|
i++ |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Printf("Using template %s...\n", *templateFilePtr) |
|
|
|
|
|
|
|
generateLog(entries, *templateFilePtr) |
|
|
|
|
|
|
|
fmt.Printf("Finished! Saved to %slog.html\n", outputPath) |
|
|
|
} |
|
|
|
|
|
|
|
type Config struct { |
|
|
|
EntriesPath string |
|
|
|
TemplateFile string |
|
|
|
} |
|
|
|
|
|
|
|
func configuration() *Config { |
|
|
|
file, err := os.Open(os.Getenv("HOME") + "/.tildelog") |
|
|
|
if err != nil { |
|
|
|
return nil |
|
|
|
} |
|
|
|
d := json.NewDecoder(file) |
|
|
|
c := Config{} |
|
|
|
err = d.Decode(&c) |
|
|
|
if err != nil { |
|
|
|
fmt.Printf("Couldn't decode configuration: %s\n", err) |
|
|
|
} |
|
|
|
return &c |
|
|
|
} |
|
|
|
|
|
|
|
var validFileFormat = regexp.MustCompile("^[0-9]{8}$") |
|
|
|
|
|
|
|
func getEntries() *[]string { |
|
|
|
files, _ := ioutil.ReadDir(entriesPath) |
|
|
|
fileList := make([]string, len(files)) |
|
|
|
fileCount := 0 |
|
|
|
// Traverse file list in reverse, i.e. newest to oldest |
|
|
|
for i := len(files)-1; i >= 0; i-- { |
|
|
|
file := files[i] |
|
|
|
if validFileFormat.Match([]byte(file.Name())) { |
|
|
|
fileList[fileCount] = file.Name() |
|
|
|
fileCount++ |
|
|
|
} |
|
|
|
} |
|
|
|
fileList = fileList[:fileCount] |
|
|
|
return &fileList |
|
|
|
} |
|
|
|
|
|
|
|
func generateLog(entries []Entry, templateFile string) { |
|
|
|
file, err := os.Create(outputPath + "log.html") |
|
|
|
if err != nil { |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
|
|
|
|
defer file.Close() |
|
|
|
|
|
|
|
writer := bufio.NewWriter(file) |
|
|
|
template, err := template.ParseGlob(templatesPath + "*.html") |
|
|
|
if err != nil { |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
template.ExecuteTemplate(writer, templateFile, entries) |
|
|
|
writer.Flush() |
|
|
|
} |
|
|
|
|