163 lines
3.6 KiB
Go
163 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type IndexData struct {
|
|
Dir string
|
|
Files []FileEntry
|
|
RootURL string
|
|
}
|
|
|
|
type FileEntry struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Date string `json:"date,omitempty"`
|
|
Source string `json:"source,omitempty"`
|
|
Topic string `json:"topic,omitempty"`
|
|
Gradeband *string `json:"gradeband,omitempty"`
|
|
}
|
|
|
|
func parseFilename(name string) (date, source, topic string, gradeband *string) {
|
|
// Remove extension
|
|
nameWithoutExt := strings.TrimSuffix(name, filepath.Ext(name))
|
|
|
|
// Split by " - "
|
|
parts := strings.Split(nameWithoutExt, " - ")
|
|
|
|
if len(parts) < 2 {
|
|
// Can't parse, return empty
|
|
return
|
|
}
|
|
|
|
date = parts[0]
|
|
source = parts[1]
|
|
|
|
if len(parts) == 2 {
|
|
// No topic or gradeband
|
|
return
|
|
}
|
|
|
|
if len(parts) == 3 {
|
|
// Just topic, no gradeband
|
|
topic = parts[2]
|
|
return
|
|
}
|
|
|
|
// 4+ parts: third part is gradeband, remaining parts are topic
|
|
gb := parts[2]
|
|
gradeband = &gb
|
|
topic = strings.Join(parts[3:], " - ")
|
|
|
|
return
|
|
}
|
|
|
|
func generateIndex(dir string, rootURL string) error {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read directory: %w", err)
|
|
}
|
|
|
|
// Normalize root URL (remove trailing slash)
|
|
rootURL = strings.TrimSuffix(rootURL, "/")
|
|
|
|
var fileNames []string
|
|
for _, entry := range entries {
|
|
name := entry.Name()
|
|
ext := filepath.Ext(name)
|
|
// Skip the index files, build files, and hidden files
|
|
if name != "index.html" && name != "index.json" &&
|
|
ext != ".go" && ext != ".tmpl" &&
|
|
!filepath.HasPrefix(name, ".") {
|
|
fileNames = append(fileNames, name)
|
|
}
|
|
}
|
|
sort.Strings(fileNames)
|
|
|
|
// Build file entries with absolute URLs
|
|
var files []FileEntry
|
|
dirName := filepath.Base(dir)
|
|
for _, name := range fileNames {
|
|
url := fmt.Sprintf("%s/%s/%s", rootURL, dirName, name)
|
|
date, source, topic, gradeband := parseFilename(name)
|
|
files = append(files, FileEntry{
|
|
Name: name,
|
|
URL: url,
|
|
Date: date,
|
|
Source: source,
|
|
Topic: topic,
|
|
Gradeband: gradeband,
|
|
})
|
|
}
|
|
|
|
templatePath := "helios/index.html.tmpl"
|
|
tmpl, err := template.ParseFiles(templatePath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse template: %w", err)
|
|
}
|
|
|
|
indexPath := filepath.Join(dir, "index.html")
|
|
f, err := os.Create(indexPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create index.html: %w", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
data := IndexData{
|
|
Dir: dirName,
|
|
Files: files,
|
|
RootURL: rootURL,
|
|
}
|
|
|
|
if err := tmpl.Execute(f, data); err != nil {
|
|
return fmt.Errorf("failed to execute template: %w", err)
|
|
}
|
|
log.Println(indexPath)
|
|
|
|
// Generate index.json
|
|
jsonPath := filepath.Join(dir, "index.json")
|
|
jsonFile, err := os.Create(jsonPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create index.json: %w", err)
|
|
}
|
|
defer jsonFile.Close()
|
|
|
|
encoder := json.NewEncoder(jsonFile)
|
|
encoder.SetIndent("", " ")
|
|
encoder.SetEscapeHTML(false)
|
|
if err := encoder.Encode(files); err != nil {
|
|
return fmt.Errorf("failed to encode JSON: %w", err)
|
|
}
|
|
log.Println(jsonPath)
|
|
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
rootURL := flag.String("root", "https://s.fc.run", "Root domain URL for absolute links")
|
|
flag.Parse()
|
|
|
|
dirs := flag.Args()
|
|
if len(dirs) == 0 {
|
|
fmt.Println("Usage: generate-index [-root <url>] <directory> [<directory>...]")
|
|
fmt.Println(" -root string")
|
|
fmt.Println(" Root domain URL for absolute links (default \"https://s.fc.run\")")
|
|
os.Exit(1)
|
|
}
|
|
|
|
for _, dir := range dirs {
|
|
if err := generateIndex(dir, *rootURL); err != nil {
|
|
log.Fatalf("Error processing %s: %v", dir, err)
|
|
}
|
|
}
|
|
}
|