- settings: get filter choices from storage for settings validation - updater: update servers to the storage - storage: minimal deep copying and data duplication - storage: add merged servers mutex for thread safety - connection: filter servers in storage - formatter: format servers to Markdown in storage - PIA: get server by name from storage directly - Updater: get servers count from storage directly - Updater: equality check done in storage, fix #882
104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/qdm12/gluetun/internal/constants"
|
|
"github.com/qdm12/gluetun/internal/constants/providers"
|
|
"github.com/qdm12/gluetun/internal/storage"
|
|
"golang.org/x/text/cases"
|
|
"golang.org/x/text/language"
|
|
)
|
|
|
|
type ServersFormatter interface {
|
|
FormatServers(args []string) error
|
|
}
|
|
|
|
var (
|
|
ErrFormatNotRecognized = errors.New("format is not recognized")
|
|
ErrProviderUnspecified = errors.New("VPN provider to format was not specified")
|
|
ErrMultipleProvidersToFormat = errors.New("more than one VPN provider to format were specified")
|
|
)
|
|
|
|
func addProviderFlag(flagSet *flag.FlagSet, providerToFormat map[string]*bool,
|
|
provider string, titleCaser cases.Caser) {
|
|
boolPtr, ok := providerToFormat[provider]
|
|
if !ok {
|
|
panic(fmt.Sprintf("unknown provider in format map: %s", provider))
|
|
}
|
|
flagSet.BoolVar(boolPtr, provider, false, "Format "+titleCaser.String(provider)+" servers")
|
|
}
|
|
|
|
func (c *CLI) FormatServers(args []string) error {
|
|
var format, output string
|
|
allProviders := providers.All()
|
|
providersToFormat := make(map[string]*bool, len(allProviders))
|
|
for _, provider := range allProviders {
|
|
providersToFormat[provider] = new(bool)
|
|
}
|
|
flagSet := flag.NewFlagSet("markdown", flag.ExitOnError)
|
|
flagSet.StringVar(&format, "format", "markdown", "Format to use which can be: 'markdown'")
|
|
flagSet.StringVar(&output, "output", "/dev/stdout", "Output file to write the formatted data to")
|
|
titleCaser := cases.Title(language.English)
|
|
for _, provider := range allProviders {
|
|
addProviderFlag(flagSet, providersToFormat, provider, titleCaser)
|
|
}
|
|
if err := flagSet.Parse(args); err != nil {
|
|
return err
|
|
}
|
|
|
|
if format != "markdown" {
|
|
return fmt.Errorf("%w: %s", ErrFormatNotRecognized, format)
|
|
}
|
|
|
|
// Verify only one provider is set to be formatted.
|
|
var providers []string
|
|
for provider, formatPtr := range providersToFormat {
|
|
if *formatPtr {
|
|
providers = append(providers, provider)
|
|
}
|
|
}
|
|
switch len(providers) {
|
|
case 0:
|
|
return ErrProviderUnspecified
|
|
case 1:
|
|
default:
|
|
return fmt.Errorf("%w: %d specified: %s",
|
|
ErrMultipleProvidersToFormat, len(providers),
|
|
strings.Join(providers, ", "))
|
|
}
|
|
providerToFormat := providers[0]
|
|
|
|
logger := newNoopLogger()
|
|
storage, err := storage.New(logger, constants.ServersData)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot create servers storage: %w", err)
|
|
}
|
|
|
|
formatted := storage.FormatToMarkdown(providerToFormat)
|
|
|
|
output = filepath.Clean(output)
|
|
file, err := os.OpenFile(output, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot open output file: %w", err)
|
|
}
|
|
|
|
_, err = fmt.Fprint(file, formatted)
|
|
if err != nil {
|
|
_ = file.Close()
|
|
return fmt.Errorf("cannot write to output file: %w", err)
|
|
}
|
|
|
|
err = file.Close()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot close output file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|