diff --git a/Makefile b/Makefile index c95d3a4..e68f3b7 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ sqlite: vhs: docker run --rm -v $PWD:/vhs ghcr.io/charmbracelet/vhs .github/demo.tape +backends: + docker-compose -f backends-compose.yml up # Copied from https://github.com/goreleaser/goreleaser-cross-example/blob/master/Makefile PACKAGE_NAME := github.com/guyfedwards/nom diff --git a/README.md b/README.md index 566c352..ce1630b 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,26 @@ ![](./.github/demo.gif) +## Migrating to V3 +**NOTE** When upgrading to V3 if you are using `config.backends` for Miniflux or FreshRSS support, you will need to update your config to be arrays. + ## Install See [releases](https://github.com/guyfedwards/nom/releases) for binaries. E.g. ```sh -curl -L https://github.com/guyfedwards/nom/releases/download/v2.16.2/nom_2.16.2_darwin_amd64.tar.gz | tar -xzvf - +curl -L https://github.com/guyfedwards/nom/releases/download/v3.0.0/nom_3.0.0_darwin_amd64.tar.gz | tar -xzvf - ``` To install the `nom` binary into `/usr/local/bin` (or into the location of your choice) in a single step: ```sh -curl -L https://github.com/guyfedwards/nom/releases/download/v2.16.2/nom_2.16.2_darwin_amd64.tar.gz | - sudo tar -C /usr/local/bin -xvzf - nom +curl -L https://github.com/guyfedwards/nom/releases/download/v3.0.0/nom_3.0.0_darwin_amd64.tar.gz | +sudo tar -C /usr/local/bin -xvzf - nom +``` + +```sh +nom -c my-custom-config.yml ``` ## Usage @@ -34,14 +41,6 @@ nom add nom -h # see all available command and options ``` -## Configuration - -Configuration lives by default in `$XDG_CONFIG_HOME/nom/config.yml` or `$HOME/Library/Application Support/nom/config.yml` on darwin. You can customise the location of the configuration file with the `--config-path` (`-c`) flag: - -```sh -nom -c my-custom-config.yml -``` - ### Feeds Feeds are listed in the `feeds` section of the configuration file. They have a URL, an option name, and an optional list of tags: @@ -146,13 +145,15 @@ As well as adding feeds directly, you can pull in feeds from another source. You ```yaml backends: miniflux: - host: http://myminiflux.foo - api_key: jafksdljfladjfk + - host: http://myminiflux.foo + api_key: jafksdljfladjfk + - host: http://yourminiflux.foo + api_key: adfhdlsajfsifdi freshrss: - host: http://myfreshrss.bar - user: admin - password: muchstrong - prefixCats: true # prefix feed name for freshrss entries + - host: http://myfreshrss.bar + user: admin + password: muchstrong + prefixCats: true # prefix feed name for freshrss entries ``` #### FreshRSS diff --git a/backends-compose.yml b/backends-compose.yml index 44df71e..22d2d35 100644 --- a/backends-compose.yml +++ b/backends-compose.yml @@ -8,6 +8,23 @@ services: - db environment: - DATABASE_URL=postgres://miniflux:secret@db:5432/miniflux?sslmode=disable + - RUN_MIGRATIONS=1 + - CREATE_ADMIN=1 + - ADMIN_USERNAME=admin + - ADMIN_PASSWORD=miniflux + + miniflux2: + image: miniflux/miniflux:latest + ports: + - "8085:8080" + depends_on: + - db2 + environment: + - DATABASE_URL=postgres://miniflux:secret@db2:5432/miniflux?sslmode=disable + - RUN_MIGRATIONS=1 + - CREATE_ADMIN=1 + - ADMIN_USERNAME=admin + - ADMIN_PASSWORD=miniflux db: image: postgres:15 @@ -21,6 +38,18 @@ services: interval: 10s start_period: 30s + db2: + image: postgres:15 + environment: + - POSTGRES_USER=miniflux + - POSTGRES_PASSWORD=secret + volumes: + - miniflux-db2:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "miniflux"] + interval: 10s + start_period: 30s + freshrss: image: freshrss/freshrss container_name: freshrss @@ -36,7 +65,23 @@ services: ports: - "8081:80" + freshrss2: + image: freshrss/freshrss + container_name: freshrss2 + hostname: freshrss2 + restart: unless-stopped + environment: + TZ: Europe/Paris + CRON_MIN: '3,33' + FRESHRSS_ENV: development + ADMIN_EMAIL: admin@example.net + ADMIN_PASSWORD: freshrss + ADMIN_API_PASSWORD: freshrss + ports: + - "8082:80" + volumes: miniflux-db: + miniflux-db2: data: extensions: diff --git a/cmd/nom/main.go b/cmd/nom/main.go index 8909d28..e9290d7 100755 --- a/cmd/nom/main.go +++ b/cmd/nom/main.go @@ -126,15 +126,18 @@ func getCmds() (*commands.Commands, error) { if err = cfg.Load(); err != nil { return nil, err } + var s store.Store if cfg.IsPreviewMode() { s, err = store.NewInMemorySQLiteStore() } else { s, err = store.NewSQLiteStore(cfg.ConfigDir, cfg.Database) } + if err != nil { return nil, fmt.Errorf("main.go: %w", err) } + cmds := commands.New(cfg, s) return cmds, nil } diff --git a/internal/config/backends.go b/internal/config/backends.go index a6b7847..feaa925 100644 --- a/internal/config/backends.go +++ b/internal/config/backends.go @@ -24,8 +24,8 @@ type FreshRSSBackend struct { } type Backends struct { - Miniflux *MinifluxBackend `yaml:"miniflux,omitempty"` - FreshRSS *FreshRSSBackend `yaml:"freshrss,omitempty"` + Miniflux []MinifluxBackend `yaml:"miniflux,omitempty"` + FreshRSS []FreshRSSBackend `yaml:"freshrss,omitempty"` } func (mfb *MinifluxBackend) GetFeeds() ([]Feed, error) { diff --git a/internal/config/config.go b/internal/config/config.go index ec7dc75..272d5b2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "gopkg.in/yaml.v3" @@ -14,6 +15,7 @@ import ( var ( ErrFeedAlreadyExists = errors.New("config.AddFeed: feed already exists") + ErrOutdatedConfigV3 = errors.New("outdated config, see docs for v3 changes") DefaultConfigDirName = "nom" DefaultConfigFileName = "config.yml" DefaultDatabaseName = "nom.db" @@ -161,7 +163,11 @@ func (c *Config) Load() error { var fileConfig Config err = yaml.Unmarshal(rawData, &fileConfig) if err != nil { - return fmt.Errorf("config.Read: %w", err) + if isBackendArrayError(err) { + return ErrOutdatedConfigV3 + } + + return fmt.Errorf("config.Load: %w", err) } c.ShowRead = fileConfig.ShowRead @@ -217,22 +223,26 @@ func (c *Config) Load() error { } if fileConfig.Backends != nil { - if fileConfig.Backends.Miniflux != nil { - mffeeds, err := fileConfig.Backends.Miniflux.GetFeeds() - if err != nil { - return err + if len(fileConfig.Backends.Miniflux) > 0 { + for _, be := range fileConfig.Backends.Miniflux { + mffeeds, err := be.GetFeeds() + if err != nil { + return err + } + + c.Feeds = append(c.Feeds, mffeeds...) } - - c.Feeds = append(c.Feeds, mffeeds...) } - if fileConfig.Backends.FreshRSS != nil { - freshfeeds, err := fileConfig.Backends.FreshRSS.GetFeeds() - if err != nil { - return err - } + if len(fileConfig.Backends.FreshRSS) > 0 { + for _, be := range fileConfig.Backends.FreshRSS { + freshfeeds, err := be.GetFeeds() + if err != nil { + return err + } - c.Feeds = append(c.Feeds, freshfeeds...) + c.Feeds = append(c.Feeds, freshfeeds...) + } } } @@ -315,3 +325,11 @@ func (c *Config) ImportFeeds() ([]Feed, error) { return nil, nil } + +const errorPrefix = "cannot unmarshal !!map into " + +// somewhat hacky check for a parsing error on the config.backends node +func isBackendArrayError(e error) bool { + return strings.Contains(e.Error(), errorPrefix+"[]config.FreshRSSBackend") || + strings.Contains(e.Error(), errorPrefix+"[]config.MinifluxBackend") +}