Skip to content

Commit

Permalink
add ENV Vars for Debug & Trace
Browse files Browse the repository at this point in the history
  • Loading branch information
gi8lino committed Dec 19, 2023
1 parent aab0049 commit a51feb6
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 22 deletions.
9 changes: 6 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
"request": "launch",
"mode": "debug",
"program": "main.go",
"env": {
"VIMBIN_THEME": "dark"
,"VIMBIN_DEBUG": "true"
},
"args": [
"--config"
,"./.vimbin.yaml"
,"--trace"
"serve"

]
}
]
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
| Flag | Description |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
| `-c`, `--config` `PATH` | Path to the configuration file. |
| `--debug` | Activates debug output for detailed logging. |
| `--debug` | Activates debug output for detailed logging. Can also be set with the environment variable `VIMBIN_DEBUG` |
| `-t`, `--token` `TOKEN` | Token to use for authentication. If not set, a random token will be generated. Can also be set with the environment variable `VIMBIN_TOKEN` |
| `--trace` | Enables trace mode. This will show the content in the logs! |
| `--trace` | Enables trace mode. This will show the content in the logs! Can also be set with the environment variable `VIMBIN_TRACE` |
| `-v`, `--version` | Print version and exit. |

### Serve
Expand All @@ -28,13 +28,13 @@ Start the server:

**Flags:**

| Flag | Description |
| :-------------------------------------- | :----------------------------------------------------------------------------------------------- |
| `-d`, `--directory` `DIRECTORY` | The path to the storage directory. Defaults to the current working directory. (default `$(pwd)`) |
| `-a`, `--listen-address` `ADDRESS:PORT` | The address to listen on for HTTP requests. (default `:8080`) |
| `-n`, `--name` string | The name of the file to save. (default ".vimbin") |
| `--theme` THEME | The theme to use. Can be `auto`, `light` or `dark`. (default `auto`) |
| `-h`, `--help` | help for serve |
| Flag | Description |
| :-------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
| `-d`, `--directory` `DIRECTORY` | The path to the storage directory. (default `$(pwd)`) |
| `-a`, `--listen-address` `ADDRESS:PORT` | The address to listen on for HTTP requests. (default `:8080`) |
| `-n`, `--name` string | The name of the file to save. (default ".vimbin") |
| `--theme` THEME | The theme to use. Can be `auto`, `light` or `dark`. (default `auto`). Can also be set with the environment variable `VIMBIN_THEME` |
| `-h`, `--help` | help for serve |

### Push

Expand Down
15 changes: 13 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"
"time"
"vimbin/internal/config"
"vimbin/internal/utils"

"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -67,14 +68,23 @@ var rootCmd = &cobra.Command{
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}
log.Logger = zerolog.New(output).With().Timestamp().Logger()

// Configure log levels based on debug and trace flags
// Retrieve debug and trace flags from environment variables if not explicitly set
if !debug || !trace {
var err error
if debug, trace, err = utils.GetDebugAndTrace(); err != nil {
log.Fatal().Msgf("Failed to retrieve debug and trace flags. %s", err)
}
}

// Set the log level
if debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
log.Debug().Msgf("Verbose output enabled")
} else if trace {
zerolog.SetGlobalLevel(zerolog.TraceLevel)
log.Debug().Msgf("Trace output enabled")
}

