-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathimport_cmd.go
119 lines (93 loc) · 2.67 KB
/
import_cmd.go
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
//
// Import an OPML feedlist.
//
package main
import (
"encoding/xml"
"flag"
"log/slog"
"os"
"github.com/skx/rss2email/configfile"
"github.com/skx/subcommands"
)
type opml struct {
XMLName xml.Name `xml:"opml"`
Version string `xml:"version,attr"`
OpmlTitle string `xml:"head>title"`
Outlines []outline `xml:"body>outline"`
}
type outline struct {
Text string `xml:"text,attr"`
Title string `xml:"title,attr"`
Type string `xml:"type,attr"`
XMLURL string `xml:"xmlUrl,attr"`
HTMLURL string `xml:"htmlUrl,attr"`
Favicon string `xml:"rssfr-favicon,attr"`
}
// Structure for our options and state.
type importCmd struct {
// We embed the NoFlags option, because we accept no command-line flags.
subcommands.NoFlags
// Configuration file, used for testing
config *configfile.ConfigFile
}
// Info is part of the subcommand-API
func (i *importCmd) Info() (string, string) {
return "import", `Import a list of feeds via an OPML file.
This command imports a series of feeds from the specified OPML
file into the configuration file this application uses.
To see details of the configuration file, including the location,
please run:
$ rss2email help config
Example:
$ rss2email import file1.opml file2.opml .. fileN.opml
`
}
// Arguments handles argument-flags we might have.
//
// In our case we use this as a hook to setup our configuration-file,
// which allows testing.
func (i *importCmd) Arguments(flags *flag.FlagSet) {
i.config = configfile.New()
}
// Execute is invoked if the user specifies `import` as the subcommand.
func (i *importCmd) Execute(args []string) int {
_, err := i.config.Parse()
if err != nil {
logger.Error("failed to parse configuration file",
slog.String("configfile", i.config.Path()),
slog.String("error", err.Error()))
return 1
}
// For each file on the command-line
for _, file := range args {
// Read content
var data []byte
data, err = os.ReadFile(file)
if err != nil {
logger.Warn("failed to read file", slog.String("file", file), slog.String("error", err.Error()))
continue
}
// Parse
o := opml{}
err = xml.Unmarshal(data, &o)
if err != nil {
logger.Warn("failed to parse XML file", slog.String("file", file), slog.String("error", err.Error()))
continue
}
for _, outline := range o.Outlines {
if outline.XMLURL != "" {
logger.Debug("Adding entry from file", slog.String("file", file), slog.String("url", outline.XMLURL))
i.config.Add(outline.XMLURL)
}
}
}
// Did we make a change? Then add them.
err = i.config.Save()
if err != nil {
logger.Error("failed to save the updated feed list", slog.String("error", err.Error()))
return 1
}
// All done.
return 0
}