|
|
|
|
@ -1,8 +1,8 @@
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
|
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
|
|
|
@ -11,37 +11,34 @@ import (
|
|
|
|
|
"periodic/prddeploy/commands"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type sshExecCmd struct {
|
|
|
|
|
run func()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *sshExecCmd) Run() error { c.run(); return nil }
|
|
|
|
|
func (c *sshExecCmd) SetStdin(_ io.Reader) {}
|
|
|
|
|
func (c *sshExecCmd) SetStdout(_ io.Writer) {}
|
|
|
|
|
func (c *sshExecCmd) SetStderr(_ io.Writer) {}
|
|
|
|
|
|
|
|
|
|
type appState int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
stateList appState = iota
|
|
|
|
|
stateForm
|
|
|
|
|
stateOutput
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type cmdResultMsg struct {
|
|
|
|
|
output string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type CommandItem struct {
|
|
|
|
|
ItemTitle string `json:"title"`
|
|
|
|
|
ItemTitle string `json:"title"`
|
|
|
|
|
ItemDescription string `json:"description"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i CommandItem) FilterValue() string { return i.ItemTitle }
|
|
|
|
|
func (i CommandItem) Title() string { return i.ItemTitle }
|
|
|
|
|
func (i CommandItem) Description() string { return i.ItemDescription }
|
|
|
|
|
func (i CommandItem) String() string { return i.ItemTitle }
|
|
|
|
|
func (i CommandItem) String() string { return i.ItemTitle }
|
|
|
|
|
|
|
|
|
|
type model struct {
|
|
|
|
|
list list.Model
|
|
|
|
|
form *huh.Form
|
|
|
|
|
state appState
|
|
|
|
|
choice int
|
|
|
|
|
output string
|
|
|
|
|
|
|
|
|
|
RemoteCommand string
|
|
|
|
|
PrivateKeyFile string
|
|
|
|
|
@ -71,8 +68,8 @@ func (m *model) ReadForm() {
|
|
|
|
|
|
|
|
|
|
func newModel() model {
|
|
|
|
|
items := []list.Item{
|
|
|
|
|
CommandItem{ItemTitle: "Run Command", ItemDescription: "Run a command on the remote host",},
|
|
|
|
|
CommandItem{ItemTitle: "Upload File", ItemDescription: "Upload a file to the remote host",},
|
|
|
|
|
CommandItem{ItemTitle: "Run Command", ItemDescription: "Run a command on the remote host"},
|
|
|
|
|
CommandItem{ItemTitle: "Upload File", ItemDescription: "Upload a file to the remote host"},
|
|
|
|
|
}
|
|
|
|
|
l := list.New(items, list.NewDefaultDelegate(), 80, 20)
|
|
|
|
|
l.Title = "Commands"
|
|
|
|
|
@ -83,6 +80,33 @@ func (m model) Init() tea.Cmd {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func execCommand(choice int, m model) tea.Cmd {
|
|
|
|
|
return func() tea.Msg {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
var err error
|
|
|
|
|
if choice == 0 {
|
|
|
|
|
err = commands.RunCommand(commands.RunCommandArgs{
|
|
|
|
|
RemoteCommand: m.RemoteCommand,
|
|
|
|
|
PrivateKeyFile: m.PrivateKeyFile,
|
|
|
|
|
Username: m.Username,
|
|
|
|
|
Host: m.Host,
|
|
|
|
|
}, &buf, &buf)
|
|
|
|
|
} else {
|
|
|
|
|
err = commands.UploadFile(commands.UploadFileArgs{
|
|
|
|
|
LocalFilepath: m.LocalFilepath,
|
|
|
|
|
DestinationFilepath: m.DestinationFilepath,
|
|
|
|
|
PrivateKeyFile: m.PrivateKeyFile,
|
|
|
|
|
Username: m.Username,
|
|
|
|
|
Host: m.Host,
|
|
|
|
|
}, &buf, &buf)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Fprintf(&buf, "\nError: %v", err)
|
|
|
|
|
}
|
|
|
|
|
return cmdResultMsg{output: buf.String()}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
|
switch m.state {
|
|
|
|
|
case stateList:
|
|
|
|
|
@ -127,28 +151,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
|
}
|
|
|
|
|
if m.form.State == huh.StateCompleted {
|
|
|
|
|
m.ReadForm()
|
|
|
|
|
var execCmd tea.ExecCommand
|
|
|
|
|
if m.choice == 0 {
|
|
|
|
|
args := commands.RunCommandArgs{
|
|
|
|
|
RemoteCommand: m.RemoteCommand,
|
|
|
|
|
PrivateKeyFile: m.PrivateKeyFile,
|
|
|
|
|
Username: m.Username,
|
|
|
|
|
Host: m.Host,
|
|
|
|
|
}
|
|
|
|
|
execCmd = &sshExecCmd{run: func() { commands.RunCommand(args) }}
|
|
|
|
|
} else {
|
|
|
|
|
args := commands.UploadFileArgs{
|
|
|
|
|
LocalFilepath: m.LocalFilepath,
|
|
|
|
|
DestinationFilepath: m.DestinationFilepath,
|
|
|
|
|
PrivateKeyFile: m.PrivateKeyFile,
|
|
|
|
|
Username: m.Username,
|
|
|
|
|
Host: m.Host,
|
|
|
|
|
}
|
|
|
|
|
execCmd = &sshExecCmd{run: func() { commands.UploadFile(args) }}
|
|
|
|
|
}
|
|
|
|
|
m.state = stateList
|
|
|
|
|
choice := m.choice
|
|
|
|
|
m.form = nil
|
|
|
|
|
return m, tea.Exec(execCmd, func(err error) tea.Msg { return nil })
|
|
|
|
|
m.state = stateOutput
|
|
|
|
|
return m, execCommand(choice, m)
|
|
|
|
|
}
|
|
|
|
|
if m.form.State == huh.StateAborted {
|
|
|
|
|
m.state = stateList
|
|
|
|
|
@ -156,6 +162,18 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
return m, cmd
|
|
|
|
|
|
|
|
|
|
case stateOutput:
|
|
|
|
|
if _, ok := msg.(tea.KeyMsg); ok {
|
|
|
|
|
m.state = stateList
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
|
case cmdResultMsg:
|
|
|
|
|
m.output = msg.output
|
|
|
|
|
m.state = stateOutput
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
|
@ -167,6 +185,8 @@ func (m model) View() string {
|
|
|
|
|
return m.list.View()
|
|
|
|
|
case stateForm:
|
|
|
|
|
return m.form.View()
|
|
|
|
|
case stateOutput:
|
|
|
|
|
return m.output + "\n\nPress any key to return..."
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|