if token := cmd.Flag("token").Value.String(); token != "" {
config.App.Server.Api.Token.Set(token)
}
Expand Down Expand Up @@ -116,10 +126,11 @@ func init() {

// initConfig reads the configuration from the specified file or environment variables.
func initConfig() {
viper.AutomaticEnv() // Read in environment variables that match

if cfgFile != "" {
// Use the config file specified by the flag.
viper.SetConfigFile(cfgFile)
viper.AutomaticEnv() // Read in environment variables that match

if err := config.App.Read(viper.ConfigFileUsed()); err != nil {
log.Fatal().Msgf("Error reading config file: %v", err)
Expand Down
12 changes: 4 additions & 8 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package cmd
import (
"fmt"
"os"
"strings"
"text/template"
"vimbin/internal/config"
"vimbin/internal/handlers"
Expand All @@ -30,9 +29,6 @@ import (
"github.com/spf13/cobra"
)

// supportedThemes is a list of themes supported by the serve command.
var supportedThemes = []string{"auto", "light", "dark"}

// serveCmd represents the serve command.
var serveCmd = &cobra.Command{
Use: "serve",
Expand All @@ -42,8 +38,8 @@ var serveCmd = &cobra.Command{
manipulate text using familiar Vim motions for an enhanced editing experience.`,
Run: func(cmd *cobra.Command, args []string) {
// Check if the specified theme is supported
if !utils.IsInList(config.App.Server.Web.Theme, supportedThemes) {
fmt.Printf("Unsupported output format: %s. Supported formats are: %s\n", config.App.Server.Web.Theme, strings.Join(supportedThemes, ", "))
if !utils.IsInList(config.App.Server.Web.Theme, config.SupportedThemes) {
fmt.Printf("Unsupported output format: %s. Supported formats are: %s\n", config.App.Server.Web.Theme, config.SupportedThemes)
_ = cmd.Help() // Makes the linter happy
os.Exit(1)
}
Expand Down Expand Up @@ -74,9 +70,9 @@ func init() {
// Define command-line flags for the serve command
serveCmd.PersistentFlags().StringVarP(&config.App.Server.Web.Address, "listen-address", "a", ":8080", "The address to listen on for HTTP requests.")

serveCmd.PersistentFlags().StringVarP(&config.App.Server.Web.Theme, "theme", "", "auto", fmt.Sprintf("The theme to use. Can be %s.", strings.Join(supportedThemes, "|")))
serveCmd.PersistentFlags().StringVarP(&config.App.Server.Web.Theme, "theme", "", "auto", fmt.Sprintf("The theme to use. Can be %s.", config.SupportedThemes))
serveCmd.RegisterFlagCompletionFunc("theme", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return supportedThemes, cobra.ShellCompDirectiveDefault
return config.SupportedThemes, cobra.ShellCompDirectiveDefault
})

serveCmd.PersistentFlags().StringVarP(&config.App.Storage.Directory, "directory", "d", "$(pwd)", "The path to the storage directory. Defaults to the current working directory.")
Expand Down
10 changes: 10 additions & 0 deletions internal/config/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (c *Config) Parse() (err error) {
// Check if the API token was set as ENV variable
if token := os.Getenv("VIMBIN_TOKEN"); token != "" {
c.Server.Api.Token.Set(token)
log.Debug().Msgf("Using API token from ENV variable: %s", token)
}

// Check if the API token is valid
Expand All @@ -63,5 +64,14 @@ func (c *Config) Parse() (err error) {
log.Debug().Msgf("Generated API token: %s", c.Server.Api.Token.Get())
}

// Check if the theme was set as ENV variable
if theme := os.Getenv("VIMBIN_THEME"); theme != "" {
if !utils.IsInList(theme, SupportedThemes) {
return fmt.Errorf("Unsupported theme: %s. Supported themes are: %s", theme, SupportedThemes)
}
c.Server.Web.Theme = theme
log.Debug().Msgf("Using theme from ENV variable: %s", theme)
}

return nil
}
12 changes: 12 additions & 0 deletions internal/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"reflect"
"strings"

"github.com/mitchellh/mapstructure"
"github.com/rs/zerolog/log"
Expand All @@ -29,6 +30,17 @@ return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
}
`

// Themes is a list of themes supported by the serve command.
type Themes []string

// SupportedThemes is a list of themes supported by the serve command.
var SupportedThemes = Themes{"auto", "light", "dark"}

// String returns the list of themes as a string.
func (t Themes) String() string {
return strings.Join(t, ", ")
}

// checkStorageFile checks if the storage file exists; if not, it creates it with default content.
//
// Parameters:
Expand Down
45 changes: 45 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,54 @@ import (
"fmt"
"net"
"net/http"
"os"
"strconv"
)

// Environment variable names
const (
VIMBINDebugEnv = "VIMBIN_DEBUG"
VIMBINTraceEnv = "VIMBIN_TRACE"
)

// GetDebugAndTrace retrieves the debug and trace flags from environment variables.
//
// The function checks the "VIMBIN_DEBUG" and "VIMBIN_TRACE" environment variables,
// parses their values, and returns the corresponding boolean flags.
//
// Returns:
// - debug: bool
// True if "VIMBIN_DEBUG" is set to "true", false otherwise.
// - trace: bool
// True if "VIMBIN_TRACE" is set to "true", false otherwise.
// - err: error
// An error if there was an issue parsing the environment variables or if
// both "VIMBIN_DEBUG" and "VIMBIN_TRACE" are set simultaneously.
func GetDebugAndTrace() (debug bool, trace bool, err error) {
// Check and parse VIMBIN_DEBUG environment variable
if debugEnv := os.Getenv(VIMBINDebugEnv); debugEnv != "" {
debug, err = strconv.ParseBool(debugEnv)
if err != nil {
return false, false, fmt.Errorf("Unable to parse '%s'. %s", VIMBINDebugEnv, err)
}
}

// Check and parse VIMBIN_TRACE environment variable
if traceEnv := os.Getenv(VIMBINTraceEnv); traceEnv != "" {
trace, err = strconv.ParseBool(traceEnv)
if err != nil {
return false, false, fmt.Errorf("Unable to parse '%s'. %s", VIMBINTraceEnv, err)
}
}

// Check for mutual exclusivity of debug and trace
if debug && trace {
return false, false, fmt.Errorf("'%s' and '%s' are mutually exclusive", VIMBINDebugEnv, VIMBINTraceEnv)
}

return debug, trace, nil
}

// IsInList checks if a value is in a list.
//
// Parameters:
Expand Down
73 changes: 73 additions & 0 deletions internal/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,82 @@ package utils

import (
"net/http"
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetDebugAndTrace(t *testing.T) {
t.Run("Both debug and trace are set", func(t *testing.T) {
os.Setenv(VIMBINDebugEnv, "true")
os.Setenv(VIMBINTraceEnv, "true")
defer os.Unsetenv(VIMBINDebugEnv)
defer os.Unsetenv(VIMBINTraceEnv)

debug, trace, err := GetDebugAndTrace()

assert.False(t, debug)
assert.False(t, trace)
assert.Error(t, err)
assert.Contains(t, err.Error(), "'VIMBIN_DEBUG' and 'VIMBIN_TRACE' are mutually exclusive")
})

t.Run("Invalid debug value", func(t *testing.T) {
os.Setenv(VIMBINDebugEnv, "invalid")
defer os.Unsetenv(VIMBINDebugEnv)

debug, trace, err := GetDebugAndTrace()

assert.False(t, debug)
assert.False(t, trace)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Unable to parse 'VIMBIN_DEBUG'")
})

t.Run("Invalid trace value", func(t *testing.T) {
os.Setenv(VIMBINTraceEnv, "invalid")
defer os.Unsetenv(VIMBINTraceEnv)

debug, trace, err := GetDebugAndTrace()

assert.False(t, debug)
assert.False(t, trace)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Unable to parse 'VIMBIN_TRACE'")
})

t.Run("Debug is set", func(t *testing.T) {
os.Setenv(VIMBINDebugEnv, "true")
defer os.Unsetenv(VIMBINDebugEnv)

debug, trace, err := GetDebugAndTrace()

assert.True(t, debug)
assert.False(t, trace)
assert.NoError(t, err)
})

t.Run("Trace is set", func(t *testing.T) {
os.Setenv(VIMBINTraceEnv, "true")
defer os.Unsetenv(VIMBINTraceEnv)

debug, trace, err := GetDebugAndTrace()

assert.False(t, debug)
assert.True(t, trace)
assert.NoError(t, err)
})

t.Run("Neither debug nor trace is set", func(t *testing.T) {
debug, trace, err := GetDebugAndTrace()

assert.False(t, debug)
assert.False(t, trace)
assert.NoError(t, err)
})
}

func TestIsInList(t *testing.T) {
t.Run("Value is in the list", func(t *testing.T) {
value := "apple"
Expand Down Expand Up @@ -53,6 +124,7 @@ func TestExtractHostAndPort(t *testing.T) {
_, _, err := ExtractHostAndPort(address)

assert.Error(t, err)
assert.Contains(t, err.Error(), "missing port in address")
})

t.Run("Invalid port", func(t *testing.T) {
Expand All @@ -61,6 +133,7 @@ func TestExtractHostAndPort(t *testing.T) {
_, _, err := ExtractHostAndPort(address)

assert.Error(t, err)
assert.Contains(t, err.Error(), "parsing \"invalid\"")
})
}

Expand Down

0 comments on commit a51feb6

Please sign in to comment.