Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor core #154

Merged
merged 2 commits into from Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
24 changes: 17 additions & 7 deletions core/factory/default.go
Expand Up @@ -2,20 +2,30 @@ package factory

import (
"fmt"
"os"

"github.com/aerogear/charmil/core/config"
"github.com/aerogear/charmil/core/debug"
"github.com/aerogear/charmil/core/iostreams"
"github.com/aerogear/charmil/core/localize"
"github.com/aerogear/charmil/core/logging"
)

// Default creates new instance of factory for plugins
func Default(localizer localize.Localizer, cfgHandler *config.CfgHandler) *Factory {
func Default(localizer localize.Localizer) *Factory {
io := iostreams.System()

var logger logging.Logger
// initializing logger
loggerFunc := func() (logging.Logger, error) {
if logger != nil {
return logger, nil
}

loggerBuilder := logging.NewStdLoggerBuilder()
loggerBuilder = loggerBuilder.Streams(os.Stdout, os.Stdin)
loggerBuilder = loggerBuilder.Streams(io.Out, io.ErrOut)

debugEnabled := debug.Enabled()
loggerBuilder = loggerBuilder.Debug(debugEnabled)

logger, err := loggerBuilder.Build()
if err != nil {
return nil, err
Expand All @@ -31,8 +41,8 @@ func Default(localizer localize.Localizer, cfgHandler *config.CfgHandler) *Facto
}

return &Factory{
Logger: logger,
Localizer: localizer,
CfgHandler: cfgHandler,
IOStreams: io,
Logger: logger,
Localizer: localizer,
}
}
3 changes: 3 additions & 0 deletions core/factory/factory.go
Expand Up @@ -2,13 +2,16 @@ package factory

import (
"github.com/aerogear/charmil/core/config"
"github.com/aerogear/charmil/core/iostreams"
"github.com/aerogear/charmil/core/localize"
"github.com/aerogear/charmil/core/logging"
)

// Factory is an abstract type which provides
// the access of charmil packages to the commands
type Factory struct {
// Type which defines the streams for the CLI
IOStreams *iostreams.IOStreams
// Logger provides functions for unified logging
Logger logging.Logger
// Localizer localizes the text in commands
Expand Down
File renamed without changes.
@@ -1,7 +1,7 @@
package flag

import (
flagutil "github.com/aerogear/charmil/pkg/cmdutil/flags"
flagutil "github.com/aerogear/charmil/core/cmdutil/flags"
)

// ValidOutput checks if value v is a valid value for --output
Expand Down
File renamed without changes.
87 changes: 58 additions & 29 deletions core/localize/i18n.go
Expand Up @@ -2,7 +2,8 @@ package localize

import (
"encoding/json"
"errors"
"fmt"
"io/fs"

"github.com/BurntSushi/toml"
"github.com/nicksnyder/go-i18n/v2/i18n"
Expand All @@ -15,6 +16,7 @@ import (
// GoI18n is a type which
// stores the details to create bundle
type GoI18n struct {
files fs.FS
language *language.Tag
bundle *i18n.Bundle
Localizer *i18n.Localizer
Expand All @@ -25,7 +27,8 @@ type GoI18n struct {
// Config is a type which helps to get the
// information to initialize the localizer
type Config struct {
Language language.Tag
Files fs.FS
Language *language.Tag
Path string
Format string
}
Expand All @@ -46,41 +49,67 @@ func (i *GoI18n) LocalizeByID(messageId string, template ...*TemplateEntry) stri
return res
}

// InitLocalizer initialize the localizer
// and create new instance for plugin
// Pass Config including lang, path & format of locals
func InitLocalizer(cfg Config) (*GoI18n, error) {

// create bundle of choose language
bundle := i18n.NewBundle(cfg.Language)
var unmarshalFunc i18n.UnmarshalFunc

// choose unmarshal func according to format of local
switch cfg.Format {
case "toml":
unmarshalFunc = toml.Unmarshal
case "json":
unmarshalFunc = json.Unmarshal
case "yaml":
unmarshalFunc = yaml.Unmarshal
default:
return nil, errors.New("unsupported format of local file " + cfg.Format)
func New(cfg *Config) (Localizer, error) {
if cfg == nil {
cfg = &Config{}
}

// load translations during initialization
bundle.RegisterUnmarshalFunc(cfg.Format, unmarshalFunc)
_, err := bundle.LoadMessageFile(cfg.Path)
if err != nil {
return nil, err
if cfg.Format == "" {
cfg.Format = "toml"
}

bundle := i18n.NewBundle(*cfg.Language)
loc := &GoI18n{
language: &cfg.Language,
files: cfg.Files,
language: cfg.Language,
bundle: bundle,
Localizer: i18n.NewLocalizer(bundle),
format: cfg.Format,
path: cfg.Path,
Localizer: i18n.NewLocalizer(bundle),
}

return loc, nil
err := loc.load()
return loc, err
}

// walk the file system and load each file into memory
func (i *GoI18n) load() error {
// localesRoot := filepath.Join(i.path, i.language.String())
return fs.WalkDir(i.files, ".", func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}

if info.IsDir() {
return nil
}

return i.MustLocalizeFile(i.files, path)
})
}

// read the message file from the file system
func (i *GoI18n) MustLocalizeFile(files fs.FS, path string) (err error) {
// open the static i18n file
buf, err := fs.ReadFile(files, path)
if err != nil {
return err
}
fileext := fmt.Sprintf("%v.%v", i.language.String(), i.format)
var unmarshalFunc i18n.UnmarshalFunc
switch i.format {
case "toml":
unmarshalFunc = toml.Unmarshal
case "yaml", "yml":
unmarshalFunc = yaml.Unmarshal
case "json":
unmarshalFunc = json.Unmarshal
default:
return fmt.Errorf("unsupported format \"%v\"", i.format)
}

i.bundle.RegisterUnmarshalFunc(i.format, unmarshalFunc)
_, err = i.bundle.ParseMessageFileBytes(buf, fileext)

return
}
9 changes: 9 additions & 0 deletions core/logging/logger.go
Expand Up @@ -2,16 +2,25 @@ package logging

// Logger is an Interface for logging messages in unified way
type Logger interface {

// DebugEnabled returns true if the debug level is enabled.
DebugEnabled() bool

// InfoEnabled returns true if the information level is enabled.
InfoEnabled() bool

// Info prints an formatted output message
// using fmt.Fprint function
Info(args ...interface{})

// Error prints an formatted error message
// using fmt.Fprint function
Error(args ...interface{})

// Infof prints an formatted output message
// using fmt.Fprintf function
Infof(format string, args ...interface{})

// Errorf prints an formatted error message
// using fmt.Fprintf function
Errorf(format string, args ...interface{})
Expand Down
59 changes: 54 additions & 5 deletions core/logging/std_logger.go
Expand Up @@ -12,20 +12,33 @@ import (
// the configuration to build the logger which uses
// standard output and error streams or custom writers
type StdLoggerBuilder struct {
outStream io.Writer
errStream io.Writer
debugEnabled bool
infoEnabled bool
errorEnabled bool
outStream io.Writer
errStream io.Writer
}

// StdLogger is a type of logger which uses
// standard output and error streams, or custom writers
type StdLogger struct {
outStream io.Writer
errStream io.Writer
debugEnabled bool
infoEnabled bool
errorEnabled bool
outStream io.Writer
errStream io.Writer
}

// NewStdLoggerBuilder returns new StdLoggerBuilder object
func NewStdLoggerBuilder() *StdLoggerBuilder {
// Allocate the object:
builder := new(StdLoggerBuilder)

// Set default values:
builder.debugEnabled = false
builder.infoEnabled = true
builder.errorEnabled = true

return builder
}

Expand All @@ -36,10 +49,47 @@ func (b *StdLoggerBuilder) Streams(out io.Writer, err io.Writer) *StdLoggerBuild
return b
}

// Debug enables or disables the debug level.
func (b *StdLoggerBuilder) Debug(flag bool) *StdLoggerBuilder {
b.debugEnabled = flag
return b
}

// Info enables or disables the information level.
func (b *StdLoggerBuilder) Info(flag bool) *StdLoggerBuilder {
b.infoEnabled = flag
return b
}

// Error enables or disables the error level.
func (b *StdLoggerBuilder) Error(flag bool) *StdLoggerBuilder {
b.errorEnabled = flag
return b
}

// DebugEnabled returns true iff the debug level is enabled.
func (l *StdLogger) DebugEnabled() bool {
return l.debugEnabled
}

// InfoEnabled returns true iff the information level is enabled.
func (l *StdLogger) InfoEnabled() bool {
return l.infoEnabled
}

// ErrorEnabled returns true iff the error level is enabled.
func (l *StdLogger) ErrorEnabled() bool {
return l.errorEnabled
}

// Build creates a new logger instance
// with configuration stored in builder
func (b *StdLoggerBuilder) Build() (logger *StdLogger, err error) {
// Allocate and populate the object:
logger = new(StdLogger)
logger.debugEnabled = b.debugEnabled
logger.infoEnabled = b.infoEnabled
logger.errorEnabled = b.errorEnabled
logger.outStream = b.outStream
logger.errStream = b.errStream
if logger.outStream == nil {
Expand All @@ -48,7 +98,6 @@ func (b *StdLoggerBuilder) Build() (logger *StdLogger, err error) {
if logger.errStream == nil {
logger.errStream = os.Stderr
}

return
}

Expand Down
13 changes: 11 additions & 2 deletions examples/host/config.json
@@ -1,5 +1,14 @@
{
"Key1": "val1",
"Key2": "val2",
"Key3": "val3"
}
"Key3": "val3",
"Key4": "val4",
"Plugins": {
"adder": {
"Key5": "val5",
"Key6": "val6",
"Key7": "val7",
"Key8": "val8"
}
}
}
4 changes: 2 additions & 2 deletions examples/host/main.go
Expand Up @@ -55,15 +55,15 @@ func init() {
}

// Creates a new factory instance with default settings
cmdFactory = factory.Default(nil, h)
cmdFactory = factory.Default(nil)
}

func main() {
// Sets a value into config
cfg.Key4 = "val4"

// Add plugin CLI into host
echoCmd, err := echo.EchoCommand(cmdFactory)
echoCmd, err := echo.EchoCommand()
if err != nil {
log.Fatal(err)
}
Expand Down
13 changes: 10 additions & 3 deletions examples/plugins/adder/main.go
@@ -1,6 +1,7 @@
package adder

import (
"embed"
"log"
"strconv"

Expand All @@ -11,6 +12,11 @@ import (
"golang.org/x/text/language"
)

var (
//go:embed locales
defaultLocales embed.FS
)

// Defines the configuration keys of the plugin.
//
// CONSTRAINT: All fields of the config struct need to be exportable
Expand All @@ -26,14 +32,15 @@ var cfg = &config{}
func AdderCommand(f *factory.Factory) (*cobra.Command, error) {

// Stores the config for localizer
cfg.LocConfig = localize.Config{
Language: language.English,
locConfig := localize.Config{
Language: &language.English,
Files: defaultLocales,
Path: "examples/plugins/adder/locales/en/adder.en.yaml",
Format: "yaml",
}

// Initializes the localizer by passing config
loc, err := localize.InitLocalizer(cfg.LocConfig)
loc, err := localize.New(&locConfig)
if err != nil {
return nil, err
}
Expand Down