Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/.goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ builds:
# main: .
id: "kmip-explorer"
binary: kmip-explorer
dir: ./
dir: ./cmd/kmip-explorer

archives:
- format: tar.gz
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: test

on:
push:
branches: [ "main" ]
branches: ["main"]
workflow_call: {}

permissions: {}
Expand All @@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-build-env
- name: Build
run: go build -v -ldflags="-s -w" -trimpath -o build/ .
run: go build -v -ldflags="-s -w" -trimpath -o build/ ./cmd/kmip-explorer

lint:
runs-on: ubuntu-latest
Expand Down
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,47 @@ It supports KMIP from v1.0 up to v1.4.
Download the latest release from the [release page](https://github.com/phsym/kmip-explorer/releases/latest)

#### Install with go
Run `go install github.com/phsym/kmip-explorer@latest`
Run `go install github.com/phsym/kmip-explorer/cmd/kmip-explorer@latest`

## Use as a library

The terminal UI can be embedded into your own application. The root package
exposes a minimal API by design: you build and own a `kmipclient.Client`
(controlling TLS, middlewares and the server address yourself), hand it to
`explorer.New`, then call `Run` to start the UI.

```go
package main

import (
"log"

"github.com/ovh/kmip-go/kmipclient"
explorer "github.com/phsym/kmip-explorer"
)

func main() {
client, err := kmipclient.Dial(
"eu-west-rbx.okms.ovh.net:5696",
kmipclient.WithClientCertFiles("cert.pem", "key.pem"),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()

// version is shown in the banner; pass "" as latestVersion to disable the
// update hint.
exp := explorer.New(client, "dev", "")
if err := exp.Run(); err != nil {
log.Fatal(err)
}
}
```

`Run` takes over the terminal and blocks until the user quits. See the
[package documentation](https://pkg.go.dev/github.com/phsym/kmip-explorer) for
details.

### Run it
Display help with `kmip-explorer -h`
Expand Down
4 changes: 2 additions & 2 deletions main.go → cmd/kmip-explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"strings"

"github.com/ovh/kmip-go/kmipclient"
"github.com/phsym/kmip-explorer/internal"
explorer "github.com/phsym/kmip-explorer"
"golang.org/x/mod/semver"

"flag"
Expand Down Expand Up @@ -81,7 +81,7 @@ func main() {

// tview.Styles.PrimitiveBackgroundColor = tcell.ColorNone
client := newClient()
exp := internal.NewExplorer(client, version, latestVersion)
exp := explorer.New(client, version, latestVersion)
if err := exp.Run(); err != nil {
fmt.Fprintln(os.Stderr, "ERROR:", err)
os.Exit(1)
Expand Down
36 changes: 34 additions & 2 deletions internal/explorer.go → explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package internal
// Package explorer provides a terminal UI for browsing and managing KMIP
// objects over a [kmipclient.Client] connection.
//
// It is primarily consumed by the kmip-explorer command, but the TUI can also
// be embedded into another application: construct an [Explorer] with [New] and
// drive it with [Explorer.Run]. The public surface is intentionally minimal —
// the caller owns the KMIP client (TLS, middlewares, server address) and hands
// it to the explorer ready to use.
//
// client, err := kmipclient.Dial(addr, opts...)
// if err != nil {
// log.Fatal(err)
// }
// defer client.Close()
// if err := explorer.New(client, version, "").Run(); err != nil {
// log.Fatal(err)
// }
package explorer

import (
"fmt"
Expand Down Expand Up @@ -44,6 +61,9 @@ const (
attrPanelExpanded = 6 // focused: the user dived into the attributes
)

// Explorer is the KMIP browser terminal application. Create one with [New] and
// start it with [Explorer.Run]. An Explorer is single-use and not safe for
// concurrent use by multiple goroutines.
type Explorer struct {
app *tview.Application
search *tview.InputField
Expand All @@ -68,7 +88,15 @@ type Explorer struct {
client *kmipclient.Client
}

func NewExplorer(client *kmipclient.Client, version, latestVersion string) *Explorer {
// New builds an Explorer that operates against the given KMIP client. The
// client must be connected and ready to use; the Explorer does not close it.
//
// version is the application version displayed in the banner; pass an empty
// string to hide the version line entirely. latestVersion is the newest
// version available upstream, used to show an update hint next to the version;
// pass an empty string to disable the hint (it is also suppressed when version
// is empty). The returned Explorer is started with [Explorer.Run].
func New(client *kmipclient.Client, version, latestVersion string) *Explorer {
ex := &Explorer{
client: client,
}
Expand Down Expand Up @@ -341,6 +369,10 @@ func (ex *Explorer) init() {
go ex.refresh(true)
}

// Run takes over the terminal, draws the UI and blocks until the user quits
// (by pressing 'q') or a fatal error occurs. It returns any error reported by
// the underlying terminal application. Run must be called at most once per
// Explorer.
func (ex *Explorer) Run() error {
ex.init()
defer ex.app.Stop()
Expand Down
Loading