aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.eu>2020-04-19 23:46:08 +0200
committerRené 'Necoro' Neumann <necoro@necoro.eu>2020-04-19 23:46:08 +0200
commit431a8ddb0c18b0781cba1d01eda3645b361f1b94 (patch)
treef67e427279e4e50d20c6acfa8ad22b51f2b5f7e6
parented1e06e6d81645fb5fedd89018c30f95b7598f84 (diff)
downloadfeed2imap-go-431a8ddb0c18b0781cba1d01eda3645b361f1b94.tar.gz
feed2imap-go-431a8ddb0c18b0781cba1d01eda3645b361f1b94.tar.bz2
feed2imap-go-431a8ddb0c18b0781cba1d01eda3645b361f1b94.zip
Restructure
-rw-r--r--internal/config/config.go63
-rw-r--r--internal/feed/feed.go45
-rw-r--r--internal/feed/parse.go7
-rw-r--r--internal/yaml/yaml.go (renamed from internal/config/yaml.go)54
-rw-r--r--internal/yaml/yaml_test.go (renamed from internal/config/yaml_test.go)154
-rw-r--r--main.go6
6 files changed, 177 insertions, 152 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index fa14315..0cebf34 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -1,73 +1,12 @@
package config
-import (
- "fmt"
- "io/ioutil"
- "strings"
-)
-
type Map map[string]interface{}
-type Feeds map[string]*Feed
-
-func (f Feeds) String() string {
- var b strings.Builder
- app := func(a ...interface{}) {
- _, _ = fmt.Fprint(&b, a...)
- }
- app("Feeds [")
-
- first := true
- for k, v := range f {
- if !first {
- app(", ")
- }
- app(`"`, k, `"`, ": ")
- if v == nil {
- app("<nil>")
- } else {
- _, _ = fmt.Fprintf(&b, "%+v", *v)
- }
- first = false
- }
- app("]")
-
- return b.String()
-}
type Config struct {
GlobalConfig Map
- Feeds Feeds
}
-type Feed struct {
- Name string
- Target []string `yaml:"-"`
- Url string
+type Options struct {
MinFreq int `yaml:"min-frequency"`
InclImages *bool `yaml:"include-images"`
}
-
-func Load(path string) (Config, error) {
- var finishedCfg Config
-
- buf, err := ioutil.ReadFile(path)
- if err != nil {
- return finishedCfg, fmt.Errorf("while reading '%s': %w", path, err)
- }
-
- var parsedCfg config
- if parsedCfg, err = parse(buf); err != nil {
- return finishedCfg, err
- }
-
- finishedCfg = Config{
- GlobalConfig: parsedCfg.GlobalConfig,
- Feeds: make(Feeds),
- }
-
- if err := buildFeeds(parsedCfg.Feeds, []string{}, finishedCfg.Feeds); err != nil {
- return finishedCfg, fmt.Errorf("while parsing: %w", err)
- }
-
- return finishedCfg, nil
-}
diff --git a/internal/feed/feed.go b/internal/feed/feed.go
new file mode 100644
index 0000000..59c15f2
--- /dev/null
+++ b/internal/feed/feed.go
@@ -0,0 +1,45 @@
+package feed
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/mmcdole/gofeed"
+
+ "github.com/Necoro/feed2imap-go/internal/config"
+)
+
+type Feed struct {
+ Name string
+ Target []string
+ Url string
+ config.Options
+ feed gofeed.Feed
+}
+
+type Feeds map[string]*Feed
+
+func (f Feeds) String() string {
+ var b strings.Builder
+ app := func(a ...interface{}) {
+ _, _ = fmt.Fprint(&b, a...)
+ }
+ app("Feeds [")
+
+ first := true
+ for k, v := range f {
+ if !first {
+ app(", ")
+ }
+ app(`"`, k, `"`, ": ")
+ if v == nil {
+ app("<nil>")
+ } else {
+ _, _ = fmt.Fprintf(&b, "%+v", *v)
+ }
+ first = false
+ }
+ app("]")
+
+ return b.String()
+}
diff --git a/internal/feed/parse.go b/internal/feed/parse.go
index 53ceb00..a38be92 100644
--- a/internal/feed/parse.go
+++ b/internal/feed/parse.go
@@ -8,7 +8,6 @@ import (
"github.com/mmcdole/gofeed"
- "github.com/Necoro/feed2imap-go/internal/config"
"github.com/Necoro/feed2imap-go/internal/log"
)
@@ -16,7 +15,7 @@ func context() (ctxt.Context, ctxt.CancelFunc) {
return ctxt.WithTimeout(ctxt.Background(), 60*time.Second)
}
-func parseFeed(feed *config.Feed) error {
+func parseFeed(feed *Feed) error {
ctx, cancel := context()
defer cancel()
fp := gofeed.NewParser()
@@ -27,7 +26,7 @@ func parseFeed(feed *config.Feed) error {
return nil
}
-func handleFeed(feed *config.Feed, wg *sync.WaitGroup) {
+func handleFeed(feed *Feed, wg *sync.WaitGroup) {
defer wg.Done()
log.Printf("Fetching %s from %s", feed.Name, feed.Url)
@@ -36,7 +35,7 @@ func handleFeed(feed *config.Feed, wg *sync.WaitGroup) {
}
}
-func Parse(feeds config.Feeds) {
+func Parse(feeds Feeds) {
var wg sync.WaitGroup
wg.Add(len(feeds))
diff --git a/internal/config/yaml.go b/internal/yaml/yaml.go
index 80fb383..8cbace7 100644
--- a/internal/config/yaml.go
+++ b/internal/yaml/yaml.go
@@ -1,25 +1,35 @@
-package config
+package yaml
import (
"fmt"
+ "io/ioutil"
"gopkg.in/yaml.v3"
+
+ C "github.com/Necoro/feed2imap-go/internal/config"
+ F "github.com/Necoro/feed2imap-go/internal/feed"
)
type config struct {
- GlobalConfig Map `yaml:",inline"`
+ GlobalConfig C.Map `yaml:",inline"`
Feeds []configGroupFeed
}
-type Group struct {
+type group struct {
Group string
Feeds []configGroupFeed
}
+type feed struct {
+ Name string
+ Url string
+ C.Options `yaml:",inline"`
+}
+
type configGroupFeed struct {
Target *string
- Feed `yaml:",inline"`
- Group `yaml:",inline"`
+ Feed feed `yaml:",inline"`
+ Group group `yaml:",inline"`
}
func (grpFeed *configGroupFeed) isGroup() bool {
@@ -34,8 +44,8 @@ func (grpFeed *configGroupFeed) target() string {
if grpFeed.Target != nil {
return *grpFeed.Target
}
- if grpFeed.Name != "" {
- return grpFeed.Name
+ if grpFeed.Feed.Name != "" {
+ return grpFeed.Feed.Name
}
return grpFeed.Group.Group
@@ -65,7 +75,7 @@ func appTarget(target []string, app string) []string {
}
// Parse the group structure and populate the `Target` fields in the feeds
-func buildFeeds(cfg []configGroupFeed, target []string, feeds Feeds) error {
+func buildFeeds(cfg []configGroupFeed, target []string, feeds F.Feeds) error {
for idx := range cfg {
f := &cfg[idx] // cannot use `_, f := range cfg` as it returns copies(!), but we need the originals
target := appTarget(target, f.target())
@@ -82,8 +92,12 @@ func buildFeeds(cfg []configGroupFeed, target []string, feeds Feeds) error {
if _, ok := feeds[name]; ok {
return fmt.Errorf("Duplicate Feed Name '%s'", name)
}
- f.Feed.Target = target
- feeds[name] = &f.Feed
+ feeds[name] = &F.Feed{
+ Name: f.Feed.Name,
+ Target: target,
+ Url: f.Feed.Url,
+ Options: f.Feed.Options,
+ }
case f.isGroup():
if err := buildFeeds(f.Group.Feeds, target, feeds); err != nil {
@@ -94,3 +108,23 @@ func buildFeeds(cfg []configGroupFeed, target []string, feeds Feeds) error {
return nil
}
+
+func Load(path string) (C.Config, F.Feeds, error) {
+ buf, err := ioutil.ReadFile(path)
+ if err != nil {
+ return C.Config{}, nil, fmt.Errorf("while reading '%s': %w", path, err)
+ }
+
+ var parsedCfg config
+ if parsedCfg, err = parse(buf); err != nil {
+ return C.Config{}, nil, err
+ }
+
+ feeds := F.Feeds{}
+
+ if err := buildFeeds(parsedCfg.Feeds, []string{}, feeds); err != nil {
+ return C.Config{}, nil, fmt.Errorf("while parsing: %w", err)
+ }
+
+ return C.Config{GlobalConfig: parsedCfg.GlobalConfig}, feeds, nil
+}
diff --git a/internal/config/yaml_test.go b/internal/yaml/yaml_test.go
index 1e77700..0e9ef08 100644
--- a/internal/config/yaml_test.go
+++ b/internal/yaml/yaml_test.go
@@ -1,9 +1,12 @@
-package config
+package yaml
import (
"reflect"
"strings"
"testing"
+
+ C "github.com/Necoro/feed2imap-go/internal/config"
+ F "github.com/Necoro/feed2imap-go/internal/feed"
)
func s(s string) *string { return &s }
@@ -21,99 +24,99 @@ func TestBuildFeeds(tst *testing.T) {
wantErr bool
target string
feeds []configGroupFeed
- result Feeds
+ result F.Feeds
}{
- {name: "Empty input", wantErr: false, target: "", feeds: nil, result: Feeds{}},
+ {name: "Empty input", wantErr: false, target: "", feeds: nil, result: F.Feeds{}},
{name: "Empty Feed", wantErr: true, target: "",
feeds: []configGroupFeed{
- {Target: s("foo"), Feed: Feed{Url: "google.de"}},
- }, result: Feeds{}},
+ {Target: s("foo"), Feed: feed{Url: "google.de"}},
+ }, result: F.Feeds{}},
{name: "Empty Feed", wantErr: true, target: "",
feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{Url: "google.de"}},
- }, result: Feeds{}},
+ {Target: nil, Feed: feed{Url: "google.de"}},
+ }, result: F.Feeds{}},
{name: "Duplicate Feed Name", wantErr: true, target: "",
feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{Name: "Dup"}},
- {Target: nil, Feed: Feed{Name: "Dup"}},
- }, result: Feeds{}},
+ {Target: nil, Feed: feed{Name: "Dup"}},
+ {Target: nil, Feed: feed{Name: "Dup"}},
+ }, result: F.Feeds{}},
{name: "Simple", wantErr: false, target: "",
feeds: []configGroupFeed{
- {Target: s("foo"), Feed: Feed{Name: "muh"}},
+ {Target: s("foo"), Feed: feed{Name: "muh"}},
},
- result: Feeds{"muh": &Feed{Name: "muh", Target: t("foo")}},
+ result: F.Feeds{"muh": &F.Feed{Name: "muh", Target: t("foo")}},
},
{name: "Simple With Target", wantErr: false, target: "moep",
feeds: []configGroupFeed{
- {Target: s("foo"), Feed: Feed{Name: "muh"}},
+ {Target: s("foo"), Feed: feed{Name: "muh"}},
},
- result: Feeds{"muh": &Feed{Name: "muh", Target: t("moep.foo")}},
+ result: F.Feeds{"muh": &F.Feed{Name: "muh", Target: t("moep.foo")}},
},
{name: "Simple With Nil Target", wantErr: false, target: "moep",
feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{Name: "muh"}},
+ {Target: nil, Feed: feed{Name: "muh"}},
},
- result: Feeds{"muh": &Feed{Name: "muh", Target: t("moep.muh")}},
+ result: F.Feeds{"muh": &F.Feed{Name: "muh", Target: t("moep.muh")}},
},
{name: "Simple With Empty Target", wantErr: false, target: "moep",
feeds: []configGroupFeed{
- {Target: s(""), Feed: Feed{Name: "muh"}},
+ {Target: s(""), Feed: feed{Name: "muh"}},
},
- result: Feeds{"muh": &Feed{Name: "muh", Target: t("moep")}},
+ result: F.Feeds{"muh": &F.Feed{Name: "muh", Target: t("moep")}},
},
{name: "Multiple Feeds", wantErr: false, target: "moep",
feeds: []configGroupFeed{
- {Target: s("foo"), Feed: Feed{Name: "muh"}},
- {Target: nil, Feed: Feed{Name: "bar"}},
+ {Target: s("foo"), Feed: feed{Name: "muh"}},
+ {Target: nil, Feed: feed{Name: "bar"}},
},
- result: Feeds{
- "muh": &Feed{Name: "muh", Target: t("moep.foo")},
- "bar": &Feed{Name: "bar", Target: t("moep.bar")},
+ result: F.Feeds{
+ "muh": &F.Feed{Name: "muh", Target: t("moep.foo")},
+ "bar": &F.Feed{Name: "bar", Target: t("moep.bar")},
},
},
{name: "Empty Group", wantErr: false, target: "",
feeds: []configGroupFeed{
- {Target: nil, Group: Group{Group: "G1"}},
+ {Target: nil, Group: group{Group: "G1"}},
},
- result: Feeds{},
+ result: F.Feeds{},
},
{name: "Simple Group", wantErr: false, target: "",
feeds: []configGroupFeed{
- {Target: nil, Group: Group{Group: "G1", Feeds: []configGroupFeed{
- {Target: s("bar"), Feed: Feed{Name: "F1"}},
- {Target: s(""), Feed: Feed{Name: "F2"}},
- {Target: nil, Feed: Feed{Name: "F3"}},
+ {Target: nil, Group: group{Group: "G1", Feeds: []configGroupFeed{
+ {Target: s("bar"), Feed: feed{Name: "F1"}},
+ {Target: s(""), Feed: feed{Name: "F2"}},
+ {Target: nil, Feed: feed{Name: "F3"}},
}}},
},
- result: Feeds{
- "F1": &Feed{Name: "F1", Target: t("G1.bar")},
- "F2": &Feed{Name: "F2", Target: t("G1")},
- "F3": &Feed{Name: "F3", Target: t("G1.F3")},
+ result: F.Feeds{
+ "F1": &F.Feed{Name: "F1", Target: t("G1.bar")},
+ "F2": &F.Feed{Name: "F2", Target: t("G1")},
+ "F3": &F.Feed{Name: "F3", Target: t("G1.F3")},
},
},
{name: "Nested Groups", wantErr: false, target: "",
feeds: []configGroupFeed{
- {Target: nil, Group: Group{Group: "G1", Feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{Name: "F0"}},
- {Target: s("bar"), Group: Group{Group: "G2",
- Feeds: []configGroupFeed{{Target: nil, Feed: Feed{Name: "F1"}}}}},
- {Target: s(""), Group: Group{Group: "G3",
- Feeds: []configGroupFeed{{Target: s("baz"), Feed: Feed{Name: "F2"}}}}},
- {Target: nil, Group: Group{Group: "G4",
- Feeds: []configGroupFeed{{Target: nil, Feed: Feed{Name: "F3"}}}}},
+ {Target: nil, Group: group{Group: "G1", Feeds: []configGroupFeed{
+ {Target: nil, Feed: feed{Name: "F0"}},
+ {Target: s("bar"), Group: group{Group: "G2",
+ Feeds: []configGroupFeed{{Target: nil, Feed: feed{Name: "F1"}}}}},
+ {Target: s(""), Group: group{Group: "G3",
+ Feeds: []configGroupFeed{{Target: s("baz"), Feed: feed{Name: "F2"}}}}},
+ {Target: nil, Group: group{Group: "G4",
+ Feeds: []configGroupFeed{{Target: nil, Feed: feed{Name: "F3"}}}}},
}}},
},
- result: Feeds{
- "F0": &Feed{Name: "F0", Target: t("G1.F0")},
- "F1": &Feed{Name: "F1", Target: t("G1.bar.F1")},
- "F2": &Feed{Name: "F2", Target: t("G1.baz")},
- "F3": &Feed{Name: "F3", Target: t("G1.G4.F3")},
+ result: F.Feeds{
+ "F0": &F.Feed{Name: "F0", Target: t("G1.F0")},
+ "F1": &F.Feed{Name: "F1", Target: t("G1.bar.F1")},
+ "F2": &F.Feed{Name: "F2", Target: t("G1.baz")},
+ "F3": &F.Feed{Name: "F3", Target: t("G1.G4.F3")},
},
},
}
for _, tt := range tests {
tst.Run(tt.name, func(tst *testing.T) {
- var feeds Feeds = Feeds{}
+ var feeds F.Feeds = F.Feeds{}
err := buildFeeds(tt.feeds, t(tt.target), feeds)
if (err != nil) != tt.wantErr {
tst.Errorf("buildFeeds() error = %v, wantErr %v", err, tt.wantErr)
@@ -133,13 +136,13 @@ func TestParse(tst *testing.T) {
inp string
wantErr bool
feeds []configGroupFeed
- globalConfig Map
+ globalConfig C.Map
}{
{name: "Empty",
inp: "", wantErr: false, feeds: nil, globalConfig: nil},
{name: "Trash", inp: "Something", wantErr: true},
{name: "Simple config",
- inp: "something: 1\nsomething_else: 2", wantErr: false, feeds: nil, globalConfig: Map{"something": 1, "something_else": 2}},
+ inp: "something: 1\nsomething_else: 2", wantErr: false, feeds: nil, globalConfig: C.Map{"something": 1, "something_else": 2}},
{name: "Config with feed",
inp: `
something: 1
@@ -151,14 +154,15 @@ feeds:
unknown-option: foo
`,
wantErr: false,
- globalConfig: Map{"something": 1},
+ globalConfig: C.Map{"something": 1},
feeds: []configGroupFeed{
- {Target: s("bar"), Feed: Feed{
- Name: "Foo",
- Target: nil,
- Url: "whatever",
- MinFreq: 0,
- InclImages: b(true),
+ {Target: s("bar"), Feed: feed{
+ Name: "Foo",
+ Url: "whatever",
+ Options: C.Options{
+ MinFreq: 0,
+ InclImages: b(true),
+ },
}}}},
{name: "Feeds",
@@ -174,17 +178,21 @@ feeds:
`,
wantErr: false,
feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{
- Name: "Foo",
- Url: "whatever",
- MinFreq: 2,
- InclImages: nil,
+ {Target: nil, Feed: feed{
+ Name: "Foo",
+ Url: "whatever",
+ Options: C.Options{
+ MinFreq: 2,
+ InclImages: nil,
+ },
}},
- {Target: s("bla"), Feed: Feed{
- Name: "Shrubbery",
- Url: "google.de",
- MinFreq: 0,
- InclImages: b(false),
+ {Target: s("bla"), Feed: feed{
+ Name: "Shrubbery",
+ Url: "google.de",
+ Options: C.Options{
+ MinFreq: 0,
+ InclImages: b(false),
+ },
}},
},
},
@@ -195,7 +203,7 @@ feeds:
target: bla
`,
wantErr: false,
- feeds: []configGroupFeed{{Target: s("bla"), Group: Group{"Foo", nil}}},
+ feeds: []configGroupFeed{{Target: s("bla"), Group: group{"Foo", nil}}},
},
{name: "Feeds and Groups",
inp: `
@@ -215,21 +223,21 @@ feeds:
`,
wantErr: false,
feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{
+ {Target: nil, Feed: feed{
Name: "Foo",
Url: "whatever",
}},
- {Target: s("target"), Group: Group{
+ {Target: s("target"), Group: group{
Group: "G1",
Feeds: []configGroupFeed{
- {Target: s(""), Group: Group{
+ {Target: s(""), Group: group{
Group: "G2",
Feeds: []configGroupFeed{
- {Target: nil, Feed: Feed{Name: "F1", Url: "google.de"}},
+ {Target: nil, Feed: feed{Name: "F1", Url: "google.de"}},
}},
},
- {Target: nil, Feed: Feed{Name: "F2"}},
- {Target: nil, Group: Group{Group: "G3"}},
+ {Target: nil, Feed: feed{Name: "F2"}},
+ {Target: nil, Group: group{Group: "G3"}},
}},
},
},
diff --git a/main.go b/main.go
index 373a491..2ce7943 100644
--- a/main.go
+++ b/main.go
@@ -6,10 +6,10 @@ import (
"net/url"
"os"
- "github.com/Necoro/feed2imap-go/internal/config"
"github.com/Necoro/feed2imap-go/internal/feed"
"github.com/Necoro/feed2imap-go/internal/imap"
"github.com/Necoro/feed2imap-go/internal/log"
+ "github.com/Necoro/feed2imap-go/internal/yaml"
)
var cfgFile = flag.String("f", "config.yml", "configuration file")
@@ -22,12 +22,12 @@ func run() error {
log.Print("Starting up...")
log.Printf("Reading configuration file '%s'", *cfgFile)
- cfg, err := config.Load(*cfgFile)
+ cfg, feeds, err := yaml.Load(*cfgFile)
if err != nil {
return err
}
- feed.Parse(cfg.Feeds)
+ feed.Parse(feeds)
imapUrl, err := url.Parse(cfg.GlobalConfig["target"].(string))
if err != nil {