Skip to content
16 changes: 13 additions & 3 deletions cmd/dbc/completions/dbc.bash
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ _dbc_install_completions() {
esac

if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "--no-verify --level -l" -- "$cur"))
COMPREPLY=($(compgen -W "--json --no-verify --level -l" -- "$cur"))
return 0
fi

Expand All @@ -87,7 +87,7 @@ _dbc_uninstall_completions() {
esac

if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "--level -l" -- "$cur"))
COMPREPLY=($(compgen -W "--json --level -l" -- "$cur"))
return 0
fi

Expand Down Expand Up @@ -172,7 +172,7 @@ _dbc_search_completions() {
prev="${COMP_WORDS[COMP_CWORD-1]}"

if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-h -v" -- "$cur"))
COMPREPLY=($(compgen -W "-h -v --json" -- "$cur"))
return 0
fi

Expand All @@ -181,6 +181,16 @@ _dbc_search_completions() {
}

_dbc_info_completions() {
local cur prev
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"

if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "--json" -- "$cur"))
return 0
fi

# Driver name completion (no specific completion available)
COMPREPLY=()
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/dbc/completions/dbc.fish
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ complete -f -c dbc -n '__fish_dbc_needs_command' -a 'completion' -d 'Generate sh
# install subcommand
complete -f -c dbc -n '__fish_dbc_using_subcommand install' -s h -d 'Show Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand install' -l help -d 'Show Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand install' -l json -d 'Print output as JSON instead of plaintext'
complete -f -c dbc -n '__fish_dbc_using_subcommand install' -l no-verify -d 'Do not verify the driver after installation'
complete -f -c dbc -n '__fish_dbc_using_subcommand install' -l level -s l -d 'Installation level' -xa 'user system'

# uninstall subcommand
complete -f -c dbc -n '__fish_dbc_using_subcommand uninstall' -l json -d 'Print output as JSON instead of plaintext'
complete -f -c dbc -n '__fish_dbc_using_subcommand uninstall' -l level -s l -d 'Installation level' -xa 'user system'

# init subcommand
Expand All @@ -69,6 +71,7 @@ complete -f -c dbc -n '__fish_dbc_using_subcommand sync' -l no-verify -d 'Do not
complete -f -c dbc -n '__fish_dbc_using_subcommand search' -s h -d 'Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand search' -l help -d 'Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand search' -s v -d 'Verbose'
complete -f -c dbc -n '__fish_dbc_using_subcommand search' -l json -d 'Print output as JSON instead of plaintext'

# remove subcommand
complete -f -c dbc -n '__fish_dbc_using_subcommand remove' -s h -d 'Help'
Expand All @@ -78,6 +81,7 @@ complete -c dbc -n '__fish_dbc_using_subcommand remove' -l path -s p -r -F -a '*
# info subcommand
complete -f -c dbc -n '__fish_dbc_using_subcommand info' -s h -d 'Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand info' -l help -d 'Help'
complete -f -c dbc -n '__fish_dbc_using_subcommand info' -l json -d 'Print output as JSON instead of plaintext'

