mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
refactor: Broke config/flags into a separate struct from Site.
This commit is contained in:
+2
-2
@@ -34,8 +34,8 @@ Page :: struct {
|
|||||||
// TODO: What is the lifetime of pages?
|
// TODO: What is the lifetime of pages?
|
||||||
walk_content :: proc(site: ^Site) -> []Page {
|
walk_content :: proc(site: ^Site) -> []Page {
|
||||||
content_path := site.content_dir
|
content_path := site.content_dir
|
||||||
include_drafts := site.drafts
|
include_drafts := .Drafts in site.features
|
||||||
sectionate := site.sectionate
|
sectionate := .Sections in site.features
|
||||||
|
|
||||||
allocator := site_allocator(site)
|
allocator := site_allocator(site)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ main :: proc() {
|
|||||||
pages := walk_content(&site)
|
pages := walk_content(&site)
|
||||||
render_site(pages, site)
|
render_site(pages, site)
|
||||||
|
|
||||||
if !site.watch {
|
if !(.Watch in site.features) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.sleep(5 * time.Second)
|
time.sleep(5 * time.Second)
|
||||||
|
|||||||
@@ -8,9 +8,29 @@ import "core:mem"
|
|||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
|
|
||||||
Site :: struct {
|
Site :: struct {
|
||||||
// TODO: User can still technically try to set this
|
arena: mem.Dynamic_Arena,
|
||||||
arena: mem.Dynamic_Arena `args:"hidden"`,
|
title: string,
|
||||||
|
description: string,
|
||||||
|
author: string,
|
||||||
|
base_url: string,
|
||||||
|
config_path: string,
|
||||||
|
content_dir: string,
|
||||||
|
static_dir: string,
|
||||||
|
output_dir: string,
|
||||||
|
layouts_dir: string,
|
||||||
|
params: json.Value,
|
||||||
|
features: bit_set[Feature],
|
||||||
|
}
|
||||||
|
|
||||||
|
Feature :: enum {
|
||||||
|
Sections,
|
||||||
|
Drafts,
|
||||||
|
Watch,
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags :: struct {
|
||||||
config_path: string `args:"name=config"`,
|
config_path: string `args:"name=config"`,
|
||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
@@ -21,13 +41,13 @@ Site :: struct {
|
|||||||
layouts_dir: string,
|
layouts_dir: string,
|
||||||
author: string,
|
author: string,
|
||||||
params: json.Value,
|
params: json.Value,
|
||||||
sectionate: bool,
|
sectionate: bool `args:"name=sections"`,
|
||||||
drafts: bool `args:"name=drafts"`,
|
drafts: bool `args:"name=drafts"`,
|
||||||
watch: bool,
|
watch: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
init_site :: proc(site: ^Site, args: []string) {
|
init_site :: proc(site: ^Site, args: []string) {
|
||||||
_flags: Site
|
_flags: Flags
|
||||||
mem.dynamic_arena_init(&site.arena, alignment = 64) // FIXME: This is a hack
|
mem.dynamic_arena_init(&site.arena, alignment = 64) // FIXME: This is a hack
|
||||||
alloc := site_allocator(site)
|
alloc := site_allocator(site)
|
||||||
flags.parse_or_exit(&_flags, args, .Odin, alloc)
|
flags.parse_or_exit(&_flags, args, .Odin, alloc)
|
||||||
@@ -43,13 +63,15 @@ init_site :: proc(site: ^Site, args: []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if load_site_config(site, path, alloc) {
|
cfg, cfg_ok := load_site_config(path, alloc)
|
||||||
site_merge(site, _flags)
|
if cfg_ok {
|
||||||
|
merge_flags(&cfg, _flags)
|
||||||
} else {
|
} else {
|
||||||
_flags.arena = site.arena
|
cfg = _flags
|
||||||
site^ = _flags
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
site_apply_flags(site, cfg)
|
||||||
|
|
||||||
// Determine config file's directory for relative defaults
|
// Determine config file's directory for relative defaults
|
||||||
config_dir := "./"
|
config_dir := "./"
|
||||||
if idx := strings.last_index(path, "/"); idx >= 0 {
|
if idx := strings.last_index(path, "/"); idx >= 0 {
|
||||||
@@ -76,10 +98,10 @@ init_site :: proc(site: ^Site, args: []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load_site_config :: proc(
|
load_site_config :: proc(
|
||||||
config: ^Site,
|
|
||||||
path: string,
|
path: string,
|
||||||
allocator := context.allocator,
|
allocator := context.allocator,
|
||||||
) -> (
|
) -> (
|
||||||
|
config: Flags,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
) {
|
) {
|
||||||
data, err := os.read_entire_file_from_path(path, allocator)
|
data, err := os.read_entire_file_from_path(path, allocator)
|
||||||
@@ -87,7 +109,7 @@ load_site_config :: proc(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarshal_err := json.unmarshal_string(string(data), config, allocator = allocator)
|
unmarshal_err := json.unmarshal_string(string(data), &config, allocator = allocator)
|
||||||
if unmarshal_err != nil {
|
if unmarshal_err != nil {
|
||||||
log.warnf("thor: failed to parse %s: %v", path, unmarshal_err)
|
log.warnf("thor: failed to parse %s: %v", path, unmarshal_err)
|
||||||
return
|
return
|
||||||
@@ -97,7 +119,7 @@ load_site_config :: proc(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
site_merge :: proc(config: ^Site, flags: Site) {
|
merge_flags :: proc(config: ^Flags, flags: Flags) {
|
||||||
if flags.base_url != "" {
|
if flags.base_url != "" {
|
||||||
config.base_url = flags.base_url
|
config.base_url = flags.base_url
|
||||||
}
|
}
|
||||||
@@ -116,9 +138,29 @@ site_merge :: proc(config: ^Site, flags: Site) {
|
|||||||
if flags.watch {
|
if flags.watch {
|
||||||
config.watch = true
|
config.watch = true
|
||||||
}
|
}
|
||||||
|
if flags.sectionate {
|
||||||
|
config.sectionate = true
|
||||||
|
}
|
||||||
config.config_path = flags.config_path
|
config.config_path = flags.config_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
site_apply_flags :: proc(site: ^Site, flags: Flags) {
|
||||||
|
site.title = flags.title
|
||||||
|
site.description = flags.description
|
||||||
|
site.author = flags.author
|
||||||
|
site.base_url = flags.base_url
|
||||||
|
site.config_path = flags.config_path
|
||||||
|
site.content_dir = flags.content_dir
|
||||||
|
site.static_dir = flags.static_dir
|
||||||
|
site.output_dir = flags.output_dir
|
||||||
|
site.layouts_dir = flags.layouts_dir
|
||||||
|
site.params = flags.params
|
||||||
|
|
||||||
|
if flags.sectionate {site.features += {.Sections}}
|
||||||
|
if flags.drafts {site.features += {.Drafts}}
|
||||||
|
if flags.watch {site.features += {.Watch}}
|
||||||
|
}
|
||||||
|
|
||||||
site_allocator :: proc(site: ^Site) -> mem.Allocator {
|
site_allocator :: proc(site: ^Site) -> mem.Allocator {
|
||||||
return mem.dynamic_arena_allocator(&site.arena)
|
return mem.dynamic_arena_allocator(&site.arena)
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-34
@@ -34,16 +34,15 @@ test_load_site_config :: proc(t: ^testing.T) {
|
|||||||
)
|
)
|
||||||
defer os.remove(path)
|
defer os.remove(path)
|
||||||
|
|
||||||
site: Site
|
cfg, ok := load_site_config(path, context.temp_allocator)
|
||||||
ok := load_site_config(&site, path, context.temp_allocator)
|
|
||||||
|
|
||||||
testing.expect(t, ok)
|
testing.expect(t, ok)
|
||||||
testing.expect_value(t, site.title, "Test Site")
|
testing.expect_value(t, cfg.title, "Test Site")
|
||||||
testing.expect_value(t, site.description, "Test desc")
|
testing.expect_value(t, cfg.description, "Test desc")
|
||||||
testing.expect_value(t, site.base_url, "https://example.com")
|
testing.expect_value(t, cfg.base_url, "https://example.com")
|
||||||
testing.expect_value(t, site.author, "Tester")
|
testing.expect_value(t, cfg.author, "Tester")
|
||||||
|
|
||||||
params, has_params := site.params.(json.Object)
|
params, has_params := cfg.params.(json.Object)
|
||||||
testing.expect(t, has_params)
|
testing.expect(t, has_params)
|
||||||
|
|
||||||
social_val := params["social"]
|
social_val := params["social"]
|
||||||
@@ -63,8 +62,7 @@ test_load_site_config :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_load_site_config_missing_file :: proc(t: ^testing.T) {
|
test_load_site_config_missing_file :: proc(t: ^testing.T) {
|
||||||
site: Site
|
_, ok := load_site_config("./nonexistent_thor_test.json", context.temp_allocator)
|
||||||
ok := load_site_config(&site, "./nonexistent_thor_test.json", context.temp_allocator)
|
|
||||||
testing.expect(t, !ok)
|
testing.expect(t, !ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +71,7 @@ test_load_site_config_invalid_json :: proc(t: ^testing.T) {
|
|||||||
path := write_temp_config("invalid", `{not valid json}`)
|
path := write_temp_config("invalid", `{not valid json}`)
|
||||||
defer os.remove(path)
|
defer os.remove(path)
|
||||||
|
|
||||||
site: Site
|
_, ok := load_site_config(path, context.temp_allocator)
|
||||||
ok := load_site_config(&site, path, context.temp_allocator)
|
|
||||||
testing.expect(t, !ok)
|
testing.expect(t, !ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,27 +80,26 @@ test_load_site_config_partial :: proc(t: ^testing.T) {
|
|||||||
path := write_temp_config("partial", `{"title":"Partial"}`)
|
path := write_temp_config("partial", `{"title":"Partial"}`)
|
||||||
defer os.remove(path)
|
defer os.remove(path)
|
||||||
|
|
||||||
site: Site
|
cfg, ok := load_site_config(path, context.temp_allocator)
|
||||||
ok := load_site_config(&site, path, context.temp_allocator)
|
|
||||||
|
|
||||||
testing.expect(t, ok)
|
testing.expect(t, ok)
|
||||||
testing.expect_value(t, site.title, "Partial")
|
testing.expect_value(t, cfg.title, "Partial")
|
||||||
testing.expect_value(t, site.description, "")
|
testing.expect_value(t, cfg.description, "")
|
||||||
testing.expect_value(t, site.author, "")
|
testing.expect_value(t, cfg.author, "")
|
||||||
testing.expect(t, site.params == nil)
|
testing.expect(t, cfg.params == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_site_merge_overrides :: proc(t: ^testing.T) {
|
test_site_merge_overrides :: proc(t: ^testing.T) {
|
||||||
config := Site {
|
config := Flags {
|
||||||
base_url = "https://original.com",
|
base_url = "https://original.com",
|
||||||
content_dir = "./content",
|
content_dir = "./content",
|
||||||
}
|
}
|
||||||
flags := Site {
|
flags := Flags {
|
||||||
base_url = "https://override.com",
|
base_url = "https://override.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
site_merge(&config, flags)
|
merge_flags(&config, flags)
|
||||||
|
|
||||||
testing.expect_value(t, config.base_url, "https://override.com")
|
testing.expect_value(t, config.base_url, "https://override.com")
|
||||||
testing.expect_value(t, config.content_dir, "./content")
|
testing.expect_value(t, config.content_dir, "./content")
|
||||||
@@ -111,13 +107,13 @@ test_site_merge_overrides :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_site_merge_empty_flags_keep_config :: proc(t: ^testing.T) {
|
test_site_merge_empty_flags_keep_config :: proc(t: ^testing.T) {
|
||||||
config := Site {
|
config := Flags {
|
||||||
base_url = "https://keep.com",
|
base_url = "https://keep.com",
|
||||||
content_dir = "./keep",
|
content_dir = "./keep",
|
||||||
}
|
}
|
||||||
flags := Site{}
|
flags := Flags{}
|
||||||
|
|
||||||
site_merge(&config, flags)
|
merge_flags(&config, flags)
|
||||||
|
|
||||||
testing.expect_value(t, config.base_url, "https://keep.com")
|
testing.expect_value(t, config.base_url, "https://keep.com")
|
||||||
testing.expect_value(t, config.content_dir, "./keep")
|
testing.expect_value(t, config.content_dir, "./keep")
|
||||||
@@ -125,38 +121,38 @@ test_site_merge_empty_flags_keep_config :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_site_merge_drafts_true :: proc(t: ^testing.T) {
|
test_site_merge_drafts_true :: proc(t: ^testing.T) {
|
||||||
config := Site {
|
config := Flags {
|
||||||
drafts = false,
|
drafts = false,
|
||||||
}
|
}
|
||||||
flags := Site {
|
flags := Flags {
|
||||||
drafts = true,
|
drafts = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
site_merge(&config, flags)
|
merge_flags(&config, flags)
|
||||||
testing.expect(t, config.drafts)
|
testing.expect(t, config.drafts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_site_merge_drafts_false_preserves :: proc(t: ^testing.T) {
|
test_site_merge_drafts_false_preserves :: proc(t: ^testing.T) {
|
||||||
config := Site {
|
config := Flags {
|
||||||
drafts = false,
|
drafts = false,
|
||||||
}
|
}
|
||||||
flags := Site {
|
flags := Flags {
|
||||||
drafts = false,
|
drafts = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
site_merge(&config, flags)
|
merge_flags(&config, flags)
|
||||||
testing.expect(t, !config.drafts)
|
testing.expect(t, !config.drafts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_site_merge_config_path :: proc(t: ^testing.T) {
|
test_site_merge_config_path :: proc(t: ^testing.T) {
|
||||||
config := Site{}
|
config := Flags{}
|
||||||
flags := Site {
|
flags := Flags {
|
||||||
config_path = "./custom/thor.json",
|
config_path = "./custom/thor.json",
|
||||||
}
|
}
|
||||||
|
|
||||||
site_merge(&config, flags)
|
merge_flags(&config, flags)
|
||||||
testing.expect_value(t, config.config_path, "./custom/thor.json")
|
testing.expect_value(t, config.config_path, "./custom/thor.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +188,7 @@ test_init_site_flag_overrides_default :: proc(t: ^testing.T) {
|
|||||||
init_site(&site, args)
|
init_site(&site, args)
|
||||||
defer destroy_site(&site)
|
defer destroy_site(&site)
|
||||||
|
|
||||||
testing.expect(t, site.drafts)
|
testing.expect(t, .Drafts in site.features)
|
||||||
testing.expect_value(t, site.base_url, "https://flag.com")
|
testing.expect_value(t, site.base_url, "https://flag.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +208,7 @@ test_init_site_full_pipeline :: proc(t: ^testing.T) {
|
|||||||
testing.expect_value(t, site.title, "Pipeline Test")
|
testing.expect_value(t, site.title, "Pipeline Test")
|
||||||
testing.expect_value(t, site.description, "Full")
|
testing.expect_value(t, site.description, "Full")
|
||||||
testing.expect_value(t, site.author, "Author")
|
testing.expect_value(t, site.author, "Author")
|
||||||
testing.expect(t, site.drafts)
|
testing.expect(t, .Drafts in site.features)
|
||||||
testing.expect_value(t, site.base_url, "https://config.com")
|
testing.expect_value(t, site.base_url, "https://config.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user