summaryrefslogtreecommitdiff
path: root/src/lib/config.spec.source.sh
blob: 764cba61f06af7459e6b023fbf0bc29ba0a188d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# ----------------------------------------------------------------------------
# Config field registry (single source of truth, task mr0)
# ----------------------------------------------------------------------------
# CONFIG_SPECS is the one place a config field's cross-cutting facts are
# declared. Before mr0 the same knowledge (default value, CLI-overridability,
# validation rule, how it prints) was restated in ~6 hand-maintained lists --
# apply_config_defaults, CLI_CONFIG_OVERRIDE_TARGETS, validate_common_config,
# print_config, and parts of log_configured_action / the dry-run plan -- so
# adding or renaming an option was shotgun surgery and the lists drifted (the
# TARBALL_INCLUDE default once flipped to 'no' here while shuriken.default.conf
# still said 'yes', fixed in 7r0). Those consumers now DERIVE from this registry,
# so a field's facts live in exactly one entry.
#
# Each entry is a '|'-delimited spec, the same encoding used by ACTION_SPECS
# (action.source.sh) and TEMPLATE_RENDER_FIELD_SPECS (template.source.sh):
#
#   name|default|has_default|cli_overridable|validation|print_kind
#
#   name            the config variable name (also the env/override key).
#   default         the value apply_config_defaults applies via
#                   VAR="${VAR:-$default}" when has_default=yes. May be empty
#                   (e.g. FAVICON, HEIGHT default to the empty string).
#   has_default     yes -> apply the scalar default above. no -> never apply a
#                   scalar default: either a required var (TITLE, THUMBHEIGHT,
#                   ...) that must be set in the config, or an array
#                   (TAR_OPTS / SYNC_DESTINATIONS) defaulted separately via a
#                   `declare -p` guard in apply_config_defaults.
#   cli_overridable yes -> the field appears in CLI_CONFIG_OVERRIDE_TARGETS, i.e.
#                   a CLI flag (declared in CLI_OPTION_SPEC) can override it. The
#                   rich per-flag table (argument names, flag/value pairs) stays
#                   in CLI_OPTION_SPEC; this facet only drives the override-target
#                   list that used to be a separate hand-kept copy of it.
#   validation      the rule validate_common_config applies. Empty means
#                   validate_common_config does not check this field (SYNC_DELETE,
#                   the timeouts only checked on their own paths, etc. are
#                   validated elsewhere). One of:
#                     required        require_config_var (non-empty)
#                     required-posint require_config_var + positive integer
#                     posint          positive integer (no non-empty requirement)
#                     opt-posint      positive integer only if set (HEIGHT)
#                     percentage      integer 0..100
#                     yesno           literal yes or no
#                     favicon         validate_favicon_config (readable file/empty)
#   print_kind      how print_config emits the field. scalar -> %s=%q. array ->
#                   %s=( ... ) via the resolve_*-fed array printer. Empty means
#                   print_config does not emit it (none today). CONFIG_SOURCE is
#                   printed separately (it is the resolved config path, not a
#                   config variable) and so is not a registry entry.
#
# Entry order is the canonical print order (print_config emits in this order).
# validate_common_config does NOT reuse this order directly: it runs all
# `required*` checks before any kind check (so a missing required var is reported
# before a malformed one -- see test_config_validators_fail_fast_without_errexit),
# which it achieves with two filtered passes over the registry.
#
# Declared -g so it survives being sourced from inside a function (the test
# harness sources the lib via test::source_shuriken_lib); a plain `declare -r`
# would be function-local and vanish on return.
declare -gra CONFIG_SPECS=(
    'INCOMING_DIR||no|yes|required|scalar'
    'DIST_DIR||no|yes|required|scalar'
    'TEMPLATE_DIR||no|yes|required|scalar'
    'FAVICON||yes|yes|favicon|scalar'
    'SOURCE_URL|https://codeberg.org/snonux/shuriken.sh|yes|yes||scalar'
    'TITLE||no|yes|required|scalar'
    'HEIGHT||yes|yes|opt-posint|scalar'
    'THUMBHEIGHT||no|yes|required-posint|scalar'
    'MAXPREVIEWS||no|yes|required-posint|scalar'
    'THUMB_SUBDIVIDE_PERCENT|30|yes|yes|percentage|scalar'
    'THUMB_FEATURE_PERCENT|10|yes|yes|percentage|scalar'
    'IMAGE_JOBS|3|yes|yes|required-posint|scalar'
    'IMAGEMAGICK_TIMEOUT|60|yes|no|posint|scalar'
    'RANDOM_SEED||yes|yes||scalar'
    'SHUFFLE|no|yes|yes|yesno|scalar'
    'SPLASH_PAGE|yes|yes|yes|yesno|scalar'
    'DETAILS_PAGE|yes|yes|yes|yesno|scalar'
    'STATS_PAGE|no|yes|yes|yesno|scalar'
    'TARBALL_INCLUDE|yes|yes|yes|yesno|scalar'
    'TARBALL_SUFFIX|.tar|yes|no||scalar'
    'TAR_TIMEOUT|120|yes|no|posint|scalar'
    'TAR_OPTS||no|no||array'
    'SYNC_DELETE|yes|yes|yes||scalar'
    'SYNC_TIMEOUT|300|yes|no|posint|scalar'
    'SYNC_DESTINATIONS||no|no||array'
    'ORIGINAL_BASEPATH||yes|no||scalar'
)

# Split one CONFIG_SPECS entry into the caller's named array (IFS='|' read), the
# same accessor pattern action_spec_field uses for ACTION_SPECS. Field indices:
#   0 name  1 default  2 has_default  3 cli_overridable  4 validation  5 print_kind
config_spec_split() {
    local -r spec="$1"; shift
    # shellcheck disable=SC2178
    local -n fields_ref="$1"; shift

    # fields_ref is a nameref output array filled for the caller; shellcheck
    # cannot see the indirect use through the nameref.
    # shellcheck disable=SC2034
    IFS='|' read -r -a fields_ref <<< "$spec"
}

# Populate CLI_CONFIG_OVERRIDE_TARGETS from the registry: every field marked
# cli_overridable=yes. This is the list apply_cli_overrides iterates to copy
# parsed --flag values onto their config var. Declared (empty) in src/shuriken.sh
# before the libs are sourced; filled here, once CONFIG_SPECS exists. Replaces the
# hand-kept copy of CLI_OPTION_SPEC's config= targets that used to drift (mr0).
# Iteration order is registry order; it is unobservable because each override
# targets a distinct variable, so no field can shadow another.
build_cli_config_override_targets() {
    local spec
    local -a fields=()

    CLI_CONFIG_OVERRIDE_TARGETS=()
    for spec in "${CONFIG_SPECS[@]}"; do
        config_spec_split "$spec" fields
        if [ "${fields[3]}" = yes ]; then
            CLI_CONFIG_OVERRIDE_TARGETS+=("${fields[0]}")
        fi
    done
}

# Build the override-target list at source time so it is ready before any CLI
# parsing. Guarded so sourcing this module without the shuriken.sh-level
# declaration (e.g. a narrowly scoped unit test) is a no-op rather than an error.
if declare -p CLI_CONFIG_OVERRIDE_TARGETS >/dev/null 2>&1; then
    build_cli_config_override_targets
fi