good progress
This commit is contained in:
parent
ac3e3a846e
commit
048940ef7a
14
cmd/add.go
14
cmd/add.go
@ -46,7 +46,6 @@ to quickly create a Cobra application.`,
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@ -64,7 +63,6 @@ func init() {
|
||||
// addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
|
||||
const focusedTextColor = "205"
|
||||
|
||||
var (
|
||||
@ -75,7 +73,6 @@ var (
|
||||
blurredSubmitButton = "[ " + te.String("Submit").Foreground(color("240")).String() + " ]"
|
||||
)
|
||||
|
||||
|
||||
// Will ask a user for a unique name until they exit or provide one.
|
||||
func cfgRename(c data.HostDetails) {
|
||||
p := tea.NewProgram(renameModel(c))
|
||||
@ -109,7 +106,6 @@ func toFile(fp string, c data.HostDetails) {
|
||||
tea.Quit()
|
||||
}
|
||||
|
||||
|
||||
type model struct {
|
||||
index int
|
||||
dbFileName input.Model
|
||||
@ -143,13 +139,10 @@ func initialModel() model {
|
||||
secret.Placeholder = "secret"
|
||||
secret.Prompt = blurredPrompt
|
||||
|
||||
|
||||
|
||||
return model{0, dbFileName, hostName, dbName, userName, secret, blurredSubmitButton}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return tea.Batch(
|
||||
input.Blink(m.dbFileName),
|
||||
@ -160,7 +153,6 @@ func (m model) Init() tea.Cmd {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
|
||||
@ -224,7 +216,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.userName = inputs[3]
|
||||
m.secret = inputs[4]
|
||||
|
||||
|
||||
if m.index == len(inputs) {
|
||||
m.submitButton = focusedSubmitButton
|
||||
} else {
|
||||
@ -240,7 +231,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
|
||||
func updateInputs(msg tea.Msg, m model) (model, tea.Cmd) {
|
||||
var (
|
||||
cmd tea.Cmd
|
||||
@ -261,11 +251,9 @@ func updateInputs(msg tea.Msg, m model) (model, tea.Cmd) {
|
||||
|
||||
m.secret, cmd = input.Update(msg, m.secret)
|
||||
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
|
||||
func (m model) View() string {
|
||||
s := "\n"
|
||||
|
||||
@ -311,7 +299,6 @@ func configurator(t []input.Model) {
|
||||
}
|
||||
toFile(fp, c)
|
||||
|
||||
|
||||
}
|
||||
|
||||
func renameModel(c data.HostDetails) rename {
|
||||
@ -363,7 +350,6 @@ func (m rename) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
m.textInput, cmd = input.Update(msg, m.textInput)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
17
cmd/load.go
17
cmd/load.go
@ -17,9 +17,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"pgee/box"
|
||||
"pgee/utils"
|
||||
"pgm/data"
|
||||
"pgm/loader"
|
||||
"pgm/logger"
|
||||
"os"
|
||||
)
|
||||
|
||||
// billyCmd represents the billy command
|
||||
@ -35,15 +36,18 @@ to quickly create a Cobra application.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var dbcfg string
|
||||
var title string
|
||||
var hosts []string
|
||||
hosts = data.ReadHosts()
|
||||
var pgHosts []string
|
||||
pgHosts = data.ReadHosts()
|
||||
title = "choose db to load, \"l\" or enter will load your choice"
|
||||
box.Box(pgee, title, dbcfg)
|
||||
err := loader.Loader(pgHosts, title, dbcfg)
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] loading error for testing, ignore.")
|
||||
}
|
||||
os.Exit(0)
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(loadCmd)
|
||||
|
||||
@ -57,4 +61,3 @@ func init() {
|
||||
// is called directly, e.g.:
|
||||
// billyCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"pgm/config"
|
||||
"pgm/logger"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
@ -64,6 +65,7 @@ func init() {
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
viper.BindPFlag("temp_db", rootCmd.PersistentFlags().Lookup("temp_db"))
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
@ -78,7 +80,6 @@ func InitConfig() {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Setenv("PGMHOME", home)
|
||||
// Search config in home directory with name ".pgm" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.SetConfigName(".pgm")
|
||||
@ -100,7 +101,6 @@ func InitConfig() {
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
logger.Logger("[LOG] Using config file:"+ viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,6 @@ func IsInit(h string, s string, l string, cfgFile string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// determines if key exists in config file
|
||||
func cfgExists(s string, d []string, cfgFile string) []string {
|
||||
var dir []string
|
||||
@ -54,8 +53,6 @@ func cfgExists( s string, d []string, cfgFile string) []string {
|
||||
dir = strings.Split(s, "/")
|
||||
cfgPath = dir[len(dir)-1]
|
||||
|
||||
|
||||
|
||||
configDirectoryKey := parseCfg(cfgPath)
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
|
||||
24
data/data.go
24
data/data.go
@ -2,6 +2,7 @@ package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
"log"
|
||||
"os"
|
||||
"pgm/logger"
|
||||
@ -40,3 +41,26 @@ func ReadHosts() []string {
|
||||
return pgee
|
||||
}
|
||||
|
||||
// returns a value from the .pgm.yaml file
|
||||
func ViperReturnKey(k string ) string {
|
||||
var h string
|
||||
var s string
|
||||
h, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] could not set home directory: " + err.Error())
|
||||
os.Exit(0)
|
||||
}
|
||||
viper.SetConfigName("scr")
|
||||
viper.SetConfigType("json")
|
||||
|
||||
viper.AddConfigPath(h + "/.pgm/scn/")
|
||||
err = viper.ReadInConfig() // Find and read the config file
|
||||
if err != nil { // Handle errors reading the config file
|
||||
logger.Logger("[ERROR] failed to load viper config: " + err.Error())
|
||||
fmt.Println("error occurred and was logged.")
|
||||
os.Exit(1)
|
||||
}
|
||||
s = viper.GetString(k)
|
||||
logger.Logger("[LOG] got value from .pgm.yaml: " + s )
|
||||
return s
|
||||
}
|
||||
|
||||
55
db/db.go
Normal file
55
db/db.go
Normal file
@ -0,0 +1,55 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/lib/pq"
|
||||
"os"
|
||||
"pgm/data"
|
||||
"pgm/logger"
|
||||
)
|
||||
|
||||
func DbConn(c data.HostDetails) *sql.DB {
|
||||
var h string
|
||||
var u string
|
||||
var pw string
|
||||
var dbn string
|
||||
var psqlInfo string
|
||||
h = c.Hostname
|
||||
u = c.Username
|
||||
pw = c.Secret
|
||||
dbn = c.DatabaseName
|
||||
psqlInfo = fmt.Sprintf("host=%s port=%d user=%s "+
|
||||
"password=%s dbname=%s sslmode=disable",
|
||||
h, 5432, u, pw, dbn)
|
||||
db, err := sql.Open("postgres", psqlInfo)
|
||||
testUserName := data.ViperReturnKey("test_user")
|
||||
logger.Logger("[LOG] reserved username is " + testUserName)
|
||||
if err != nil {
|
||||
switch u {
|
||||
case testUserName:
|
||||
logger.Logger("[ERROR] go tests expects to connect with the docker compose database." +
|
||||
"[ERROR] run \"docker-compose up\" and re-run tests")
|
||||
os.Exit(1)
|
||||
default:
|
||||
logger.Logger("[ERROR] db error: " + err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err = db.PingContext(ctx)
|
||||
if err != nil {
|
||||
switch u {
|
||||
case testUserName:
|
||||
logger.Logger("[ERROR] db error, unable to ping: " + err.Error()+
|
||||
"[ERROR] ensure docker database is running and re-run tests")
|
||||
os.Exit(1)
|
||||
default:
|
||||
logger.Logger("[ERROR] db error: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
pg-db:
|
||||
image: postgres:11.5
|
||||
container_name: pg-db
|
||||
expose:
|
||||
- "5432"
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_DB=localdb
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
volumes:
|
||||
- ${PWD}/sql/localDB.sql:/docker-entrypoint-initdb.d/localdb.sql
|
||||
|
||||
|
||||
3
go.mod
3
go.mod
@ -6,9 +6,10 @@ require (
|
||||
github.com/charmbracelet/bubbles v0.7.1
|
||||
github.com/charmbracelet/bubbletea v0.12.1
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/magiconair/properties v1.8.4 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
||||
github.com/mitchellh/mapstructure v1.3.3
|
||||
github.com/muesli/termenv v0.7.4
|
||||
github.com/pelletier/go-toml v1.8.1 // indirect
|
||||
github.com/spf13/afero v1.4.1 // indirect
|
||||
|
||||
1
go.sum
1
go.sum
@ -114,6 +114,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
|
||||
282
loader/loader.go
Normal file
282
loader/loader.go
Normal file
@ -0,0 +1,282 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/muesli/termenv"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"pgm/config"
|
||||
"pgm/data"
|
||||
"pgm/db"
|
||||
"pgm/logger"
|
||||
"pgm/ui"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type host struct {
|
||||
tic int
|
||||
t string
|
||||
choices []string
|
||||
choice int
|
||||
chosen bool
|
||||
Quitting bool
|
||||
Frames int
|
||||
File string
|
||||
isTest bool
|
||||
}
|
||||
|
||||
var (
|
||||
term = termenv.ColorProfile()
|
||||
subtle = makeFgStyle("241")
|
||||
dot = colorFg(" • ", "236")
|
||||
)
|
||||
|
||||
func Loader(t []string, s string, b string) error {
|
||||
var hostChoice host
|
||||
var isT bool
|
||||
isT = setTest(s)
|
||||
logger.Logger("[LOG] is loader test: " + strconv.FormatBool(hostChoice.isTest))
|
||||
hostChoice = host{60, s, t, 0, false, false, 0, b, isT}
|
||||
if err := tea.NewProgram(hostChoice).Start(); err != nil {
|
||||
if isT == true {
|
||||
return nil
|
||||
}
|
||||
logger.Logger("[ERROR] tea error occured")
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// method to enable go tests if set to true
|
||||
// loader function will test that it can load the ui to chose a database
|
||||
// and quits the ui
|
||||
func setTest(s string) bool {
|
||||
logger.Logger("[LOG] is test: " + s)
|
||||
if s == "test" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m host) Init() tea.Cmd {
|
||||
return tick()
|
||||
}
|
||||
|
||||
func choicesUpdate(msg tea.Msg, m host) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "q", "esc":
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
case "j", "down":
|
||||
m.choice += 1
|
||||
if m.choice > len(m.choices) {
|
||||
m.choice = len(m.choices)
|
||||
}
|
||||
case "k", "up":
|
||||
m.choice -= 1
|
||||
if m.choice < 0 {
|
||||
m.choice = 0
|
||||
}
|
||||
case "l", "enter":
|
||||
m.File = m.choices[m.choice]
|
||||
m.chosen = true
|
||||
return m, Frame()
|
||||
}
|
||||
|
||||
case tickMsg:
|
||||
if m.isTest == true {
|
||||
m.File = "test"
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
if m.tic == 0 {
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
m.tic -= 1
|
||||
return m, tick()
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Update loop for the second view after a choice has been made
|
||||
func (m host) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if msg, ok := msg.(tea.KeyMsg); ok {
|
||||
k := msg.String()
|
||||
if k == "q" || k == "esc" || k == "ctrl+c" {
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
|
||||
if !m.chosen {
|
||||
return choicesUpdate(msg, m)
|
||||
}
|
||||
return m, tea.Quit
|
||||
}
|
||||
|
||||
// Views return a string based on data in the host. That string which will be
|
||||
// rendered to the terminal.
|
||||
func (m host) View() string {
|
||||
logger.Logger("[LOG] view initialized")
|
||||
var s string
|
||||
if m.Quitting {
|
||||
logger.Logger("[LOG] leaving pgm")
|
||||
return "leaving pgm..."
|
||||
|
||||
}
|
||||
if !m.chosen {
|
||||
s = choicesView(m)
|
||||
} else {
|
||||
tea.Quit()
|
||||
LoadUi(m)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Passes our config to the screen file.
|
||||
// screen is tasked with rendering more in depth views.
|
||||
func LoadUi(m host) {
|
||||
var g data.HostDetails
|
||||
var h string
|
||||
h, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] uable to set home dir: " + err.Error())
|
||||
os.Exit(0)
|
||||
}
|
||||
config.ReadConfig()
|
||||
l := viper.GetString("hosts_dir")
|
||||
filepath := h + "/" + l + "/" + m.File
|
||||
loadhost(filepath, &g)
|
||||
Screener(g)
|
||||
|
||||
}
|
||||
|
||||
// Creates the menu for choosing a file from your configs.
|
||||
// Exits after 60 seconds.
|
||||
// Gets Title from outside in the load method if this... should ever be needed elsewhere.
|
||||
func choicesView(m host) string {
|
||||
var menu string
|
||||
c := m.choice
|
||||
|
||||
tpl := m.t + "\n\n"
|
||||
tpl += "%s\n\n"
|
||||
tpl += "menu exits in %s seconds\n\n"
|
||||
tpl += subtle("j/k, up/down: select") + dot + subtle("enter: choose") + dot + subtle("q, esc: quit")
|
||||
for i, s := range m.choices {
|
||||
menu = menu + "::" + checkbox(s, c == i)
|
||||
}
|
||||
mn := strings.Replace(menu, "::", "\n", -1)
|
||||
choices := fmt.Sprintf(
|
||||
mn,
|
||||
)
|
||||
|
||||
return fmt.Sprintf(tpl, choices, colorFg(strconv.Itoa(m.tic), "79"))
|
||||
}
|
||||
|
||||
// the rest of these functions are to do with looks and aesthetics
|
||||
|
||||
// returns a neat checkbox
|
||||
func checkbox(label string, checked bool) string {
|
||||
if checked {
|
||||
return colorFg("[x] "+label, "212")
|
||||
}
|
||||
return fmt.Sprintf("[ ] %s", label)
|
||||
}
|
||||
|
||||
// fun colors
|
||||
func colorFg(val, color string) string {
|
||||
return termenv.String(val).Foreground(term.Color(color)).String()
|
||||
}
|
||||
|
||||
// Return a function that will colorize the foreground of a given string.
|
||||
func makeFgStyle(color string) func(string) string {
|
||||
return termenv.Style{}.Foreground(term.Color(color)).Styled
|
||||
}
|
||||
|
||||
// Frame event
|
||||
func Frame() tea.Cmd {
|
||||
return tea.Tick(time.Second/60, func(time.Time) tea.Msg {
|
||||
return FrameMsg{}
|
||||
})
|
||||
}
|
||||
|
||||
type tickMsg struct{}
|
||||
type FrameMsg struct{}
|
||||
|
||||
// exits if no choice is selected in a minute
|
||||
func tick() tea.Cmd {
|
||||
return tea.Tick(time.Second, func(time.Time) tea.Msg {
|
||||
return tickMsg{}
|
||||
})
|
||||
}
|
||||
|
||||
// loads a yaml file into the correct format for consumption.
|
||||
// errs the pipeline step if there is not a configuration in this repository.
|
||||
func loadhost(c string, p *data.HostDetails) *data.HostDetails {
|
||||
logger.Logger("[LOG] file path string is: " + c)
|
||||
cfg, err := ioutil.ReadFile(c)
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] unable to find this filepath: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
json.Unmarshal(cfg, &p)
|
||||
return p
|
||||
}
|
||||
|
||||
func Screener(g data.HostDetails) error {
|
||||
var scn Scr
|
||||
var dbConn *sql.DB
|
||||
logger.Logger("[LOG] starting screen")
|
||||
s := data.ViperReturnKey("UserSessions")
|
||||
|
||||
mapstructure.Decode(s, &scn)
|
||||
dbConn = db.DbConn(g)
|
||||
switch g.Username {
|
||||
case "test":
|
||||
dbConn.Close()
|
||||
return nil
|
||||
}
|
||||
ui.GraphicUi(dbConn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Simple struct for a view in the UI.
|
||||
type Scr struct {
|
||||
Query string `json:"query"`
|
||||
Columns int `json:"columns"`
|
||||
UIType string `json:"uiType"`
|
||||
Title string `json:"title"`
|
||||
Quitting bool
|
||||
}
|
||||
|
||||
func (m Scr) Init() tea.Cmd {
|
||||
return tick()
|
||||
}
|
||||
|
||||
func (m Scr) View() string {
|
||||
|
||||
return m.Query
|
||||
}
|
||||
|
||||
func (m Scr) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if msg, ok := msg.(tea.KeyMsg); ok {
|
||||
k := msg.String()
|
||||
if k == "q" || k == "esc" || k == "ctrl+c" {
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@ -7,7 +7,10 @@ import (
|
||||
|
||||
func Logger(s string) bool {
|
||||
var h string
|
||||
h = os.Getenv("PGMHOME")
|
||||
h, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if s == "test" {
|
||||
os.Create("/var/tmp/PGMLOGTEST")
|
||||
file, err := os.OpenFile("/var/tmp/PGMLOGTEST", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
|
||||
|
||||
70
main_test.go
70
main_test.go
@ -1,10 +1,13 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
"pgm/config"
|
||||
"pgm/data"
|
||||
"pgm/loader"
|
||||
"pgm/logger"
|
||||
"testing"
|
||||
)
|
||||
@ -14,7 +17,7 @@ import (
|
||||
func TestInit(t *testing.T) {
|
||||
t.Parallel()
|
||||
var cfg string
|
||||
testCases := []initTests{
|
||||
testCases := []initTest{
|
||||
{a: "junk", b: "notreal", c: "failingonpurpose", want: true},
|
||||
{a: "test_host_dir", b: "test_screen_dr", c: "test_log_dir", want: true},
|
||||
}
|
||||
@ -57,7 +60,70 @@ func TestLoadConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
|
||||
type initTests struct {
|
||||
// loader function will test that it can load the ui to chose a database
|
||||
// and quits the ui.
|
||||
// "test" is added into the array of files a user has configured and selected
|
||||
func TestLoader(t *testing.T) {
|
||||
t.Parallel()
|
||||
var tc []string
|
||||
var s string
|
||||
var b string
|
||||
var want error = nil
|
||||
s = "test"
|
||||
b = "test"
|
||||
tc = data.ReadHosts()
|
||||
tc = append(tc, "test")
|
||||
got := loader.Loader(tc, s, b)
|
||||
if want != got {
|
||||
t.Errorf("want %t, got %t", want, got)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func TestScreener(t *testing.T){
|
||||
t.Parallel()
|
||||
var p data.HostDetails
|
||||
var testDb string
|
||||
var want error = nil
|
||||
var h string
|
||||
h, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] could not set home directory: " + err.Error())
|
||||
os.Exit(0)
|
||||
}
|
||||
viper.SetConfigName(".pgm") // config file name without extension
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(h)
|
||||
viper.AutomaticEnv() // read value ENV variable
|
||||
|
||||
err = viper.ReadInConfig()
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] fatal error config file: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
testDb = viper.GetString("test_db")
|
||||
err = json.Unmarshal([]byte(testDb), &p)
|
||||
if err != nil {
|
||||
logger.Logger("[LOG] test screener failed: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
got := loader.Screener(p)
|
||||
if want != got {
|
||||
t.Errorf("want %t, got %t", want, got)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
type viperHostTest struct {
|
||||
a string
|
||||
want bool
|
||||
}
|
||||
|
||||
|
||||
type initTest struct {
|
||||
a, b, c string
|
||||
want bool
|
||||
}
|
||||
21
sql/localDB.sql
Normal file
21
sql/localDB.sql
Normal file
@ -0,0 +1,21 @@
|
||||
create schema test;
|
||||
create table test.employees (
|
||||
Id SERIAL NOT NULL PRIMARY KEY,
|
||||
Name VARCHAR(50),
|
||||
Location VARCHAR(50)
|
||||
);
|
||||
create table test.company (
|
||||
cid SERIAL NOT NULL PRIMARY KEY,
|
||||
Name VARCHAR(50)
|
||||
);
|
||||
create table test.employer (
|
||||
eid SERIAL NOT NULL PRIMARY KEY,
|
||||
Id INT,
|
||||
cid INT
|
||||
);
|
||||
ALTER TABLE test.employer add constraint emp_fk foreign key(Id) REFERENCES test.employees(id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
insert into test.employees (name,location) VALUES ('bob','kalamazoo');
|
||||
create role test with login password 'test';
|
||||
insert into test.employees (name,location) VALUES ('cheeks','magoo');
|
||||
update test.employees set location = 'buttsville' where name = 'cheeks';
|
||||
grant all privileges on schema test to test;
|
||||
24
ui/ui.go
Normal file
24
ui/ui.go
Normal file
@ -0,0 +1,24 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"database/sql"
|
||||
"pgm/logger"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func GraphicUi(db *sql.DB, ) {
|
||||
row, err := db.Query("Select name from test.employees")
|
||||
if err != nil {
|
||||
logger.Logger("[ERROR] database error occured: " + err.Error())
|
||||
os.Exit(0)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
fmt.Println(row)
|
||||
}
|
||||
tea.Quit()
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user