Use yaml for config, build filename and slug using configurable templates
parent
442395a83c
commit
cbf53ccb23
155
config.go
155
config.go
|
@ -2,8 +2,9 @@ package main
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/caarlos0/env/v6"
|
||||
"gopkg.in/yaml.v2"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -17,6 +18,8 @@ var (
|
|||
SelectedCdn Cdn
|
||||
SelectedNotificationServices NotificationServices
|
||||
SelectedImageCompression ImageCompression
|
||||
DefaultLanguage string
|
||||
Languages map[string]Language
|
||||
)
|
||||
|
||||
type SyndicationTarget struct {
|
||||
|
@ -24,41 +27,109 @@ type SyndicationTarget struct {
|
|||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type config struct {
|
||||
BlogUrl string `env:"BLOG_URL,required"`
|
||||
BaseUrl string `env:"BASE_URL,required"`
|
||||
MediaUrl string `env:"MEDIA_URL"`
|
||||
GitFilepath string `env:"GIT_FILEPATH" envDefault:"/tmp/micropubrepo"`
|
||||
GitUrl string `env:"GIT_URL"`
|
||||
GitUsername string `env:"GIT_USERNAME"`
|
||||
GitPassword string `env:"GIT_PASSWORD"`
|
||||
GitAuthorName string `env:"GIT_AUTHOR_NAME" envDefault:"hugo-micropub"`
|
||||
GitAuthorEmail string `env:"GIT_AUTHOR_EMAIL" envDefault:"hugo-micropub@example.com"`
|
||||
BunnyCdnKey string `env:"BUNNY_CDN_KEY"`
|
||||
BunnyCdnStorageKey string `env:"BUNNY_CDN_STORAGE_KEY"`
|
||||
BunnyCdnStorageName string `env:"BUNNY_CDN_STORAGE_NAME"`
|
||||
TelegramUserId int `env:"TELEGRAM_USER_ID"`
|
||||
TelegramBotToken string `env:"TELEGRAM_BOT_TOKEN"`
|
||||
IgnoredWebmentionUrls []string `env:"WEBMENTION_IGNORED" envSeparator:","`
|
||||
SyndicationTargets []string `env:"SYNDICATION" envSeparator:","`
|
||||
TinifyKey string `env:"TINIFY_KEY"`
|
||||
type YamlConfig struct {
|
||||
BlogUrl string `yaml:"blogUrl"`
|
||||
BaseUrl string `yaml:"baseUrl"`
|
||||
MediaUrl string `yaml:"mediaUrl"`
|
||||
DefaultLanguage string `yaml:"defaultLang"`
|
||||
Languages map[string]Language `yaml:"languages"`
|
||||
Git GitConfig `yaml:"git"`
|
||||
BunnyCdn BunnyCdnConfig `yaml:"bunnyCdn"`
|
||||
Telegram TelegramConfig `yaml:"telegram"`
|
||||
Tinify TinifyConfig `yaml:"tinify"`
|
||||
IgnoredWebmentionUrls []string `yaml:"ignoreWebmention"`
|
||||
SyndicationTargets []string `yaml:"syndication"`
|
||||
}
|
||||
|
||||
type BunnyCdnConfig struct {
|
||||
Key string `yaml:"key"`
|
||||
StorageKey string `yaml:"storageKey"`
|
||||
StorageName string `yaml:"storageName"`
|
||||
}
|
||||
|
||||
type TelegramConfig struct {
|
||||
UserId int `yaml:"userId"`
|
||||
BotToken string `yaml:"botToken"`
|
||||
}
|
||||
|
||||
type TinifyConfig struct {
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
type GitConfig struct {
|
||||
Filepath string `yaml:"filepath"`
|
||||
Url string `yaml:"url"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
AuthorName string `yaml:"authorName"`
|
||||
AuthorEmail string `yaml:"authorEmail"`
|
||||
}
|
||||
|
||||
type Language struct {
|
||||
BlogUrl string `yaml:"blogUrl"`
|
||||
ContentDir string `yaml:"contentDir"`
|
||||
DefaultSection string `yaml:"defaultSection"`
|
||||
Sections map[string]Section `yaml:"sections"`
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
FilenameTemplate string `yaml:"file"`
|
||||
LocationTemplate string `yaml:"location"`
|
||||
}
|
||||
|
||||
func initConfig() (err error) {
|
||||
cfg := config{}
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
return errors.New("failed to parse config, probably not all required env vars set")
|
||||
configFileName, configSet := os.LookupEnv("CONFIG")
|
||||
if !configSet {
|
||||
configFileName = "config.yml"
|
||||
}
|
||||
configFile, err := os.Open(configFileName)
|
||||
if err != nil {
|
||||
return errors.New("failed to open config file")
|
||||
}
|
||||
cfg := YamlConfig{}
|
||||
err = yaml.NewDecoder(configFile).Decode(&cfg)
|
||||
if err != nil {
|
||||
return errors.New("failed to parse yaml")
|
||||
}
|
||||
// Blog URL (required)
|
||||
if len(cfg.BlogUrl) < 1 {
|
||||
return errors.New("blogUrl not configured")
|
||||
}
|
||||
if !strings.HasSuffix(cfg.BlogUrl, "/") {
|
||||
return errors.New("missing trailing slash in BLOG_URL")
|
||||
return errors.New("missing trailing slash in configured blogUrl")
|
||||
}
|
||||
BlogUrl = cfg.BlogUrl
|
||||
// Media endpoint
|
||||
// Media endpoint (required)
|
||||
if len(cfg.BaseUrl) < 1 {
|
||||
return errors.New("baseUrl not configured")
|
||||
}
|
||||
if len(cfg.MediaUrl) < 1 {
|
||||
return errors.New("mediaUrl not configured")
|
||||
}
|
||||
if !strings.HasSuffix(cfg.BaseUrl, "/") {
|
||||
return errors.New("missing trailing slash in BASE_URL")
|
||||
return errors.New("missing trailing slash in configured baseUrl")
|
||||
}
|
||||
MediaEndpointUrl = cfg.BaseUrl + "media"
|
||||
// Languages (required)
|
||||
if len(cfg.DefaultLanguage) < 1 {
|
||||
return errors.New("no default language configured")
|
||||
}
|
||||
DefaultLanguage = cfg.DefaultLanguage
|
||||
if len(cfg.Languages) > 0 {
|
||||
for _, lang := range cfg.Languages {
|
||||
if len(lang.ContentDir) < 1 || len(lang.DefaultSection) < 1 || len(lang.Sections) < 1 {
|
||||
return errors.New("language not completely configured")
|
||||
}
|
||||
for _, section := range lang.Sections {
|
||||
if len(section.FilenameTemplate) < 1 || len(section.LocationTemplate) < 1 {
|
||||
return errors.New("section not completely configured")
|
||||
}
|
||||
}
|
||||
}
|
||||
Languages = cfg.Languages
|
||||
} else {
|
||||
return errors.New("no languages configured")
|
||||
}
|
||||
// Ignored Webmention URLs (optional)
|
||||
IgnoredWebmentionUrls = cfg.IgnoredWebmentionUrls
|
||||
// Syndication Targets (optional)
|
||||
|
@ -73,14 +144,14 @@ func initConfig() (err error) {
|
|||
// Find selected storage
|
||||
SelectedStorage = func() Storage {
|
||||
// Git
|
||||
if len(cfg.GitFilepath) > 0 && len(cfg.GitUrl) > 0 && len(cfg.GitUsername) > 0 && len(cfg.GitPassword) > 0 && len(cfg.GitAuthorName) > 0 && len(cfg.GitAuthorEmail) > 0 {
|
||||
if len(cfg.Git.Filepath) > 0 && len(cfg.Git.Url) > 0 && len(cfg.Git.Username) > 0 && len(cfg.Git.Password) > 0 && len(cfg.Git.AuthorName) > 0 && len(cfg.Git.AuthorEmail) > 0 {
|
||||
return &Git{
|
||||
filepath: cfg.GitFilepath,
|
||||
url: cfg.GitUrl,
|
||||
username: cfg.GitUsername,
|
||||
password: cfg.GitPassword,
|
||||
name: cfg.GitAuthorName,
|
||||
email: cfg.GitAuthorEmail,
|
||||
filepath: cfg.Git.Filepath,
|
||||
url: cfg.Git.Url,
|
||||
username: cfg.Git.Username,
|
||||
password: cfg.Git.Password,
|
||||
name: cfg.Git.AuthorName,
|
||||
email: cfg.Git.AuthorEmail,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -92,10 +163,10 @@ func initConfig() (err error) {
|
|||
SelectedMediaStorage = func() MediaStorage {
|
||||
// BunnyCDN
|
||||
// MEDIA_URL needs trailing slash too
|
||||
if len(cfg.BunnyCdnStorageKey) > 0 && len(cfg.BunnyCdnStorageName) > 0 && len(cfg.MediaUrl) > 0 && strings.HasSuffix(cfg.MediaUrl, "/") {
|
||||
if len(cfg.BunnyCdn.StorageKey) > 0 && len(cfg.BunnyCdn.StorageName) > 0 && len(cfg.MediaUrl) > 0 && strings.HasSuffix(cfg.MediaUrl, "/") {
|
||||
return &BunnyCdnStorage{
|
||||
key: cfg.BunnyCdnStorageKey,
|
||||
storageZoneName: cfg.BunnyCdnStorageName,
|
||||
key: cfg.BunnyCdn.StorageKey,
|
||||
storageZoneName: cfg.BunnyCdn.StorageName,
|
||||
baseLocation: cfg.MediaUrl,
|
||||
}
|
||||
}
|
||||
|
@ -107,8 +178,8 @@ func initConfig() (err error) {
|
|||
// Find selected CDN (optional)
|
||||
SelectedCdn = func() Cdn {
|
||||
// BunnyCDN
|
||||
if len(cfg.BunnyCdnKey) > 0 {
|
||||
return &BunnyCdn{key: cfg.BunnyCdnKey}
|
||||
if len(cfg.BunnyCdn.Key) > 0 {
|
||||
return &BunnyCdn{key: cfg.BunnyCdn.Key}
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
@ -119,10 +190,10 @@ func initConfig() (err error) {
|
|||
SelectedNotificationServices = func() NotificationServices {
|
||||
var notificationServices []NotificationService = nil
|
||||
// Telegram
|
||||
if cfg.TelegramUserId > 0 && len(cfg.TelegramBotToken) > 0 {
|
||||
if cfg.Telegram.UserId > 0 && len(cfg.Telegram.BotToken) > 0 {
|
||||
notificationServices = append(notificationServices, &Telegram{
|
||||
userId: cfg.TelegramUserId,
|
||||
botToken: cfg.TelegramBotToken,
|
||||
userId: cfg.Telegram.UserId,
|
||||
botToken: cfg.Telegram.BotToken,
|
||||
})
|
||||
}
|
||||
return notificationServices
|
||||
|
@ -133,9 +204,9 @@ func initConfig() (err error) {
|
|||
// Find configured image compression service (optional)
|
||||
SelectedImageCompression = func() ImageCompression {
|
||||
// Tinify
|
||||
if len(cfg.TinifyKey) > 0 {
|
||||
if len(cfg.Tinify.Key) > 0 {
|
||||
return &Tinify{
|
||||
key: cfg.TinifyKey,
|
||||
key: cfg.Tinify.Key,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
64
entry.go
64
entry.go
|
@ -9,6 +9,7 @@ import (
|
|||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -258,26 +259,57 @@ func computeExtraSettings(entry *Entry) error {
|
|||
random := generateRandomString(now, 5)
|
||||
entry.slug = fmt.Sprintf("%v-%02d-%02d-%v", now.Year(), int(now.Month()), now.Day(), random)
|
||||
}
|
||||
// Compute filename and location
|
||||
contentFolder := "content"
|
||||
localizedBlogUrl := BlogUrl
|
||||
if len(entry.language) > 0 && entry.language != "en" {
|
||||
// Append language to content folder: "content-de" for language "de"
|
||||
contentFolder += "-" + entry.language
|
||||
// Append language to BlogUrl
|
||||
localizedBlogUrl += entry.language + "/"
|
||||
// Set language
|
||||
if len(entry.language) == 0 {
|
||||
entry.language = DefaultLanguage
|
||||
}
|
||||
if len(entry.section) < 1 {
|
||||
entry.section = "micro"
|
||||
// Compute filename and location
|
||||
lang := Languages[entry.language]
|
||||
contentFolder := lang.ContentDir
|
||||
localizedBlogUrl := BlogUrl
|
||||
if len(lang.BlogUrl) != 0 {
|
||||
localizedBlogUrl = lang.BlogUrl
|
||||
}
|
||||
if len(entry.section) == 0 {
|
||||
entry.section = lang.DefaultSection
|
||||
}
|
||||
entry.section = strings.ToLower(entry.section)
|
||||
if entry.section == "thoughts" || entry.section == "links" || entry.section == "micro" {
|
||||
entry.filename = fmt.Sprintf("%v/%v/%02d/%02d/%v.md", contentFolder, entry.section, now.Year(), int(now.Month()), entry.slug)
|
||||
entry.location = fmt.Sprintf("%v%v/%02d/%02d/%v/", localizedBlogUrl, entry.section, now.Year(), int(now.Month()), entry.slug)
|
||||
} else {
|
||||
entry.filename = fmt.Sprintf("%v/%v/%v.md", contentFolder, entry.section, entry.slug)
|
||||
entry.location = fmt.Sprintf("%v%v/%v/", localizedBlogUrl, entry.section, entry.slug)
|
||||
section := lang.Sections[entry.section]
|
||||
pathVars := struct {
|
||||
LocalContentFolder string
|
||||
LocalBlogUrl string
|
||||
Year int
|
||||
Month int
|
||||
Slug string
|
||||
Section string
|
||||
}{
|
||||
LocalContentFolder: contentFolder,
|
||||
LocalBlogUrl: localizedBlogUrl,
|
||||
Year: now.Year(),
|
||||
Month: int(now.Month()),
|
||||
Slug: entry.slug,
|
||||
Section: entry.section,
|
||||
}
|
||||
filenameTmpl, err := template.New("filename").Parse(section.FilenameTemplate)
|
||||
if err != nil {
|
||||
return errors.New("failed to parse filename template")
|
||||
}
|
||||
filename := new(bytes.Buffer)
|
||||
err = filenameTmpl.Execute(filename, pathVars)
|
||||
if err != nil {
|
||||
return errors.New("failed to execute filename template")
|
||||
}
|
||||
entry.filename = filename.String()
|
||||
locationTmpl, err := template.New("location").Parse(section.LocationTemplate)
|
||||
if err != nil {
|
||||
return errors.New("failed to parse location template")
|
||||
}
|
||||
location := new(bytes.Buffer)
|
||||
err = locationTmpl.Execute(location, pathVars)
|
||||
if err != nil {
|
||||
return errors.New("failed to execute location template")
|
||||
}
|
||||
entry.location = location.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
1
go.mod
1
go.mod
|
@ -4,7 +4,6 @@ go 1.14
|
|||
|
||||
require (
|
||||
codeberg.org/jlelse/tinify v0.0.0-20200123222407-7fc9c21822b0
|
||||
github.com/caarlos0/env/v6 v6.2.1
|
||||
github.com/go-git/go-git/v5 v5.0.0
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
willnorris.com/go/webmention v0.0.0-20200126231626-5a55fff6bf71
|
||||
|
|
5
go.sum
5
go.sum
|
@ -8,8 +8,6 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
|
|||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/caarlos0/env/v6 v6.2.1 h1:/bFpX1dg4TNioJjg7mrQaSrBoQvRfLUHNfXivdFbbEo=
|
||||
github.com/caarlos0/env/v6 v6.2.1/go.mod h1:3LpmfcAYCG6gCiSgDLaFR5Km1FRpPwFvBbRcjHar6Sw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -51,9 +49,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
|
|
Loading…
Reference in New Issue