# docs subcommand
complete -f -c dbc -n '__fish_dbc_using_subcommand docs' -s h -d 'Help'
Expand Down
4 changes: 4 additions & 0 deletions cmd/dbc/completions/dbc.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function _dbc_install_completions {
'(--help)-h[Help]' \
'(-h)--help[Help]' \
'--no-verify[do not verify the driver after installation]' \
'--json[Print output as JSON instead of plaintext]' \
'(-l)--level[installation level]: :(user system)' \
'(--level)-l[installation level]: :(user system)' \
':driver name: '
Expand All @@ -80,6 +81,7 @@ function _dbc_uninstall_completions {
_arguments \
'(-l)--level[installation level]: :(user system)' \
'(--level)-l[installation level]: :(user system)' \
'--json[Print output as JSON instead of plaintext]' \
':driver name: '
}

Expand Down Expand Up @@ -115,13 +117,15 @@ function _dbc_search_completions {
'(--help)-h[Help]' \
'(-h)--help[Help]' \
'-v[verbose]' \
'--json[Print output as JSON instead of plaintext]' \
':search term: '
}

function _dbc_info_completions {
_arguments \
'(--help)-h[Help]' \
'(-h)--help[Help]' \
'--json[Print output as JSON instead of plaintext]' \
':driver name: '
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/dbc/driver_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func TestUnmarshalDriverList(t *testing.T) {
{"less", "[drivers]\nflightsql = {version = '<=1.8.0'}", []dbc.PkgInfo{
{Driver: dbc.Driver{Path: "flightsql"}, Version: semver.MustParse("1.8.0")},
}, nil},
{"greater", "[drivers]\nflightsql = {version = '>=1.8.0, <1.10.0'}", []dbc.PkgInfo{
{Driver: dbc.Driver{Path: "flightsql"}, Version: semver.MustParse("1.9.0")},
{"greater", "[drivers]\nflightsql = {version = '>=1.8.0, <=1.10.0'}", []dbc.PkgInfo{
{Driver: dbc.Driver{Path: "flightsql"}, Version: semver.MustParse("1.10.0")},
}, nil},
}

Expand Down
44 changes: 40 additions & 4 deletions cmd/dbc/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"encoding/json"
"strings"

tea "github.com/charmbracelet/bubbletea"
Expand All @@ -23,12 +24,14 @@ import (

type InfoCmd struct {
Driver string `arg:"positional,required" help:"Driver to get info about"`
Json bool `help:"Print output as JSON instead of plaintext"`
}

func (c InfoCmd) GetModelCustom(baseModel baseModel) tea.Model {
return infoModel{
baseModel: baseModel,
driver: c.Driver,
baseModel: baseModel,
jsonOutput: c.Json,
driver: c.Driver,
}
}

Expand All @@ -42,8 +45,9 @@ func (c InfoCmd) GetModel() tea.Model {
type infoModel struct {
baseModel

driver string
drv dbc.Driver
driver string
jsonOutput bool
drv dbc.Driver
}

func (m infoModel) Init() tea.Cmd {
Expand Down Expand Up @@ -83,6 +87,35 @@ func formatDriverInfo(drv dbc.Driver) string {
return b.String()
}

func driverInfoJSON(drv dbc.Driver) string {
info := drv.MaxVersion()

var driverInfoOutput = struct {
Driver string `json:"driver"`
Version string `json:"version"`
Title string `json:"title"`
License string `json:"license"`
Desc string `json:"description"`
Packages []string `json:"packages"`
}{
Driver: drv.Path,
Version: info.Version.String(),
Title: drv.Title,
License: drv.License,
Desc: drv.Desc,
}
for _, pkg := range info.Packages {
driverInfoOutput.Packages = append(driverInfoOutput.Packages, pkg.PlatformTuple)
}

jsonBytes, err := json.Marshal(driverInfoOutput)
if err != nil {
return err.Error()
}

return string(jsonBytes)
}

func (m infoModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case dbc.Driver:
Expand All @@ -96,6 +129,9 @@ func (m infoModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (m infoModel) FinalOutput() string {
if m.jsonOutput {
return driverInfoJSON(m.drv)
}
return formatDriverInfo(m.drv)
}

Expand Down
66 changes: 53 additions & 13 deletions cmd/dbc/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"encoding/json"
"errors"
"fmt"
"io/fs"
Expand Down Expand Up @@ -51,18 +52,20 @@ type InstallCmd struct {
// URI url.URL `arg:"-u" placeholder:"URL" help:"Base URL for fetching drivers"`
Driver string `arg:"positional,required" help:"Driver to install"`
Level config.ConfigLevel `arg:"-l" help:"Config level to install to (user, system)"`
Json bool `arg:"--json" help:"Output JSON instead of plaintext"`
NoVerify bool `arg:"--no-verify" help:"Allow installation of drivers without a signature file"`
}

func (c InstallCmd) GetModelCustom(baseModel baseModel) tea.Model {
s := spinner.New()
s.Spinner = spinner.MiniDot
return progressiveInstallModel{
Driver: c.Driver,
NoVerify: c.NoVerify,
spinner: s,
cfg: getConfig(c.Level),
baseModel: baseModel,
Driver: c.Driver,
NoVerify: c.NoVerify,
jsonOutput: c.Json,
spinner: s,
cfg: getConfig(c.Level),
baseModel: baseModel,
p: dbc.NewFileProgress(
progress.WithDefaultGradient(),
progress.WithWidth(20),
Expand Down Expand Up @@ -147,6 +150,7 @@ type progressiveInstallModel struct {
Driver string
VersionInput *semver.Version
NoVerify bool
jsonOutput bool
cfg config.Config

DriverPackage dbc.PkgInfo
Expand All @@ -173,23 +177,55 @@ func (m progressiveInstallModel) Init() tea.Cmd {
func (m progressiveInstallModel) FinalOutput() string {
if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil {
if m.conflictingInfo.Version.Equal(m.DriverPackage.Version) {
if m.jsonOutput {
return fmt.Sprintf(`{"status":"already installed","driver":"%s","version":"%s","location":"%s"}`,
m.conflictingInfo.ID, m.conflictingInfo.Version, filepath.SplitList(m.cfg.Location)[0])
}
return fmt.Sprintf("\nDriver %s %s already installed at %s\n",
m.conflictingInfo.ID, m.conflictingInfo.Version, filepath.SplitList(m.cfg.Location)[0])
}
}

var b strings.Builder
if m.state == stDone {
if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil {
b.WriteString(fmt.Sprintf("\nRemoved conflicting driver: %s (version: %s)",
m.conflictingInfo.ID, m.conflictingInfo.Version))
var output struct {
Status string `json:"status"`
Driver string `json:"driver"`
Version string `json:"version"`
Location string `json:"location"`
Message string `json:"message,omitempty"`
Conflict string `json:"conflict,omitempty"`
}

b.WriteString(fmt.Sprintf("\nInstalled %s %s to %s\n",
m.Driver, m.DriverPackage.Version, filepath.SplitList(m.cfg.Location)[0]))
output.Status = "installed"
output.Driver = m.Driver
output.Version = m.DriverPackage.Version.String()
output.Location = filepath.SplitList(m.cfg.Location)[0]
if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil {
output.Conflict = fmt.Sprintf("%s (version: %s)", m.conflictingInfo.ID, m.conflictingInfo.Version)
}

if m.postInstallMessage != "" {
b.WriteString("\n" + postMsgStyle.Render(m.postInstallMessage) + "\n")
output.Message = m.postInstallMessage
}

if m.jsonOutput {
jsonOutput, err := json.Marshal(output)
if err != nil {
return fmt.Sprintf(`{"status":"error","error":"%s"}`, err.Error())
}
return string(jsonOutput)
}

if output.Conflict != "" {
fmt.Fprintf(&b, "\nRemoved conflicting driver: %s", output.Conflict)
}

fmt.Fprintf(&b, "\nInstalled %s %s to %s\n",
output.Driver, output.Version, output.Location)

if output.Message != "" {
b.WriteString("\n" + postMsgStyle.Render(output.Message) + "\n")
}
}
return b.String()
Expand Down Expand Up @@ -303,6 +339,10 @@ func (m progressiveInstallModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Sequence(func() tea.Msg {
return config.CreateManifest(m.cfg, msg.DriverInfo)
}, tea.Quit)
case error:
if m.jsonOutput {
return m, tea.Sequence(tea.Println(fmt.Sprintf(`{"status":"error","error":"%s"}`, msg.Error())), tea.Quit)
}
}

base, cmd := m.baseModel.Update(msg)
Expand All @@ -320,7 +360,7 @@ func checkbox(label string, checked bool) string {
var postMsgStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))

func (m progressiveInstallModel) View() string {
if m.status != 0 {
if m.status != 0 || m.jsonOutput {
return ""
}

Expand All @@ -333,7 +373,7 @@ func (m progressiveInstallModel) View() string {
var b strings.Builder
for s := range stDone {
if s == m.state {
b.WriteString(fmt.Sprintf("[%s] %s...", m.spinner.View(), s.String()))
fmt.Fprintf(&b, "[%s] %s...", m.spinner.View(), s.String())
if s == stDownloading {
b.WriteString(" " + m.p.View())
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/dbc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func main() {

if !args.Quiet {
if fo, ok := m.(HasFinalOutput); ok {
fmt.Print(fo.FinalOutput())
fmt.Println(fo.FinalOutput())
}
}

Expand Down
Loading
Loading