From dbcc13a5cf92813eb9ff444888341f0fbaba568e Mon Sep 17 00:00:00 2001
From: Svilen Markov <7613769+svilenmarkov@users.noreply.github.com>
Date: Mon, 16 Dec 2024 23:59:25 +0000
Subject: [PATCH] Allow inserting env variables anywhere in the config
---
internal/glance/config-fields.go | 56 -------------------
internal/glance/config.go | 47 +++++++++++++++-
internal/glance/templates/bookmarks.html | 2 +-
.../glance/templates/monitor-compact.html | 2 +-
internal/glance/templates/monitor.html | 2 +-
internal/glance/widget-bookmarks.go | 10 ++--
internal/glance/widget-changedetection.go | 2 +-
internal/glance/widget-custom-api.go | 18 +++---
internal/glance/widget-dns-stats.go | 14 ++---
internal/glance/widget-monitor.go | 12 ++--
internal/glance/widget-releases.go | 8 +--
internal/glance/widget-repository.go | 12 ++--
internal/glance/widget-rss.go | 6 +-
13 files changed, 90 insertions(+), 101 deletions(-)
diff --git a/internal/glance/config-fields.go b/internal/glance/config-fields.go
index 9a47820..6c6f0c5 100644
--- a/internal/glance/config-fields.go
+++ b/internal/glance/config-fields.go
@@ -2,7 +2,6 @@ package glance
import (
"fmt"
- "os"
"regexp"
"strconv"
"strings"
@@ -112,61 +111,6 @@ func (d *durationField) UnmarshalYAML(node *yaml.Node) error {
return nil
}
-var optionalEnvFieldPattern = regexp.MustCompile(`(^|.)\$\{([A-Z0-9_]+)\}`)
-
-type optionalEnvField string
-
-func (f *optionalEnvField) UnmarshalYAML(node *yaml.Node) error {
- var value string
-
- err := node.Decode(&value)
- if err != nil {
- return err
- }
-
- replaced := optionalEnvFieldPattern.ReplaceAllStringFunc(value, func(match string) string {
- if err != nil {
- return ""
- }
-
- groups := optionalEnvFieldPattern.FindStringSubmatch(match)
-
- if len(groups) != 3 {
- return match
- }
-
- prefix, key := groups[1], groups[2]
-
- if prefix == `\` {
- if len(match) >= 2 {
- return match[1:]
- } else {
- return ""
- }
- }
-
- value, found := os.LookupEnv(key)
- if !found {
- err = fmt.Errorf("environment variable %s not found", key)
- return ""
- }
-
- return prefix + value
- })
-
- if err != nil {
- return err
- }
-
- *f = optionalEnvField(replaced)
-
- return nil
-}
-
-func (f *optionalEnvField) String() string {
- return string(*f)
-}
-
type customIconField struct {
URL string
IsFlatIcon bool
diff --git a/internal/glance/config.go b/internal/glance/config.go
index 0f6b259..0ab79af 100644
--- a/internal/glance/config.go
+++ b/internal/glance/config.go
@@ -69,10 +69,15 @@ type page struct {
}
func newConfigFromYAML(contents []byte) (*config, error) {
+ contents, err := parseConfigEnvVariables(contents)
+ if err != nil {
+ return nil, err
+ }
+
config := &config{}
config.Server.Port = 8080
- err := yaml.Unmarshal(contents, config)
+ err = yaml.Unmarshal(contents, config)
if err != nil {
return nil, err
}
@@ -94,6 +99,46 @@ func newConfigFromYAML(contents []byte) (*config, error) {
return config, nil
}
+var configEnvVariablePattern = regexp.MustCompile(`(^|.)\$\{([A-Z0-9_]+)\}`)
+
+func parseConfigEnvVariables(contents []byte) ([]byte, error) {
+ var err error
+
+ replaced := configEnvVariablePattern.ReplaceAllFunc(contents, func(match []byte) []byte {
+ if err != nil {
+ return nil
+ }
+
+ groups := configEnvVariablePattern.FindSubmatch(match)
+ if len(groups) != 3 {
+ return match
+ }
+
+ prefix, key := string(groups[1]), string(groups[2])
+ if prefix == `\` {
+ if len(match) >= 2 {
+ return match[1:]
+ } else {
+ return nil
+ }
+ }
+
+ value, found := os.LookupEnv(key)
+ if !found {
+ err = fmt.Errorf("environment variable %s not found", key)
+ return nil
+ }
+
+ return []byte(prefix + value)
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ return replaced, nil
+}
+
func formatWidgetInitError(err error, w widget) error {
return fmt.Errorf("%s widget: %v", w.GetType(), err)
}
diff --git a/internal/glance/templates/bookmarks.html b/internal/glance/templates/bookmarks.html
index 711abb6..1e8bfc7 100644
--- a/internal/glance/templates/bookmarks.html
+++ b/internal/glance/templates/bookmarks.html
@@ -13,7 +13,7 @@
{{ end }}
- {{ .Title }}
+ {{ .Title }}
{{ end }}
diff --git a/internal/glance/templates/monitor-compact.html b/internal/glance/templates/monitor-compact.html
index e888c17..dca5683 100644
--- a/internal/glance/templates/monitor-compact.html
+++ b/internal/glance/templates/monitor-compact.html
@@ -21,7 +21,7 @@
{{ end }}
{{ define "site" }}
-{{ .Title }}
+{{ .Title }}
{{ if not .Status.TimedOut }}
{{ .Status.ResponseTime.Milliseconds | formatNumber }}ms
{{ end }}
{{ if eq .StatusStyle "ok" }}
diff --git a/internal/glance/templates/monitor.html b/internal/glance/templates/monitor.html
index 5c541a8..7e95b99 100644
--- a/internal/glance/templates/monitor.html
+++ b/internal/glance/templates/monitor.html
@@ -25,7 +25,7 @@

{{ end }}
-
{{ .Title }}
+
{{ .Title }}
{{ if not .Status.Error }}
- {{ .StatusText }}
diff --git a/internal/glance/widget-bookmarks.go b/internal/glance/widget-bookmarks.go
index 8641914..3c7a69c 100644
--- a/internal/glance/widget-bookmarks.go
+++ b/internal/glance/widget-bookmarks.go
@@ -13,11 +13,11 @@ type bookmarksWidget struct {
Title string `yaml:"title"`
Color *hslColorField `yaml:"color"`
Links []struct {
- Title string `yaml:"title"`
- URL optionalEnvField `yaml:"url"`
- Icon customIconField `yaml:"icon"`
- SameTab bool `yaml:"same-tab"`
- HideArrow bool `yaml:"hide-arrow"`
+ Title string `yaml:"title"`
+ URL string `yaml:"url"`
+ Icon customIconField `yaml:"icon"`
+ SameTab bool `yaml:"same-tab"`
+ HideArrow bool `yaml:"hide-arrow"`
} `yaml:"links"`
} `yaml:"groups"`
}
diff --git a/internal/glance/widget-changedetection.go b/internal/glance/widget-changedetection.go
index ed2fc86..8ca8803 100644
--- a/internal/glance/widget-changedetection.go
+++ b/internal/glance/widget-changedetection.go
@@ -18,7 +18,7 @@ type changeDetectionWidget struct {
ChangeDetections changeDetectionWatchList `yaml:"-"`
WatchUUIDs []string `yaml:"watches"`
InstanceURL string `yaml:"instance-url"`
- Token optionalEnvField `yaml:"token"`
+ Token string `yaml:"token"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
}
diff --git a/internal/glance/widget-custom-api.go b/internal/glance/widget-custom-api.go
index 17f3ee8..b7acce3 100644
--- a/internal/glance/widget-custom-api.go
+++ b/internal/glance/widget-custom-api.go
@@ -18,13 +18,13 @@ var customAPIWidgetTemplate = mustParseTemplate("custom-api.html", "widget-base.
type customAPIWidget struct {
widgetBase `yaml:",inline"`
- URL optionalEnvField `yaml:"url"`
- Template string `yaml:"template"`
- Frameless bool `yaml:"frameless"`
- Headers map[string]optionalEnvField `yaml:"headers"`
- APIRequest *http.Request `yaml:"-"`
- compiledTemplate *template.Template `yaml:"-"`
- CompiledHTML template.HTML `yaml:"-"`
+ URL string `yaml:"url"`
+ Template string `yaml:"template"`
+ Frameless bool `yaml:"frameless"`
+ Headers map[string]string `yaml:"headers"`
+ APIRequest *http.Request `yaml:"-"`
+ compiledTemplate *template.Template `yaml:"-"`
+ CompiledHTML template.HTML `yaml:"-"`
}
func (widget *customAPIWidget) initialize() error {
@@ -45,13 +45,13 @@ func (widget *customAPIWidget) initialize() error {
widget.compiledTemplate = compiledTemplate
- req, err := http.NewRequest(http.MethodGet, widget.URL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, widget.URL, nil)
if err != nil {
return err
}
for key, value := range widget.Headers {
- req.Header.Add(key, value.String())
+ req.Header.Add(key, value)
}
widget.APIRequest = req
diff --git a/internal/glance/widget-dns-stats.go b/internal/glance/widget-dns-stats.go
index 8b004b6..f6bc4b3 100644
--- a/internal/glance/widget-dns-stats.go
+++ b/internal/glance/widget-dns-stats.go
@@ -20,13 +20,13 @@ type dnsStatsWidget struct {
TimeLabels [8]string `yaml:"-"`
Stats *dnsStats `yaml:"-"`
- HourFormat string `yaml:"hour-format"`
- Service string `yaml:"service"`
- AllowInsecure bool `yaml:"allow-insecure"`
- URL optionalEnvField `yaml:"url"`
- Token optionalEnvField `yaml:"token"`
- Username optionalEnvField `yaml:"username"`
- Password optionalEnvField `yaml:"password"`
+ HourFormat string `yaml:"hour-format"`
+ Service string `yaml:"service"`
+ AllowInsecure bool `yaml:"allow-insecure"`
+ URL string `yaml:"url"`
+ Token string `yaml:"token"`
+ Username string `yaml:"username"`
+ Password string `yaml:"password"`
}
func makeDNSWidgetTimeLabels(format string) [8]string {
diff --git a/internal/glance/widget-monitor.go b/internal/glance/widget-monitor.go
index c3e1310..e5f7919 100644
--- a/internal/glance/widget-monitor.go
+++ b/internal/glance/widget-monitor.go
@@ -109,9 +109,9 @@ func statusCodeToStyle(status int, altStatusCodes []int) string {
}
type SiteStatusRequest struct {
- URL optionalEnvField `yaml:"url"`
- CheckURL optionalEnvField `yaml:"check-url"`
- AllowInsecure bool `yaml:"allow-insecure"`
+ URL string `yaml:"url"`
+ CheckURL string `yaml:"check-url"`
+ AllowInsecure bool `yaml:"allow-insecure"`
}
type siteStatus struct {
@@ -123,10 +123,10 @@ type siteStatus struct {
func fetchSiteStatusTask(statusRequest *SiteStatusRequest) (siteStatus, error) {
var url string
- if statusRequest.CheckURL.String() != "" {
- url = statusRequest.CheckURL.String()
+ if statusRequest.CheckURL != "" {
+ url = statusRequest.CheckURL
} else {
- url = statusRequest.URL.String()
+ url = statusRequest.URL
}
request, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
diff --git a/internal/glance/widget-releases.go b/internal/glance/widget-releases.go
index 0ac6caa..51296b0 100644
--- a/internal/glance/widget-releases.go
+++ b/internal/glance/widget-releases.go
@@ -20,8 +20,8 @@ type releasesWidget struct {
Releases appReleaseList `yaml:"-"`
releaseRequests []*releaseRequest `yaml:"-"`
Repositories []string `yaml:"repositories"`
- Token optionalEnvField `yaml:"token"`
- GitLabToken optionalEnvField `yaml:"gitlab-token"`
+ Token string `yaml:"token"`
+ GitLabToken string `yaml:"gitlab-token"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
ShowSourceIcon bool `yaml:"show-source-icon"`
@@ -38,8 +38,8 @@ func (widget *releasesWidget) initialize() error {
widget.CollapseAfter = 5
}
- var tokenAsString = widget.Token.String()
- var gitLabTokenAsString = widget.GitLabToken.String()
+ var tokenAsString = widget.Token
+ var gitLabTokenAsString = widget.GitLabToken
for _, repository := range widget.Repositories {
parts := strings.SplitN(repository, ":", 2)
diff --git a/internal/glance/widget-repository.go b/internal/glance/widget-repository.go
index df1e8b7..1eeb8b4 100644
--- a/internal/glance/widget-repository.go
+++ b/internal/glance/widget-repository.go
@@ -14,12 +14,12 @@ var repositoryWidgetTemplate = mustParseTemplate("repository.html", "widget-base
type repositoryWidget struct {
widgetBase `yaml:",inline"`
- RequestedRepository string `yaml:"repository"`
- Token optionalEnvField `yaml:"token"`
- PullRequestsLimit int `yaml:"pull-requests-limit"`
- IssuesLimit int `yaml:"issues-limit"`
- CommitsLimit int `yaml:"commits-limit"`
- Repository repository `yaml:"-"`
+ RequestedRepository string `yaml:"repository"`
+ Token string `yaml:"token"`
+ PullRequestsLimit int `yaml:"pull-requests-limit"`
+ IssuesLimit int `yaml:"issues-limit"`
+ CommitsLimit int `yaml:"commits-limit"`
+ Repository repository `yaml:"-"`
}
func (widget *repositoryWidget) initialize() error {
diff --git a/internal/glance/widget-rss.go b/internal/glance/widget-rss.go
index 8c0f5eb..da7416e 100644
--- a/internal/glance/widget-rss.go
+++ b/internal/glance/widget-rss.go
@@ -139,7 +139,7 @@ func shortenFeedDescriptionLen(description string, maxLen int) string {
}
type rssFeedRequest struct {
- URL optionalEnvField `yaml:"url"`
+ URL string `yaml:"url"`
Title string `yaml:"title"`
HideCategories bool `yaml:"hide-categories"`
HideDescription bool `yaml:"hide-description"`
@@ -161,7 +161,7 @@ func (f rssFeedItemList) sortByNewest() rssFeedItemList {
var feedParser = gofeed.NewParser()
func fetchItemsFromRSSFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {
- req, err := http.NewRequest("GET", request.URL.String(), nil)
+ req, err := http.NewRequest("GET", request.URL, nil)
if err != nil {
return nil, err
}
@@ -206,7 +206,7 @@ func fetchItemsFromRSSFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {
} else {
parsedUrl, err := url.Parse(feed.Link)
if err != nil {
- parsedUrl, err = url.Parse(request.URL.String())
+ parsedUrl, err = url.Parse(request.URL)
}
if err == nil {