-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added more readable, fancy logs with lipgloss package * Added better confirm messages with huh package * Tidied go.mod, renamed cli in usage descriptions
- Loading branch information
1 parent
adfddfc
commit efbd9c1
Showing
6 changed files
with
292 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,40 @@ | ||
module github.com/bitrise-io/bitrise-remote-access-cli | ||
|
||
go 1.21.3 | ||
go 1.22 | ||
|
||
toolchain go1.23.4 | ||
|
||
require ( | ||
github.com/charmbracelet/huh v0.6.0 | ||
github.com/charmbracelet/lipgloss v1.0.0 | ||
github.com/kevinburke/ssh_config v1.2.0 // https://github.com/kevinburke/ssh_config/issues/50 | ||
github.com/pkg/sftp v1.13.7 | ||
github.com/urfave/cli/v3 v3.0.0-beta1 | ||
golang.org/x/crypto v0.33.0 | ||
) | ||
|
||
require github.com/urfave/cli/v3 v3.0.0-beta1 | ||
|
||
require ( | ||
github.com/atotto/clipboard v0.1.4 // indirect | ||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect | ||
github.com/catppuccin/go v0.2.0 // indirect | ||
github.com/charmbracelet/bubbles v0.20.0 // indirect | ||
github.com/charmbracelet/bubbletea v1.3.4 // indirect | ||
github.com/charmbracelet/x/ansi v0.8.0 // indirect | ||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect | ||
github.com/charmbracelet/x/term v0.2.1 // indirect | ||
github.com/dustin/go-humanize v1.0.1 // indirect | ||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect | ||
github.com/kr/fs v0.1.0 // indirect | ||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | ||
github.com/mattn/go-isatty v0.0.20 // indirect | ||
github.com/mattn/go-localereader v0.0.1 // indirect | ||
github.com/mattn/go-runewidth v0.0.16 // indirect | ||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect | ||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect | ||
github.com/muesli/cancelreader v0.2.2 // indirect | ||
github.com/muesli/termenv v0.16.0 // indirect | ||
github.com/rivo/uniseg v0.4.7 // indirect | ||
golang.org/x/sync v0.11.0 // indirect | ||
golang.org/x/sys v0.30.0 // indirect | ||
golang.org/x/text v0.22.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package logger | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/charmbracelet/huh" | ||
"github.com/charmbracelet/lipgloss" | ||
) | ||
|
||
const ( | ||
neutral90 = "#dfdae1" | ||
neutral60 = "#94879b" | ||
purple70 = "#c289e6" | ||
blue70 = "#71b8ef" | ||
green70 = "#77cf8f" | ||
yellow70 = "#ebba00" | ||
red70 = "#ff8091" | ||
) | ||
|
||
func Success(a ...any) { | ||
message := getFormattedMessage(a...) | ||
Successf("%s", message) | ||
} | ||
|
||
func Info(a ...any) { | ||
message := getFormattedMessage(a...) | ||
Infof("%s", message) | ||
} | ||
|
||
func Warn(a ...any) { | ||
message := getFormattedMessage(a...) | ||
Warnf("%s", message) | ||
} | ||
|
||
func Successf(format string, a ...any) { | ||
message := fmt.Sprintf(format, a...) | ||
|
||
write("INFO", message, blue70, green70, green70, true) | ||
} | ||
|
||
func Infof(format string, a ...any) { | ||
message := fmt.Sprintf(format, a...) | ||
|
||
write("INFO", message, blue70, neutral60, neutral90, false) | ||
} | ||
|
||
func Warnf(format string, a ...any) { | ||
message := fmt.Sprintf(format, a...) | ||
|
||
write("WARN", message, yellow70, yellow70, yellow70, true) | ||
} | ||
|
||
func Error(a ...any) { | ||
message := getFormattedMessage(a...) | ||
write("ERROR", message, red70, red70, red70, true) | ||
} | ||
|
||
func PrintFormattedOutput(headerText, bodyText string) { | ||
headerStyle := lipgloss.NewStyle(). | ||
Bold(true). | ||
Foreground(lipgloss.Color(purple70)). | ||
PaddingBottom(1) | ||
bodyStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(purple70)) | ||
frameStyle := lipgloss.NewStyle(). | ||
MarginLeft(3). | ||
BorderForeground(lipgloss.AdaptiveColor{Dark: neutral90, Light: neutral60}). | ||
Border(lipgloss.RoundedBorder()). | ||
Padding(1, 2) | ||
|
||
header := headerStyle.Render(headerText) | ||
body := bodyStyle.Render(bodyText) | ||
|
||
content := fmt.Sprintf("%s\n%s", header, body) | ||
framedContent := frameStyle.Render(content) | ||
|
||
fmt.Println(framedContent) | ||
} | ||
|
||
func Confirm(title, onYes, onNo string) (bool, error) { | ||
var confirm bool | ||
|
||
err := huh.NewConfirm(). | ||
Title(title). | ||
Affirmative("yes"). | ||
Negative("no"). | ||
Value(&confirm). | ||
WithTheme( | ||
confirmTheme(), | ||
). | ||
Run() | ||
|
||
if err == nil { | ||
if confirm && onYes != "" { | ||
Info(onYes) | ||
} else if !confirm && onNo != "" { | ||
Info(onNo) | ||
} | ||
} | ||
|
||
return confirm, err | ||
} | ||
|
||
func confirmTheme() *huh.Theme { | ||
t := huh.ThemeBase() | ||
|
||
var ( | ||
neutral = lipgloss.AdaptiveColor{Dark: neutral90, Light: neutral60} | ||
purple = lipgloss.Color(purple70) | ||
) | ||
|
||
t.Focused.Base = t.Focused.Base.BorderForeground(neutral).MarginTop(1).MarginLeft(3) // sideline | ||
t.Focused.Title = t.Focused.Title.Foreground(purple) // description | ||
|
||
t.Focused.FocusedButton = t.Focused.FocusedButton.Background(purple).Bold(true) // selected tile | ||
t.Focused.BlurredButton = t.Focused.BlurredButton.Background(neutral) // unselected tile | ||
|
||
t.Blurred = t.Focused | ||
t.Blurred.Base = t.Blurred.Base.BorderStyle(lipgloss.RoundedBorder()) | ||
|
||
return t | ||
} | ||
|
||
func write(tag, message string, tagColor, messageColorDark, messageColorLight string, boldText bool) { | ||
timestamp := time.Now().Format("15:04:05") | ||
tagStr := lipgloss.NewStyle(). | ||
Foreground(lipgloss.Color(tagColor)). | ||
Width(7). | ||
Align(lipgloss.Right). | ||
PaddingLeft(2). | ||
PaddingRight(0). | ||
Bold(true). | ||
Render(tag) | ||
|
||
timeStr := lipgloss.NewStyle(). | ||
PaddingLeft(1). | ||
Render(fmt.Sprintf("[%s]", timestamp)) | ||
|
||
messageStr := lipgloss.NewStyle(). | ||
Foreground(lipgloss.AdaptiveColor{Dark: messageColorDark, Light: messageColorLight}). | ||
PaddingLeft(1). | ||
Bold(boldText). | ||
Render(message) | ||
|
||
formattedMessage := tagStr + timeStr + messageStr | ||
|
||
fmt.Println(formattedMessage) | ||
} | ||
|
||
func getFormattedMessage(a ...any) string { | ||
if len(a) < 1 { | ||
return "" | ||
} else if str, ok := a[0].(string); ok { | ||
if len(a) == 1 { | ||
return str | ||
} | ||
return fmt.Sprintf(str, a[1:]...) | ||
} else if err, ok := a[0].(error); ok { | ||
return err.Error() | ||
} | ||
return fmt.Sprint(a...) | ||
} |
Oops, something went wrong.