Files
kmanage/cmd/helper_completion.go
T

198 lines
4.8 KiB
Go

package cmd
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"time"
"kmanage/pkg/komodo"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
type completionCache struct {
Timestamp time.Time `json:"timestamp"`
Repos []string `json:"repos"`
Owners []string `json:"owners"`
Stacks []string `json:"stacks"`
Accounts []string `json:"accounts"`
}
func getCachePath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".kmanage_cache.json"), nil
}
func loadCache() *completionCache {
path, err := getCachePath()
if err != nil {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var cache completionCache
if err := json.Unmarshal(data, &cache); err != nil {
return nil
}
// Cache TTL is 3 minutes
if time.Since(cache.Timestamp) > 3*time.Minute {
return nil
}
return &cache
}
func saveCache(cache *completionCache) {
path, err := getCachePath()
if err != nil {
return
}
cache.Timestamp = time.Now()
data, _ := json.Marshal(cache)
_ = os.WriteFile(path, data, 0600)
}
// completeGitAccountNames provides dynamic auto-completion for configured Git account names.
func completeGitAccountNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
cfg, err := LoadAppConfig()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var accounts []string
for k := range cfg.GitAccounts {
accounts = append(accounts, k)
}
return filterCompletions(accounts, toComplete), cobra.ShellCompDirectiveNoFileComp
}
// completeRepoNames dynamically suggests repository names for Cobra auto-completion.
func completeRepoNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) > 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
cached := loadCache()
if cached != nil && len(cached.Repos) > 0 {
return filterCompletions(cached.Repos, toComplete), cobra.ShellCompDirectiveNoFileComp
}
accountFlag, _ := cmd.Flags().GetString("account")
allAccountsFlag, _ := cmd.Flags().GetBool("all-accounts")
clients, err := getSelectedGitClients(accountFlag, allAccountsFlag)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var repoNames []string
ownerMap := make(map[string]bool)
for _, client := range clients {
repos, err := client.ListRepositories()
if err != nil {
continue
}
for _, r := range repos {
repoNames = append(repoNames, r.FullName)
owner := r.Owner.UserName
if owner == "" && strings.Contains(r.FullName, "/") {
owner = strings.SplitN(r.FullName, "/", 2)[0]
}
if owner != "" {
ownerMap[owner] = true
}
}
}
var ownerNames []string
for o := range ownerMap {
ownerNames = append(ownerNames, o)
}
cfg, _ := LoadAppConfig()
var accountNames []string
if cfg != nil {
for a := range cfg.GitAccounts {
accountNames = append(accountNames, a)
}
}
saveCache(&completionCache{
Repos: repoNames,
Owners: ownerNames,
Accounts: accountNames,
})
return filterCompletions(repoNames, toComplete), cobra.ShellCompDirectiveNoFileComp
}
// completeOwnerNames dynamically suggests repository owner/organization names.
func completeOwnerNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
cached := loadCache()
if cached != nil && len(cached.Owners) > 0 {
return filterCompletions(cached.Owners, toComplete), cobra.ShellCompDirectiveNoFileComp
}
_, _ = completeRepoNames(cmd, args, toComplete)
cached = loadCache()
if cached != nil {
return filterCompletions(cached.Owners, toComplete), cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveNoFileComp
}
// completeStackNames dynamically suggests stack names from Komodo.
func completeStackNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
client, err := getKomodoClient()
if err != nil {
url := viper.GetString("komodo_url")
key := viper.GetString("komodo_key")
secret := viper.GetString("komodo_secret")
if url == "" || key == "" || secret == "" {
return nil, cobra.ShellCompDirectiveNoFileComp
}
client = komodo.NewClient(url, key, secret)
}
stacks, err := client.ListStacks()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var stackNames []string
for _, s := range stacks {
stackNames = append(stackNames, s.Name)
}
return filterCompletions(stackNames, toComplete), cobra.ShellCompDirectiveNoFileComp
}
func filterCompletions(items []string, prefix string) []string {
if prefix == "" {
return items
}
var matches []string
lowerPrefix := strings.ToLower(prefix)
for _, item := range items {
if strings.HasPrefix(strings.ToLower(item), lowerPrefix) {
matches = append(matches, item)
}
}
return matches
}