Skip to content

Commit

Permalink
Caching the way I should have from the beginning (#11)
Browse files Browse the repository at this point in the history
* Caching the way I should have from the beginning
  • Loading branch information
Shackelford-Arden authored Jul 12, 2024
1 parent b4dbbbf commit 8c3e1a3
Show file tree
Hide file tree
Showing 11 changed files with 527 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changes/unreleased/Added-20240712-115926.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: Added
body: Caching, the way it should have been from the beginning.
time: 2024-07-12T11:59:26.503843-05:00
custom:
Author: Shackelford-Arden
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,28 @@ With this enabled, `hctx` will store credentials when switching between stacks.
This can be helpful when/if you need to quickly switch between two or more stacks, but
don't want to bother with authenticating each time you switch.

_Note: Using `unset` will not cache anything, as it assumes you are no longer using
that stack._
_Note: Using `unset` will cache any token currently set in environment variables._

Preferably, Nomad and Consul CLIs would do the caching for you. If
either implement this in the future, `hctx` will be updated to prefer
those methods over itself.

You can find cache file in `~/.config/hctx/cache.json`.

You can also view the current cache by running:

```shell
hctx cache show
```

#### Cache Management

`hctx` includes a few commands to interact with your cache:

* `cache show`
* `cache clean` - This simply finds stacks that have expired tokens and cleans them out.
* `cache clear` - This removes all cache items.

### Shell Prompts

This section contains information about how one _might_ configure the
Expand Down Expand Up @@ -165,11 +178,6 @@ format = 'hctx [$env_value]($style)'
- Could potentially come into play w/ shell prompt updating
- [x] Add support for stack aliases
- Let daily usage use shorter names where shell prompt updating uses slightly more verbose naming
- [ ] Add `add` command
- **Due to the way HCL itself works, this is not an option while using HCL as the config file.**
- [ ] Add `edit` command
- I'd want to make sure that a user could modify a single attribute of a stack.
- **Due to the way HCL itself works, this is not an option while using HCL as the config file.**

## Maybes

Expand Down Expand Up @@ -201,8 +209,6 @@ such as `nomad` to `hctx` without having to include `hctx run` :eyes:

### Binary Version Management

Boy, brain really starts going nuts if it is allowed, huh?

Name is fairly self-explanatory. Main reason for thinking about this is
there may be times there some environments have version sprawl and
ensuring you are using the same version of the binary as what is in
Expand Down
18 changes: 16 additions & 2 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package cache
import (
"encoding/json"
"fmt"
"os"

"github.com/Shackelford-Arden/hctx/config"
"github.com/Shackelford-Arden/hctx/models"
"os"
)

const FilePerms = os.FileMode(0600)
Expand Down Expand Up @@ -81,7 +82,8 @@ func (c *Cache) Update(stackName string, data models.StackCache) error {
return nil
}

func (c *Cache) Get(stackName string) *models.StackCache {
// GetStack retrieves the cache for the given stack.
func (c *Cache) GetStack(stackName string) *models.StackCache {
var cacheStack *models.StackCache

for name, cache := range *c {
Expand All @@ -94,6 +96,18 @@ func (c *Cache) Get(stackName string) *models.StackCache {
return cacheStack
}

// Get retrieves the full cache blob, typically for displaying.
func (c *Cache) Get() (map[string]models.StackCache, error) {

cache := map[string]models.StackCache{}

for stackName, stackCache := range *c {
cache[stackName] = stackCache
}

return cache, nil
}

func (c *Cache) Save(path string) error {

cp := path
Expand Down
4 changes: 2 additions & 2 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestValidCache(t *testing.T) {
t.Fatal(err)
}

cacheItem := cache.Get("test")
cacheItem := cache.GetStack("test")

if cacheItem == nil {
t.Fatal("cache item is nil when it shouldn't be")
Expand All @@ -72,7 +72,7 @@ func TestMissingCacheItem(t *testing.T) {
t.Fatal(err)
}

cacheItem := cache.Get("fake-test")
cacheItem := cache.GetStack("fake-test")

if cacheItem != nil {
t.Fatal("cached item should be nil, as fake-test should be missing.")
Expand Down
89 changes: 89 additions & 0 deletions cmd/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cmd

import (
"encoding/json"
"fmt"

"github.com/Shackelford-Arden/hctx/cache"
"github.com/Shackelford-Arden/hctx/models"
"github.com/urfave/cli/v2"
)

// CleanCache checks all items in the cache file
// and removes any that have expired or are not valid,
// including stacks that are no longer in the config.
func CleanCache(ctx *cli.Context) error {

newCache := cache.Cache{}
currentCache, err := AppCache.Get()
if err != nil {
return fmt.Errorf("failed to get current cache: %s", err)
}

for stack, stackCache := range currentCache {

// Check if cached stack is in config
configStack := AppConfig.GetStack(stack)
if configStack == nil {
continue
}

cleanCache := models.StackCache{
NomadToken: stackCache.NomadToken,
ConsulToken: stackCache.ConsulToken,
}

// Validate if tokens have expired.
if stackCache.NomadToken != "" && configStack.Nomad != nil {
nomToken := validNomadToken(configStack.Nomad.Address, stackCache.NomadToken)
if !nomToken {
// Remove expired token from cache
cleanCache.NomadToken = ""
}
}

if stackCache.ConsulToken != "" && configStack.Consul != nil {
conToken := validNomadToken(configStack.Consul.Address, stackCache.ConsulToken)
if !conToken {
// Remove expired token from cache
cleanCache.ConsulToken = ""
}
}

newCache[stack] = cleanCache
}

AppCache = &newCache
saveErr := AppCache.Save("")
if saveErr != nil {
return fmt.Errorf("failed to save cache: %s", saveErr)
}

return nil
}

// ClearCache removes all items from the cache file.
func ClearCache(ctx *cli.Context) error {

AppCache = &cache.Cache{}
saveErr := AppCache.Save("")
if saveErr != nil {
return fmt.Errorf("failed to save cleared cache: %s", saveErr)
}

return nil
}

// ShowCache shows the content of the cache file.
func ShowCache(ctx *cli.Context) error {

cache, _ := AppCache.Get()
fmtCache, fmtErr := json.MarshalIndent(cache, "", " ")
if fmtErr != nil {
return fmt.Errorf("failed to read/format the cache: %s", fmtErr.Error())
}

fmt.Println(string(fmtCache))

return nil
}
32 changes: 28 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package cmd

import (
"fmt"
"log/slog"
"os"

"github.com/Shackelford-Arden/hctx/cache"
"github.com/Shackelford-Arden/hctx/config"
"github.com/urfave/cli/v2"
"log/slog"
"os"
)

var AppConfig *config.Config
Expand Down Expand Up @@ -56,13 +57,13 @@ func ValidateConfig(ctx *cli.Context) error {
}

// Get Cache
cache, cacheErr := cache.NewCache("")
cacheItem, cacheErr := cache.NewCache("")
if cacheErr != nil {
return cacheErr
}

AppConfig = cfg
AppCache = cache
AppCache = cacheItem

return nil
}
Expand Down Expand Up @@ -114,6 +115,29 @@ func App() (*cli.App, error) {
Usage: "Used to generate the appropriate shell scripts to set environment variables.",
Args: true,
},
{
Name: "cache",
Aliases: []string{"c"},
Usage: "Interact with the cache.",
Subcommands: []*cli.Command{
{
Name: "show",
Aliases: []string{"s"},
Usage: "ShowCache the current cache",
Action: ShowCache,
},
{
Name: "clear",
Usage: "Clears out the cache of all items.",
Action: ClearCache,
},
{
Name: "clean",
Usage: "Checks all cached items and removes those that have expired.",
Action: CleanCache,
},
},
},
},
}

Expand Down
57 changes: 52 additions & 5 deletions cmd/use.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,69 @@ func Use(ctx *cli.Context) error {
}

currentStack := AppConfig.GetCurrentStack()
// If caching is enabled, set to cache.
// If caching is enabled, cache current stack tokens.
if currentStack != nil && AppConfig.CacheAuth {
currentCache := AppCache.GetStack(currentStack.Name)
toCache := cache.GetCacheableValues()
if toCache.NomadToken != "" {
validToken := validNomadToken(selectedStack.Nomad.Address, toCache.NomadToken)
if validToken {
currentCache.NomadToken = toCache.NomadToken
}
}

if toCache.ConsulToken != "" {
validToken := validConsulToken(selectedStack.Consul.Address, toCache.ConsulToken)
if validToken {
currentCache.ConsulToken = toCache.ConsulToken
}
}
updateErr := AppCache.Update(currentStack.Name, toCache)
if updateErr != nil {
return fmt.Errorf("could not update cache for stack %s: %v", currentStack.Name, updateErr)
}
_ = AppCache.Save("")
}

useOut := unsetTokens(AppConfig.Shell)
var stackCache *models.StackCache
if AppConfig.CacheAuth {
stackCache = AppCache.Get(selectedStack.Name)
currentStackCache := AppCache.GetStack(selectedStack.Name)

// Pull in cache of selected stack, clearing out
// any that are invalid.
if AppConfig.CacheAuth && currentStackCache != nil {

cleanCache := models.StackCache{}

// Validate if tokens have expired.
cleanCache.NomadToken = currentStackCache.NomadToken
if currentStackCache.NomadToken != "" && selectedStack.Nomad != nil {
nomToken := validNomadToken(selectedStack.Nomad.Address, currentStackCache.NomadToken)
if !nomToken {
// Remove expired token from cache
cleanCache.NomadToken = ""
}
}

cleanCache.ConsulToken = currentStackCache.ConsulToken
if currentStackCache.ConsulToken != "" && selectedStack.Consul != nil {
conToken := validConsulToken(selectedStack.Consul.Address, currentStackCache.ConsulToken)
if !conToken {
// Remove expired token from cache
cleanCache.ConsulToken = ""
}
}

err := AppCache.Update(selectedStack.Name, cleanCache)
if err != nil {
return fmt.Errorf("could not update cache for stack %s: %v", selectedStack.Name, err)
}

// Set this so that correct values are pulled in
// later when cached values are pulled in, if enabled
currentStackCache = &cleanCache
}

useOut += selectedStack.Use(AppConfig.Shell, stackCache, AppConfig.CacheAuth)
useOut += selectedStack.Use(AppConfig.Shell, currentStackCache, AppConfig.CacheAuth)

fmt.Println(useOut)

Expand Down
Loading

0 comments on commit 8c3e1a3

Please sign in to comment.