2 Commits

Author SHA1 Message Date
8e257639e0 fixed list items 2025-02-12 18:16:57 +01:00
157a215e87 initial try 2025-02-11 19:13:06 +01:00
43 changed files with 957 additions and 685 deletions

View File

@@ -1,96 +0,0 @@
prSections:
- title: Responsible PRs
filters: repo:tlinden/anydb is:open NOT dependabot
layout:
repoName:
hidden: true
- title: Responsible Dependabot PRs
filters: repo:tlinden/anydb is:open dependabot
layout:
repoName:
hidden: true
issuesSections:
- title: Responsible Issues
filters: is:open repo:tlinden/anydb -author:@me
layout:
repoName:
hidden: true
- title: Note-to-Self Issues
filters: is:open repo:tlinden/anydb author:@me
layout:
creator:
hidden: true
repoName:
hidden: true
defaults:
preview:
open: false
width: 100
keybindings:
universal:
- key: "shift+down"
builtin: pageDown
- key: "shift+up"
builtin: pageUp
prs:
- key: g
name: gitu
command: >
cd {{.RepoPath}} && /home/scip/bin/gitu
- key: M
name: squash-merge
command: gh pr merge --rebase --squash --admin --repo {{.RepoName}} {{.PrNumber}}
- key: i
name: show ci checks
command: gh pr checks --repo {{.RepoName}} {{.PrNumber}} | glow -p
- key: e
name: edit pr
command: ~/.config/gh-dash/edit-gh-pr {{.RepoName}} {{.PrNumber}}
- key: E
name: open repo in emacs
command: emacsclient {{.RepoPath}} &
issues:
- key: v
name: view
command: gh issue view --repo {{.RepoName}} {{.IssueNumber}} | glow -p
- key: l
name: add label
command: gh issue --repo {{.RepoName}} edit {{.IssueNumber}} --add-label $(gum choose bug enhancement question dependencies wontfix)
- key: L
name: remove label
command: gh issue --repo {{.RepoName}} edit {{.IssueNumber}} --remove-label $(gum choose bug enhancement question dependencies wontfix)
- key: E
name: open repo in emacs
command: emacsclient {{.RepoPath}} &
theme:
ui:
sectionsShowCount: true
table:
compact: false
showSeparator: true
colors:
text:
primary: "#E2E1ED"
secondary: "#6770cb"
inverted: "#242347"
faint: "#b0793b"
warning: "#E0AF68"
success: "#3DF294"
background:
selected: "#1B1B33"
border:
primary: "#383B5B"
secondary: "#39386B"
faint: "#8d3e0b"
repoPaths:
:owner/:repo: ~/dev/:repo
pager:
diff: delta

56
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: build-and-test
#on: [push, pull_request]
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
build:
strategy:
matrix:
version: ['1.23']
os: [ubuntu-latest, macos-latest]
name: Build
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.version }}
id: go
- name: checkout
uses: actions/checkout@v4
- name: build
run: go build
- name: test
run: make test
- name: Update coverage report
uses: ncruces/go-coverage-report@main
with:
report: true
chart: true
amend: true
if: |
matrix.os == 'ubuntu-latest' &&
github.event_name == 'push'
continue-on-error: true
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v5
with:
go-version: 1.23
- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v6

34
.github/workflows/pushimage.yaml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: build-push-image
on:
push:
tags:
- 'v*'
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
registry: https://ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991
with:
push: true
tags: ghcr.io/tlinden/anydb:${{ github.ref_name}}
- name: Build and push latest Docker image
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991
with:
push: true
tags: ghcr.io/tlinden/anydb:latest

87
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,87 @@
name: build-release
on:
push:
tags:
- "v*.*.*"
jobs:
release:
name: Build Release Assets
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.23.5
- name: Build the executables
run: ./mkrel.sh anydb ${{ github.ref_name}}
- name: List the executables
run: ls -l ./releases
- name: Upload the binaries
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: ./releases/*
file_glob: true
- name: Build Changelog
id: github_release
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
mode: "PR"
configurationJson: |
{
"template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
"pr_template": "- #{{TITLE}} (##{{NUMBER}}) by #{{AUTHOR}}\n#{{BODY}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## New Features",
"labels": ["add", "feature"]
},
{
"title": "## Bug Fixes",
"labels": ["fix", "bug", "revert"]
},
{
"title": "## Documentation Enhancements",
"labels": ["doc"]
},
{
"title": "## Refactoring Efforts",
"labels": ["refactor"]
},
{
"title": "## Miscellaneus Changes",
"labels": []
}
],
"ignore_labels": [
"duplicate", "good first issue", "help wanted", "invalid", "question", "wontfix"
],
"label_extractor": [
{
"pattern": "(.) (.+)",
"target": "$1"
},
{
"pattern": "(.) (.+)",
"target": "$1",
"on_property": "title"
}
]
}
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{steps.github_release.outputs.changelog}}

View File

@@ -1,6 +0,0 @@
linters:
exclusions:
rules:
- linters:
- staticcheck
text: "QF1008:"

View File

@@ -1,7 +0,0 @@
version: "2"
linters:
exclusions:
rules:
- linters:
- staticcheck
text: "QF1008:"

View File

@@ -1,69 +0,0 @@
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 2
before:
hooks:
- go mod tidy
gitea_urls:
api: https://codeberg.org/api/v1
download: https://codeberg.org
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
- freebsd
archives:
- formats: [tar.gz]
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}_{{ .Tag }}
# use zip for windows archives
format_overrides:
- goos: windows
formats: [zip]
- goos: linux
formats: [tar.gz,binary]
files:
- src: "*.md"
strip_parent: true
- src: "docs/*"
strip_parent: true
- src: Makefile.dist
dst: Makefile
wrap_in_directory: true
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
groups:
- title: Improved
regexp: '^.*?(feat|add|new)(\([[:word:]]+\))??!?:.+$'
order: 0
- title: Fixed
regexp: '^.*?(bug|fix)(\([[:word:]]+\))??!?:.+$'
order: 1
- title: Changed
order: 999
release:
header: "# Release Notes"
footer: >-
---
Full Changelog: [{{ .PreviousTag }}...{{ .Tag }}](https://codeberg.org/scip/epuppy/compare/{{ .PreviousTag }}...{{ .Tag }})

View File

@@ -1,27 +0,0 @@
matrix:
platform:
- linux/amd64
goversion:
- 1.24
labels:
platform: ${platform}
steps:
build:
when:
event: [push]
image: golang:${goversion}
commands:
- go get
- go build
- go test
linter:
when:
event: [push]
image: golang:${goversion}
commands:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
- golangci-lint --version
- golangci-lint run ./...

View File

@@ -1,32 +0,0 @@
# https://woodpecker-ci.org/plugins/docker-buildx
# enable Package unit and go to /scip/-/packages after building to link to proj
variables:
- &repo codeberg.org/${CI_REPO_OWNER}/anydb
steps:
dryrun:
image: docker.io/woodpeckerci/plugin-docker-buildx:latest
settings:
dockerfile: Dockerfile
platforms: linux/amd64
dry_run: true
repo: *repo
tags: latest
when:
event: [pull_request]
publish:
image: docker.io/woodpeckerci/plugin-docker-buildx:latest
settings:
dockerfile: Dockerfile
platforms: linux/amd64
repo: *repo
registry: codeberg.org
tags: latest,${CI_COMMIT_SHA:0:8},${CI_COMMIT_TAG}
username: ${CI_REPO_OWNER}
password:
from_secret: REGISTRY_TOKEN
when:
event: [tag]
branch: main

View File

@@ -1,15 +0,0 @@
# build release
labels:
platform: linux/amd64
steps:
goreleaser:
image: goreleaser/goreleaser
when:
event: [tag]
environment:
GITEA_TOKEN:
from_secret: DEPLOY_TOKEN
commands:
- goreleaser release --clean --verbose

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
FROM golang:1.24-alpine as builder FROM golang:1.23-alpine as builder
RUN apk update RUN apk update
RUN apk upgrade RUN apk upgrade

View File

@@ -51,11 +51,11 @@ endif
app/dbentry.pb.go: app/dbentry.proto app/dbentry.pb.go: app/dbentry.proto
protoc -I=. --go_out=app app/dbentry.proto protoc -I=. --go_out=app app/dbentry.proto
mv app/codeberg.org/scip/anydb/app/dbentry.pb.go app/dbentry.pb.go mv app/github.com/tlinden/anydb/app/dbentry.pb.go app/dbentry.pb.go
rm -rf app/github.com rm -rf app/github.com
buildlocal: buildlocal:
go build -ldflags "-X 'codeberg.org/scip/anydb/cfg.VERSION=$(VERSION)'" go build -ldflags "-X 'github.com/tlinden/anydb/cfg.VERSION=$(VERSION)'"
# binaries are being built by ci workflow on tag creation # binaries are being built by ci workflow on tag creation
release: release:
@@ -70,12 +70,12 @@ install: buildlocal
clean: clean:
rm -rf $(tool) releases coverage.out rm -rf $(tool) releases coverage.out
test: clean test:
ANYDB_PASSWORD=test go test -v ./... ANYDB_PASSWORD=test go test -v ./...
singletest: singletest:
@echo "Call like this: ''make singletest TEST=TestPrepareColumns MOD=lib" @echo "Call like this: ''make singletest TEST=TestPrepareColumns MOD=lib"
ANYDB_PASSWORD=test go test -run $(TEST) codeberg.org/scip/anydb/$(MOD) ANYDB_PASSWORD=test go test -run $(TEST) github.com/tlinden/anydb/$(MOD)
cover-report: cover-report:
go test ./... -cover -coverprofile=coverage.out go test ./... -cover -coverprofile=coverage.out

View File

@@ -1,20 +0,0 @@
# -*-make-*-
.PHONY: install all
tool = rpn
PREFIX = /usr/local
UID = root
GID = 0
all:
@echo "Type 'sudo make install' to install the tool."
@echo "To change prefix, type 'sudo make install PREFIX=/opt'"
install:
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -d -o $(UID) -g $(GID) $(PREFIX)/share/doc
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
install -o $(UID) -g $(GID) -m 444 *.md $(PREFIX)/share/doc/

View File

@@ -1,24 +1,18 @@
## A personal key value store ## A personal key value store
[![status-badge](https://ci.codeberg.org/api/badges/15517/status.svg)](https://ci.codeberg.org/repos/15517) [![Actions](https://github.com/tlinden/anydb/actions/workflows/ci.yaml/badge.svg)](https://github.com/tlinden/anydb/actions)
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://codeberg.org/scip/anydb/blob/master/LICENSE) [![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/anydb/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/codeberg.org/scip/anydb)](https://goreportcard.com/report/codeberg.org/scip/anydb) [![Go Coverage](https://github.com/tlinden/anydb/wiki/coverage.svg)](https://raw.githack.com/wiki/tlinden/anydb/coverage.html)
[![GitHub release](https://img.shields.io/github/v/release/tlinden/anydb?color=%2300a719)](https://codeberg.org/scip/anydb/releases) [![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/anydb)](https://goreportcard.com/report/github.com/tlinden/anydb)
[![Documentation](https://img.shields.io/badge/manpage-documentation-blue)](https://codeberg.org/scip/anydb/raw/branch/main/anydb.pod) [![GitHub release](https://img.shields.io/github/v/release/tlinden/anydb?color=%2300a719)](https://github.com/TLINDEN/anydb/releases/latest)
[![Documentation](https://img.shields.io/badge/manpage-documentation-blue)](https://github.com/TLINDEN/anydb/blob/master/anydb.pod)
> [!CAUTION] > [!CAUTION]
> Between version 0.1.0 and version 0.2.1 deletion of keys did not work. There > Version 0.1.3 introduced a [regression bug](https://github.com/TLINDEN/anydb/issues/19),
> is a unit test to check for this, but this unit test had a bug as well and
> didn't catch it. The bug and the test have been fixed. You are advised to
> upgrade to 0.2.1 and above.
> [!CAUTION]
> Version 0.1.3 introduced a [regression](https://codeberg.org/scip/anydb/issues/19),
> which caused the encryption feature not to work correctly anymore. > which caused the encryption feature not to work correctly anymore.
> If you are using anydb 0.1.3, you are urgently advised to > If you are using anydb 0.1.3, you are urgently advised to
> upgrade to 0.2.0 > upgrade to 0.2.0
Anydb is a simple to use commandline tool to store anything you'd Anydb is a simple to use commandline tool to store anything you'd
like, even binary files etc. It is a re-implementation of like, even binary files etc. It is a re-implementation of
[skate](https://github.com/charmbracelet/skate) for the following [skate](https://github.com/charmbracelet/skate) for the following
@@ -46,17 +40,17 @@ And I wrote a very similar [tool](https://www.daemon.de/projects/dbtool/) 24 yea
**anydb** can do all the things you can do with skate: **anydb** can do all the things you can do with skate:
![simple demo](https://codeberg.org/scip/anydb/raw/branch/demo/intro.gif) ![simple demo](https://github.com/TLINDEN/anydb/blob/main/demo/intro.gif)
However, there are more features than just that! However, there are more features than just that!
![advanced demo](https://codeberg.org/scip/anydb/raw/branch/demo/advanced.gif) ![advanced demo](https://github.com/TLINDEN/anydb/blob/main/demo/advanced.gif)
## Installation ## Installation
There are multiple ways to install **anydb**: There are multiple ways to install **anydb**:
- Go to the [latest release page](https://codeberg.org/scip/anydb/releases), - Go to the [latest release page](https://github.com/tlinden/anydb/releases/latest),
locate the binary for your operating system and platform. locate the binary for your operating system and platform.
Download it and put it into some directory within your `$PATH` variable. Download it and put it into some directory within your `$PATH` variable.
@@ -69,7 +63,7 @@ There are multiple ways to install **anydb**:
- You can also install from source. Issue the following commands in your shell: - You can also install from source. Issue the following commands in your shell:
```shell ```shell
git clone https://codeberg.org/scip/anydb.git git clone https://github.com/TLINDEN/anydb.git
cd anydb cd anydb
make make
sudo make install sudo make install
@@ -77,7 +71,7 @@ There are multiple ways to install **anydb**:
- Or, if you have the GO toolkit installed, just install it like this: - Or, if you have the GO toolkit installed, just install it like this:
```shell ```shell
go install codeberg.org/scip/anydb@latest go install github.com/tlinden/anydb@latest
``` ```
If you do not find a binary release for your platform, please don't If you do not find a binary release for your platform, please don't
@@ -104,14 +98,14 @@ Here, we operate in a local directory `mydb`, which we'll use as HOME
inside the docker container. anydb will store its database in inside the docker container. anydb will store its database in
`mydb/.config/anydb/default.db`. `mydb/.config/anydb/default.db`.
A list of available images is [here](https://codeberg.org/scip/anydb/pkgs/container/anydb/versions?filters%5Bversion_type%5D=tagged) A list of available images is [here](https://github.com/tlinden/anydb/pkgs/container/anydb/versions?filters%5Bversion_type%5D=tagged)
## Documentation ## Documentation
The documentation is provided as a unix man-page. It will be The documentation is provided as a unix man-page. It will be
automatically installed if you install from source. However, you can automatically installed if you install from source. However, you can
[read the man-page online](https://codeberg.org/scip/anydb/blob/master/anydb.pod) [read the man-page online](https://github.com/TLINDEN/anydb/blob/master/anydb.pod)
Or if you cloned the repository you can read it this way (perl needs Or if you cloned the repository you can read it this way (perl needs
to be installed though): `perldoc anydb.pod`. to be installed though): `perldoc anydb.pod`.
@@ -128,7 +122,7 @@ best way for me to forget to do something.
In order to report a bug, unexpected behavior, feature requests or to In order to report a bug, unexpected behavior, feature requests or to
submit a patch, please open an issue on github: submit a patch, please open an issue on github:
https://codeberg.org/scip/anydb/issues. https://github.com/TLINDEN/anydb/issues.
## Copyright and license ## Copyright and license
@@ -140,7 +134,7 @@ T.v.Dein <tom AT vondein DOT org>
## Project homepage ## Project homepage
https://codeberg.org/scip/anydb https://github.com/TLINDEN/anydb
## Copyright and License ## Copyright and License

View File

@@ -1,4 +1,4 @@
.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42)
.\" .\"
.\" Standard preamble: .\" Standard preamble:
.\" ======================================================================== .\" ========================================================================
@@ -133,7 +133,7 @@
.\" ======================================================================== .\" ========================================================================
.\" .\"
.IX Title "ANYDB 1" .IX Title "ANYDB 1"
.TH ANYDB 1 "2025-02-11" "1" "User Commands" .TH ANYDB 1 "2025-02-10" "1" "User Commands"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents. .\" way too many mistakes in technical documents.
.if n .ad l .if n .ad l
@@ -746,7 +746,7 @@ List all keys:
.IX Header "BUGS" .IX Header "BUGS"
In order to report a bug, unexpected behavior, feature requests In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github: or to submit a patch, please open an issue on github:
<https://codeberg.org/scip/anydb/issues>. <https://github.com/TLINDEN/anydb/issues>.
.PP .PP
Please repeat the failing command with debugging enabled \f(CW\*(C`\-d\*(C'\fR and Please repeat the failing command with debugging enabled \f(CW\*(C`\-d\*(C'\fR and
include the output in the issue. include the output in the issue.

View File

@@ -583,7 +583,7 @@ List all keys:
In order to report a bug, unexpected behavior, feature requests In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github: or to submit a patch, please open an issue on github:
L<https://codeberg.org/scip/anydb/issues>. L<https://github.com/TLINDEN/anydb/issues>.
Please repeat the failing command with debugging enabled C<-d> and Please repeat the failing command with debugging enabled C<-d> and
include the output in the issue. include the output in the issue.

101
app/db.go
View File

@@ -20,7 +20,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"log"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
@@ -28,8 +27,6 @@ import (
"strings" "strings"
"time" "time"
common "codeberg.org/scip/anydb/common"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
timestamppb "google.golang.org/protobuf/types/known/timestamppb" timestamppb "google.golang.org/protobuf/types/known/timestamppb"
@@ -63,8 +60,15 @@ type DbTag struct {
Keys []string `json:"key"` Keys []string `json:"key"`
} }
func (entry *DbEntry) Taglist() string { // required for ui
return strings.Join(entry.Tags, ",") func (entry DbEntry) FilterValue() string {
return entry.Preview
}
func (entry DbEntry) Description() string {
return "Val: " + entry.Preview
}
func (entry DbEntry) Title() string {
return "Key: " + entry.Key
} }
const BucketData string = "data" const BucketData string = "data"
@@ -100,14 +104,7 @@ func (db *DB) Open() error {
} }
} }
var opts *bolt.Options b, err := bolt.Open(db.Dbfile, 0600, nil)
if db.Debug {
log := common.Slogger{Logger: slog.Default()}
opts = &bolt.Options{Logger: log}
}
b, err := bolt.Open(db.Dbfile, 0600, opts)
if err != nil { if err != nil {
return fmt.Errorf("failed to open DB %s: %w", db.Dbfile, err) return fmt.Errorf("failed to open DB %s: %w", db.Dbfile, err)
} }
@@ -116,10 +113,8 @@ func (db *DB) Open() error {
return nil return nil
} }
func (db *DB) Close() { func (db *DB) Close() error {
if err := db.DB.Close(); err != nil { return db.DB.Close()
log.Fatal(err)
}
} }
func (db *DB) List(attr *DbAttr, fulltext bool) (DbEntries, error) { func (db *DB) List(attr *DbAttr, fulltext bool) (DbEntries, error) {
@@ -238,29 +233,48 @@ func (db *DB) Set(attr *DbAttr) error {
// check if the entry already exists and if yes, check if it has // check if the entry already exists and if yes, check if it has
// any tags. if so, we initialize our update struct with these // any tags. if so, we initialize our update struct with these
// tags unless it has new tags configured. // tags unless it has new tags configured.
slog.Debug("+++ GET") // FIXME: use Get()
oldentry, err := db.txGet(attr) err := db.DB.View(func(tx *bolt.Tx) error {
if err != nil { root := tx.Bucket([]byte(db.Bucket))
if !strings.Contains(err.Error(), "no such key") { if root == nil {
return err return nil
}
bucket := root.Bucket([]byte("meta"))
if bucket == nil {
return nil
}
slog.Debug("opened buckets", "root", root, "data", bucket)
pbentry := bucket.Get([]byte(entry.Key))
if pbentry == nil {
return nil
}
var oldentry DbEntry
if err := proto.Unmarshal(pbentry, &oldentry); err != nil {
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
} }
}
if oldentry != nil {
if len(oldentry.Tags) > 0 && len(entry.Tags) == 0 { if len(oldentry.Tags) > 0 && len(entry.Tags) == 0 {
// initialize update entry with tags from old entry // initialize update entry with tags from old entry
entry.Tags = oldentry.Tags entry.Tags = oldentry.Tags
} }
return nil
})
if err != nil {
return err
} }
slog.Debug("+++ MARSHAL")
// marshall our data // marshall our data
pbentry, err := proto.Marshal(&entry) pbentry, err := proto.Marshal(&entry)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshall protobuf: %w", err) return fmt.Errorf("failed to marshall protobuf: %w", err)
} }
slog.Debug("+++ UPDATE")
err = db.DB.Update(func(tx *bolt.Tx) error { err = db.DB.Update(func(tx *bolt.Tx) error {
// create root bucket // create root bucket
root, err := tx.CreateBucketIfNotExists([]byte(db.Bucket)) root, err := tx.CreateBucketIfNotExists([]byte(db.Bucket))
@@ -304,10 +318,12 @@ func (db *DB) Set(attr *DbAttr) error {
return nil return nil
} }
// internal DB getter, assumes db.DB has already been func (db *DB) Get(attr *DbAttr) (*DbEntry, error) {
// opened successfully. Do NOT call this w/o valid if err := db.Open(); err != nil {
// DB handle! return nil, err
func (db *DB) txGet(attr *DbAttr) (*DbEntry, error) { }
defer db.Close()
entry := DbEntry{} entry := DbEntry{}
err := db.DB.View(func(tx *bolt.Tx) error { err := db.DB.View(func(tx *bolt.Tx) error {
@@ -358,26 +374,11 @@ func (db *DB) txGet(attr *DbAttr) (*DbEntry, error) {
return nil return nil
}) })
if err != nil {
return nil, err
}
return &entry, nil
}
func (db *DB) Get(attr *DbAttr) (*DbEntry, error) {
if err := db.Open(); err != nil {
return nil, err
}
defer db.Close()
entry, err := db.txGet(attr)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read from DB: %w", err) return nil, fmt.Errorf("failed to read from DB: %w", err)
} }
return entry, nil return &entry, nil
} }
func (db *DB) Del(attr *DbAttr) error { func (db *DB) Del(attr *DbAttr) error {
@@ -387,14 +388,8 @@ func (db *DB) Del(attr *DbAttr) error {
defer db.Close() defer db.Close()
err := db.DB.Update(func(tx *bolt.Tx) error { err := db.DB.Update(func(tx *bolt.Tx) error {
// root bucket bucket := tx.Bucket([]byte(db.Bucket))
root := tx.Bucket([]byte(db.Bucket))
if root == nil {
return nil
}
// get data sub bucket
bucket := root.Bucket([]byte("meta"))
if bucket == nil { if bucket == nil {
return nil return nil
} }

View File

@@ -2,8 +2,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.5 // protoc-gen-go v1.36.1
// protoc v4.24.4 // protoc v3.21.12
// source: app/dbentry.proto // source: app/dbentry.proto
package app package app
@@ -14,7 +14,6 @@ import (
timestamppb "google.golang.org/protobuf/types/known/timestamppb" timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect" reflect "reflect"
sync "sync" sync "sync"
unsafe "unsafe"
) )
const ( const (
@@ -134,7 +133,7 @@ func (x *DbEntry) GetValue() string {
var File_app_dbentry_proto protoreflect.FileDescriptor var File_app_dbentry_proto protoreflect.FileDescriptor
var file_app_dbentry_proto_rawDesc = string([]byte{ var file_app_dbentry_proto_rawDesc = []byte{
0x0a, 0x11, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x62, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x0a, 0x11, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x62, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x70, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x70, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
@@ -157,16 +156,16 @@ var file_app_dbentry_proto_rawDesc = string([]byte{
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x6c, 0x69, 0x6e, 0x64, 0x65,
0x6e, 0x2f, 0x61, 0x6e, 0x79, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x6e, 0x2f, 0x61, 0x6e, 0x79, 0x64, 0x62, 0x2f, 0x61, 0x70, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33, 0x74, 0x6f, 0x33,
}) }
var ( var (
file_app_dbentry_proto_rawDescOnce sync.Once file_app_dbentry_proto_rawDescOnce sync.Once
file_app_dbentry_proto_rawDescData []byte file_app_dbentry_proto_rawDescData = file_app_dbentry_proto_rawDesc
) )
func file_app_dbentry_proto_rawDescGZIP() []byte { func file_app_dbentry_proto_rawDescGZIP() []byte {
file_app_dbentry_proto_rawDescOnce.Do(func() { file_app_dbentry_proto_rawDescOnce.Do(func() {
file_app_dbentry_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_dbentry_proto_rawDesc), len(file_app_dbentry_proto_rawDesc))) file_app_dbentry_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dbentry_proto_rawDescData)
}) })
return file_app_dbentry_proto_rawDescData return file_app_dbentry_proto_rawDescData
} }
@@ -194,7 +193,7 @@ func file_app_dbentry_proto_init() {
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_dbentry_proto_rawDesc), len(file_app_dbentry_proto_rawDesc)), RawDescriptor: file_app_dbentry_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 1, NumMessages: 1,
NumExtensions: 0, NumExtensions: 0,
@@ -205,6 +204,7 @@ func file_app_dbentry_proto_init() {
MessageInfos: file_app_dbentry_proto_msgTypes, MessageInfos: file_app_dbentry_proto_msgTypes,
}.Build() }.Build()
File_app_dbentry_proto = out.File File_app_dbentry_proto = out.File
file_app_dbentry_proto_rawDesc = nil
file_app_dbentry_proto_goTypes = nil file_app_dbentry_proto_goTypes = nil
file_app_dbentry_proto_depIdxs = nil file_app_dbentry_proto_depIdxs = nil
} }

View File

@@ -5,7 +5,7 @@ package app;
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
option go_package = "codeberg.org/scip/anydb/app"; option go_package = "github.com/tlinden/anydb/app";
message DbEntry { message DbEntry {
string Id = 1; string Id = 1;

View File

@@ -20,7 +20,8 @@ import "os"
func cleanError(file string, err error) error { func cleanError(file string, err error) error {
// remove given [backup] file and forward the given error // remove given [backup] file and forward the given error
return os.Remove(file) os.Remove(file)
return err
} }
func fileExists(filename string) bool { func fileExists(filename string) bool {

View File

@@ -1,5 +1,5 @@
/* /*
Copyright © 2025 Thomas von Dein Copyright © 2024 Thomas von Dein
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -22,11 +22,11 @@ import (
"os" "os"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/common" "github.com/tlinden/anydb/common"
) )
var Version string = "v0.2.6" var Version string = "v0.2.0"
type BucketConfig struct { type BucketConfig struct {
Encrypt bool Encrypt bool

View File

@@ -517,7 +517,7 @@ REST API
BUGS BUGS
In order to report a bug, unexpected behavior, feature requests or to In order to report a bug, unexpected behavior, feature requests or to
submit a patch, please open an issue on github: submit a patch, please open an issue on github:
<https://codeberg.org/scip/anydb/issues>. <https://github.com/TLINDEN/anydb/issues>.
Please repeat the failing command with debugging enabled "-d" and Please repeat the failing command with debugging enabled "-d" and
include the output in the issue. include the output in the issue.

View File

@@ -22,9 +22,9 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/output" "github.com/tlinden/anydb/output"
) )
func Set(conf *cfg.Config) *cobra.Command { func Set(conf *cfg.Config) *cobra.Command {
@@ -156,7 +156,7 @@ func Del(conf *cfg.Config) *cobra.Command {
Long: `Delete key and value matching key`, Long: `Delete key and value matching key`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 { if len(args) == 0 {
return errors.New("no key specified") return errors.New("No key specified")
} }
// errors at this stage do not cause the usage to be shown // errors at this stage do not cause the usage to be shown

View File

@@ -21,15 +21,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"os/exec" "os/exec"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/output" "github.com/tlinden/anydb/output"
"codeberg.org/scip/anydb/rest" "github.com/tlinden/anydb/rest"
"github.com/tlinden/anydb/ui"
) )
func Export(conf *cfg.Config) *cobra.Command { func Export(conf *cfg.Config) *cobra.Command {
@@ -286,11 +287,7 @@ func editContent(editor string, content string) (string, error) {
if err != nil { if err != nil {
return "", fmt.Errorf("failed to create templ file: %w", err) return "", fmt.Errorf("failed to create templ file: %w", err)
} }
defer func() { defer os.Remove(tmp.Name())
if err := os.Remove(tmp.Name()); err != nil {
log.Fatal(err)
}
}()
// put the content into a tmp file // put the content into a tmp file
_, err = tmp.WriteString(content) _, err = tmp.WriteString(content)
@@ -315,11 +312,7 @@ func editContent(editor string, content string) (string, error) {
if err != nil { if err != nil {
return "", fmt.Errorf("failed to open temp file: %w", err) return "", fmt.Errorf("failed to open temp file: %w", err)
} }
defer func() { defer modified.Close()
if err := modified.Close(); err != nil {
log.Fatal(err)
}
}()
newcontent, err := io.ReadAll(modified) newcontent, err := io.ReadAll(modified)
if err != nil { if err != nil {
@@ -333,3 +326,31 @@ func editContent(editor string, content string) (string, error) {
return newcontentstr, nil return newcontentstr, nil
} }
func Shell(conf *cfg.Config) *cobra.Command {
var cmd = &cobra.Command{
Use: "shell",
Short: "shell",
Long: `interactive ui`,
RunE: func(cmd *cobra.Command, args []string) error {
// errors at this stage do not cause the usage to be shown
cmd.SilenceUsage = true
entries, err := conf.DB.List(&app.DbAttr{}, conf.Fulltext)
if err != nil {
return err
}
p := tea.NewProgram(ui.NewModel(conf, entries), tea.WithAltScreen())
if _, err := p.Run(); err != nil {
return err
}
return nil
},
}
cmd.PersistentFlags().BoolVarP(&conf.NoHumanize, "no-human", "N", false, "do not translate to human readable values")
return cmd
}

View File

@@ -24,9 +24,10 @@ import (
"path/filepath" "path/filepath"
"runtime/debug" "runtime/debug"
slogmulti "github.com/samber/slog-multi"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
"github.com/tlinden/yadu" "github.com/tlinden/yadu"
) )
@@ -90,13 +91,25 @@ func Execute() {
slog.SetLogLoggerLevel(slog.LevelDebug) slog.SetLogLoggerLevel(slog.LevelDebug)
handler := yadu.NewHandler(os.Stdout, opts) dbg, err := os.Create("debug.log")
debuglogger := slog.New(handler).With( if err != nil {
return err
}
// FIXME: control this with a flag!
//outhandler := yadu.NewHandler(os.Stdout, opts)
filehandler := yadu.NewHandler(dbg, opts)
debuglogger := slog.New(slogmulti.Fanout(
//outhandler,
filehandler,
)).With(
slog.Group("program_info", slog.Group("program_info",
slog.Int("pid", os.Getpid()), slog.Int("pid", os.Getpid()),
slog.String("go_version", buildInfo.GoVersion), slog.String("go_version", buildInfo.GoVersion),
), ),
) )
slog.SetDefault(debuglogger) slog.SetDefault(debuglogger)
slog.Debug("parsed config", "conf", conf) slog.Debug("parsed config", "conf", conf)
@@ -157,6 +170,7 @@ func Execute() {
rootCmd.AddCommand(Man(&conf)) rootCmd.AddCommand(Man(&conf))
rootCmd.AddCommand(Info(&conf)) rootCmd.AddCommand(Info(&conf))
rootCmd.AddCommand(Edit(&conf)) rootCmd.AddCommand(Edit(&conf))
rootCmd.AddCommand(Shell(&conf))
err = rootCmd.Execute() err = rootCmd.Execute()
if err != nil { if err != nil {

View File

@@ -20,7 +20,8 @@ import "os"
func CleanError(file string, err error) error { func CleanError(file string, err error) error {
// remove given [backup] file and forward the given error // remove given [backup] file and forward the given error
return os.Remove(file) os.Remove(file)
return err
} }
func FileExists(filename string) bool { func FileExists(filename string) bool {

View File

@@ -1,23 +0,0 @@
package common
import (
"fmt"
"log/slog"
)
type Slogger struct {
*slog.Logger
}
func (l Slogger) Debug(v ...interface{}) {}
func (l Slogger) Debugf(format string, v ...interface{}) { l.Logger.Debug(fmt.Sprintf(format, v...)) }
func (l Slogger) Error(v ...interface{}) {}
func (l Slogger) Errorf(format string, v ...interface{}) { l.Logger.Error(fmt.Sprintf(format, v...)) }
func (l Slogger) Info(v ...interface{}) {}
func (l Slogger) Infof(format string, v ...interface{}) { l.Logger.Info(fmt.Sprintf(format, v...)) }
func (l Slogger) Warning(v ...interface{}) {}
func (l Slogger) Warningf(format string, v ...interface{}) { l.Logger.Warn(fmt.Sprintf(format, v...)) }
func (l Slogger) Fatal(v ...interface{}) {}
func (l Slogger) Fatalf(format string, v ...interface{}) { l.Logger.Error(fmt.Sprintf(format, v...)) }
func (l Slogger) Panic(v ...interface{}) {}
func (l Slogger) Panicf(format string, v ...interface{}) { l.Logger.Error(fmt.Sprintf(format, v...)) }

View File

@@ -1,95 +0,0 @@
#!/bin/sh
template="{{.Key}} {{.Created.AsTime.Year}}-{{.Created.AsTime.Month}}-{{.Created.AsTime.Day}} {{.Taglist}} {{.Preview}}"
header="TITLE DATE TAGS PREVIEW"
# its possible to use another version of anydb for testing purposes
anydb="${ANYDB:-anydb}"
# list command
command="( echo '$header'; $anydb ls -m template --template '$template' ) | column -t -l4"
for binary in fzf $anydb column diff awk less; do
if ! type $binary > /dev/null 2>&1; then
echo "$binary is not installed!"
exit 1
fi
done
if type gum > /dev/null 2>&1; then
GUM=1
fi
_rand() {
awk 'BEGIN {srand(); printf( "%d\n", 1024 * rand() )}'
}
_list() {
(
echo "$header"
$anydb ls -m template --template "$template"
) | column -t -l4
}
_updater() {
_port="$1"
_cache="/tmp/anydbcache.$port"
_current="/tmp/anydbcache.$port.current"
touch $_current $_cache
while :; do
sleep 10
_list > $_current
if ! diff -q $_current $_cache > /dev/null 2>&1; then
curl -d "reload($command)+clear-screen" "http://127.0.0.1:$_port"
fi
cp $_current $_cache
done
}
_cleanup() {
# get rid of the update child
kill $pid
# clean up reloader cache
rm -f /tmp/anydbcache.${port}*
}
# fork background updater
port=$((8000 + $(_rand) % 1000))
_updater $port &
pid=$!
db=$($anydb info | grep Database | cut -d: -f2)
shorthelp="$db - [enter]read [c-e]edit [c-k]kill [c-c]exit [c-k]delete"
if test -n "$GUM"; then
color="Color \"#ff\" \"#0000ff\"" # white on blue
db="{{ $color \"Database:\"}}$db"
enter="{{ $color \"[Enter]\"}} Read"
edit="{{ $color \"[ctrl-c]\"}} Edit"
delete="{{ $color \"[ctrl-k]\"}} Delete"
template="$db $enter $edit $delete"
shorthelp=$(echo "$template" | gum format -t template)
fi
trap '_cleanup; (exit $?); exit' INT TERM EXIT
: | command="$command" fzf \
--bind "start:reload:$command" \
--header-lines 1 --layout=reverse --info=inline \
--height 100% --pointer="→" --separator="─" \
--scrollbar="│" --preview-window "right:50%" \
--border-label="$shorthelp" \
--border=bottom --layout=reverse --info=inline \
--height 100% --header-first --cycle --header-lines=1 --listen=$port \
--bind "enter:execute: clear; $anydb get {1} | less" \
--bind "ctrl-e:execute: $anydb edit {1}" \
--bind "ctrl-k:execute:$anydb del {1}"

View File

@@ -177,6 +177,6 @@ Enter
Sleep 3s Sleep 3s
Enter Enter
Type "# Try it out yourself: codeberg.org/scip/anydb!" Type "# Try it out yourself: github.com/tlinden/anydb!"
Enter Enter
Sleep 4s Sleep 4s

55
go.mod
View File

@@ -1,40 +1,59 @@
module codeberg.org/scip/anydb module github.com/tlinden/anydb
go 1.24.0 go 1.23
toolchain go1.24.1 toolchain go1.23.5
require ( require (
github.com/alecthomas/repr v0.4.0
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/gofiber/fiber/v2 v2.52.9 github.com/gofiber/fiber/v2 v2.52.6
github.com/inconshreveable/mousetrap v1.1.0 github.com/inconshreveable/mousetrap v1.1.0
github.com/olekukonko/tablewriter v1.1.0 github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/rogpeppe/go-internal v1.14.1 github.com/rogpeppe/go-internal v1.13.1
github.com/spf13/cobra v1.10.1 github.com/spf13/cobra v1.8.1
github.com/tlinden/yadu v0.1.3 go.etcd.io/bbolt v1.4.0
go.etcd.io/bbolt v1.4.3 golang.org/x/crypto v0.31.0
golang.org/x/crypto v0.42.0 golang.org/x/term v0.27.0
golang.org/x/term v0.35.0 google.golang.org/protobuf v1.36.5
google.golang.org/protobuf v1.36.9
) )
require ( require (
github.com/andybalholm/brotli v1.1.1 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/bubbles v0.20.0 // indirect
github.com/charmbracelet/bubbletea v1.3.3 // indirect
github.com/charmbracelet/lipgloss v1.0.0 // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.16.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/gofiber/fiber/v3 v3.0.0-beta.3 // indirect
github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // 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/mattn/go-runewidth v0.0.16 // indirect
github.com/olekukonko/errors v1.1.0 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/olekukonko/ll v0.0.9 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/muesli/termenv v0.15.2 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/sahilm/fuzzy v0.1.1 // indirect
github.com/samber/lo v1.49.1 // indirect
github.com/samber/slog-multi v1.4.0 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/tlinden/yadu v0.1.3 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.36.0 // indirect golang.org/x/sync v0.11.0 // indirect
golang.org/x/tools v0.26.0 // indirect golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.22.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

162
go.sum
View File

@@ -1,75 +1,163 @@
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
github.com/charmbracelet/bubbletea v1.3.3 h1:WpU6fCY0J2vDWM3zfS3vIDi/ULq3SYphZhkAGGvmEUY=
github.com/charmbracelet/bubbletea v1.3.3/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
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/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/samber/slog-multi v1.4.0 h1:pwlPMIE7PrbTHQyKWDU+RIoxP1+HKTNOujk3/kdkbdg=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/samber/slog-multi v1.4.0/go.mod h1:FsQ4Uv2L+E/8TZt+/BVgYZ1LoDWCbfCU21wVIoMMrO8=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY= github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA= github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -24,7 +24,7 @@ import (
"runtime" "runtime"
"github.com/inconshreveable/mousetrap" "github.com/inconshreveable/mousetrap"
"codeberg.org/scip/anydb/cmd" "github.com/tlinden/anydb/cmd"
) )
func main() { func main() {
@@ -41,7 +41,7 @@ func init() {
// thus give the user time to read it. // thus give the user time to read it.
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
if mousetrap.StartedByExplorer() { if mousetrap.StartedByExplorer() {
fmt.Println("Do no double click anydb.exe!") fmt.Println("Do no double click kleingebaeck.exe!")
fmt.Println("Please open a command shell and run it from there.") fmt.Println("Please open a command shell and run it from there.")
fmt.Println() fmt.Println()
fmt.Print("Press any key to quit: ") fmt.Print("Press any key to quit: ")

View File

@@ -17,15 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
import ( import (
"os"
"testing" "testing"
"github.com/rogpeppe/go-internal/testscript" "github.com/rogpeppe/go-internal/testscript"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
testscript.Main(m, map[string]func(){ os.Exit(testscript.RunMain(m, map[string]func() int{
"anydb": main, "anydb": Main,
}) }))
} }
func TestAnydb(t *testing.T) { func TestAnydb(t *testing.T) {

View File

@@ -52,15 +52,8 @@ for D in $DIST; do
tardir="${tool}-${os}-${arch}-${version}" tardir="${tool}-${os}-${arch}-${version}"
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz" tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
if test "$D" = "linux/amd64"; then
pie="-buildmode=pie"
fi
set -x set -x
GOOS=${os} GOARCH=${arch} go build -tags osusergo,netgo -ldflags "-extldflags=-static -w" --trimpath $pie -o ${binfile} GOOS=${os} GOARCH=${arch} go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o ${binfile}
strip --strip-all ${binfile}
mkdir -p ${tardir} mkdir -p ${tardir}
cp ${binfile} README.md LICENSE ${tardir}/ cp ${binfile} README.md LICENSE ${tardir}/
echo 'tool = anydb echo 'tool = anydb

View File

@@ -21,8 +21,8 @@ import (
"fmt" "fmt"
"os" "os"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
) )
func WriteJSON(attr *app.DbAttr, conf *cfg.Config, entries app.DbEntries) error { func WriteJSON(attr *app.DbAttr, conf *cfg.Config, entries app.DbEntries) error {

View File

@@ -1,5 +1,5 @@
/* /*
Copyright © 2025 Thomas von Dein Copyright © 2024 Thomas von Dein
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -28,10 +28,8 @@ import (
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer" "github.com/tlinden/anydb/app"
"github.com/olekukonko/tablewriter/tw" "github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
) )
func List(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error { func List(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error {
@@ -73,9 +71,7 @@ func ListTemplate(writer io.Writer, conf *cfg.Config, entries app.DbEntries) err
} }
if buf.Len() > 0 { if buf.Len() > 0 {
if _, err := fmt.Fprintln(writer, buf.String()); err != nil { fmt.Fprintln(writer, buf.String())
return fmt.Errorf("failed to write output: %w", err)
}
} }
} }
@@ -84,46 +80,13 @@ func ListTemplate(writer io.Writer, conf *cfg.Config, entries app.DbEntries) err
func ListTable(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error { func ListTable(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error {
tableString := &strings.Builder{} tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString)
styleTSV := tw.NewSymbolCustom("space").WithColumn("\t")
table := tablewriter.NewTable(tableString,
tablewriter.WithRenderer(
renderer.NewBlueprint(tw.Rendition{
Borders: tw.BorderNone,
Symbols: styleTSV,
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.On},
Lines: tw.Lines{ShowFooterLine: tw.Off, ShowHeaderLine: tw.Off},
},
})),
tablewriter.WithConfig(tablewriter.Config{
Header: tw.CellConfig{
Formatting: tw.CellFormatting{
AutoFormat: tw.Off,
},
Padding: tw.CellPadding{
Global: tw.Padding{Left: "", Right: ""},
},
},
Row: tw.CellConfig{
Formatting: tw.CellFormatting{
AutoWrap: tw.WrapNone,
Alignment: tw.AlignLeft,
},
Padding: tw.CellPadding{
Global: tw.Padding{Left: "", Right: ""},
},
},
}),
tablewriter.WithPadding(tw.PaddingNone),
)
if !conf.NoHeaders { if !conf.NoHeaders {
if conf.Mode == "wide" { if conf.Mode == "wide" {
table.Header([]string{"KEY", "TAGS", "SIZE", "UPDATED", "VALUE"}) table.SetHeader([]string{"KEY", "TAGS", "SIZE", "UPDATED", "VALUE"})
} else { } else {
table.Header([]string{"KEY", "VALUE"}) table.SetHeader([]string{"KEY", "VALUE"})
} }
} }
@@ -131,42 +94,44 @@ func ListTable(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error
if conf.Mode == "wide" { if conf.Mode == "wide" {
switch conf.NoHumanize { switch conf.NoHumanize {
case true: case true:
if err := table.Append([]string{
table.Append([]string{ row.Key,
row.Key, strings.Join(row.Tags, ","),
strings.Join(row.Tags, ","), strconv.FormatUint(row.Size, 10),
strconv.FormatUint(row.Size, 10), row.Created.AsTime().Format("02.01.2006T03:04.05"),
row.Created.AsTime().Format("02.01.2006T03:04.05"), row.Preview,
row.Preview, })
}); err != nil {
return fmt.Errorf("failed to add data to table: %w", err)
}
default: default:
if err := table.Append([]string{ table.Append([]string{
row.Key, row.Key,
strings.Join(row.Tags, ","), strings.Join(row.Tags, ","),
humanize.Bytes(uint64(row.Size)), humanize.Bytes(uint64(row.Size)),
humanize.Time(row.Created.AsTime()), humanize.Time(row.Created.AsTime()),
row.Preview, row.Preview,
}); err != nil { })
return fmt.Errorf("failed to add data to table: %w", err)
}
} }
} else { } else {
if err := table.Append([]string{row.Key, row.Preview}); err != nil { table.Append([]string{row.Key, row.Preview})
return fmt.Errorf("failed to add data to table: %w", err)
}
} }
} }
if err := table.Render(); err != nil { table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
return fmt.Errorf("failed to render table: %w", err) table.SetAutoWrapText(false)
} table.SetAutoFormatHeaders(true)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetNoWhiteSpace(true)
if _, err := fmt.Fprint(writer, tableString.String()); err != nil { table.SetTablePadding("\t") // pad with tabs
return fmt.Errorf("failed to write output: %w", err)
} table.Render()
fmt.Fprint(writer, tableString.String())
return nil return nil
} }

View File

@@ -20,13 +20,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"reflect" "reflect"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
"golang.org/x/term" "golang.org/x/term"
//"github.com/alecthomas/repr" //"github.com/alecthomas/repr"
) )
@@ -44,9 +43,7 @@ func Print(writer io.Writer, conf *cfg.Config, attr *app.DbAttr, entry *app.DbEn
if isatty { if isatty {
fmt.Println("binary data omitted") fmt.Println("binary data omitted")
} else { } else {
if _, err := os.Stdout.WriteString(entry.Value); err != nil { os.Stdout.WriteString(entry.Value)
return err
}
} }
} else { } else {
fmt.Print(string(entry.Value)) fmt.Print(string(entry.Value))
@@ -82,11 +79,7 @@ func WriteFile(writer io.Writer, conf *cfg.Config, attr *app.DbAttr, entry *app.
if err != nil { if err != nil {
return fmt.Errorf("failed to open file %s for writing: %w", attr.File, err) return fmt.Errorf("failed to open file %s for writing: %w", attr.File, err)
} }
defer func() { defer fd.Close()
if err := fd.Close(); err != nil {
log.Fatal(err)
}
}()
fileHandle = fd fileHandle = fd
} }
@@ -109,45 +102,34 @@ func WriteFile(writer io.Writer, conf *cfg.Config, attr *app.DbAttr, entry *app.
} }
func Info(writer io.Writer, conf *cfg.Config, info *app.DbInfo) error { func Info(writer io.Writer, conf *cfg.Config, info *app.DbInfo) error {
if _, err := fmt.Fprintf(writer, "Database: %s\n", info.Path); err != nil { fmt.Fprintf(writer, "Database: %s\n", info.Path)
return fmt.Errorf("failed to write output: %w", err)
}
for _, bucket := range info.Buckets { for _, bucket := range info.Buckets {
if conf.NoHumanize { if conf.NoHumanize {
if _, err := fmt.Fprintf( fmt.Fprintf(
writer, writer,
"%19s: %s\n%19s: %d\n%19s: %d\n%19s: %t\n", "%19s: %s\n%19s: %d\n%19s: %d\n%19s: %t\n",
"Bucket", bucket.Name, "Bucket", bucket.Name,
"Size", bucket.Size, "Size", bucket.Size,
"Keys", bucket.Keys, "Keys", bucket.Keys,
"Encrypted", conf.Encrypt); err != nil { "Encrypted", conf.Encrypt)
return fmt.Errorf("failed to write output: %w", err)
}
} else { } else {
if _, err := fmt.Fprintf( fmt.Fprintf(
writer, writer,
"%19s: %s\n%19s: %s\n%19s: %d\n", "%19s: %s\n%19s: %s\n%19s: %d\n",
"Bucket", bucket.Name, "Bucket", bucket.Name,
"Size", humanize.Bytes(uint64(bucket.Size)), "Size", humanize.Bytes(uint64(bucket.Size)),
"Keys", bucket.Keys); err != nil { "Keys", bucket.Keys)
return fmt.Errorf("failed to write output: %w", err)
}
} }
if conf.Debug { if conf.Debug {
val := reflect.ValueOf(&bucket.Stats).Elem() val := reflect.ValueOf(&bucket.Stats).Elem()
for i := 0; i < val.NumField(); i++ { for i := 0; i < val.NumField(); i++ {
if _, err := fmt.Fprintf(writer, "%19s: %v\n", val.Type().Field(i).Name, val.Field(i)); err != nil { fmt.Fprintf(writer, "%19s: %v\n", val.Type().Field(i).Name, val.Field(i))
return fmt.Errorf("failed to write output: %w", err)
}
} }
} }
if _, err := fmt.Fprintln(writer); err != nil { fmt.Fprintln(writer)
return fmt.Errorf("failed to write output: %w", err)
}
} }
return nil return nil
} }

View File

@@ -20,8 +20,8 @@ import (
//"github.com/alecthomas/repr" //"github.com/alecthomas/repr"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"codeberg.org/scip/anydb/app" "github.com/tlinden/anydb/app"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
) )
type SetContext struct { type SetContext struct {

View File

@@ -21,7 +21,7 @@ import (
"github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/logger"
"codeberg.org/scip/anydb/cfg" "github.com/tlinden/anydb/cfg"
) )
// used to return to the api client // used to return to the api client
@@ -104,7 +104,11 @@ Wrapper to respond with proper json status, message and code,
shall be prepared and called by the handlers directly. shall be prepared and called by the handlers directly.
*/ */
func JsonStatus(c *fiber.Ctx, code int, msg string) error { func JsonStatus(c *fiber.Ctx, code int, msg string) error {
success := code == fiber.StatusOK success := true
if code != fiber.StatusOK {
success = false
}
return c.Status(code).JSON(Result{ return c.Status(code).JSON(Result{
Code: code, Code: code,

View File

@@ -78,4 +78,4 @@ exec anydb -f test.db del foo
# check deleted # check deleted
exec anydb -f test.db list exec anydb -f test.db list
! stdout blah ! stdout bar

99
ui/delegate.go Normal file
View File

@@ -0,0 +1,99 @@
package ui
import (
"log"
"log/slog"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
)
func newItemDelegate(keys *delegateKeyMap, config *cfg.Config) list.DefaultDelegate {
d := list.NewDefaultDelegate()
d.UpdateFunc = func(msg tea.Msg, m *list.Model) tea.Cmd {
var title string
if entry, ok := m.SelectedItem().(item); ok {
title = entry.Title()
slog.Debug("active entry", "entry", title)
} else {
slog.Debug("no active entry")
return nil
}
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.choose):
return m.NewStatusMessage(statusMessageStyle("You chose " + title))
case key.Matches(msg, keys.remove):
if err := config.DB.Del(&app.DbAttr{Key: title}); err != nil {
log.Fatal(err)
}
index := m.Index()
m.RemoveItem(index)
if len(m.Items()) == 0 {
keys.remove.SetEnabled(false)
}
return m.NewStatusMessage(statusMessageStyle("Deleted " + title))
}
}
return nil
}
help := []key.Binding{keys.choose, keys.remove}
d.ShortHelpFunc = func() []key.Binding {
return help
}
d.FullHelpFunc = func() [][]key.Binding {
return [][]key.Binding{help}
}
return d
}
type delegateKeyMap struct {
choose key.Binding
remove key.Binding
}
// Additional short help entries. This satisfies the help.KeyMap interface and
// is entirely optional.
func (d delegateKeyMap) ShortHelp() []key.Binding {
return []key.Binding{
d.choose,
d.remove,
}
}
// Additional full help entries. This satisfies the help.KeyMap interface and
// is entirely optional.
func (d delegateKeyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{
d.choose,
d.remove,
},
}
}
func newDelegateKeyMap() *delegateKeyMap {
return &delegateKeyMap{
choose: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "choose"),
),
remove: key.NewBinding(
key.WithKeys("x", "backspace"),
key.WithHelp("x", "delete"),
),
}
}

95
ui/root.bak Normal file
View File

@@ -0,0 +1,95 @@
/*
Copyright © 2024 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ui
import (
"fmt"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/tlinden/anydb/cfg"
)
type model struct {
spinner spinner.Model
conf *cfg.Config
quitting bool
err error
}
var quitKeys = key.NewBinding(
key.WithKeys("q", "esc", "ctrl+c"),
key.WithHelp("", "press q to quit"),
)
var (
appStyle = lipgloss.NewStyle().Padding(1, 2)
titleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFFDF5")).
Background(lipgloss.Color("#25A065")).
Padding(0, 1)
statusMessageStyle = lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).
Render
)
func InitialModel(conf *cfg.Config) model {
s := spinner.New()
s.Spinner = spinner.Dot
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
return model{spinner: s, conf: conf}
}
func (m model) Init() tea.Cmd {
return m.spinner.Tick
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
if key.Matches(msg, quitKeys) {
m.quitting = true
return m, tea.Quit
}
return m, nil
case error:
m.err = msg
return m, nil
default:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}
}
func (m model) View() string {
if m.err != nil {
return m.err.Error()
}
str := fmt.Sprintf("\n\n %s Loading forever... %s\n\n", m.spinner.View(), quitKeys.Help().Desc)
if m.quitting {
return str + "\n"
}
return str
}

213
ui/root.go Normal file
View File

@@ -0,0 +1,213 @@
/*
Copyright © 2024 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ui
import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
)
var (
appStyle = lipgloss.NewStyle().Padding(1, 2)
titleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFFDF5")).
Background(lipgloss.Color("#25A065")).
Padding(0, 1)
statusMessageStyle = lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).
Render
)
type Loader struct {
items []list.Item
conf *cfg.Config
}
func (loader *Loader) Update() error {
entries, err := loader.conf.DB.List(&app.DbAttr{}, loader.conf.Fulltext)
if err != nil {
return err
}
loader.items = nil
for _, entry := range entries {
loader.items = append(loader.items, item{
title: entry.Key,
description: entry.Preview,
})
}
return nil
}
type model struct {
conf *cfg.Config
loader *Loader
quitting bool
err error
list list.Model
keys *listKeyMap
delegateKeys *delegateKeyMap
}
type listKeyMap struct {
toggleSpinner key.Binding
toggleTitleBar key.Binding
toggleStatusBar key.Binding
togglePagination key.Binding
toggleHelpMenu key.Binding
insertItem key.Binding
}
type item struct {
title string
description string
}
func (i item) Title() string { return i.title }
func (i item) Description() string { return i.description }
func (i item) FilterValue() string { return i.title }
func newListKeyMap() *listKeyMap {
return &listKeyMap{
insertItem: key.NewBinding(
key.WithKeys("a"),
key.WithHelp("a", "add item"),
),
toggleSpinner: key.NewBinding(
key.WithKeys("s"),
key.WithHelp("s", "toggle spinner"),
),
toggleTitleBar: key.NewBinding(
key.WithKeys("T"),
key.WithHelp("T", "toggle title"),
),
toggleStatusBar: key.NewBinding(
key.WithKeys("S"),
key.WithHelp("S", "toggle status"),
),
togglePagination: key.NewBinding(
key.WithKeys("P"),
key.WithHelp("P", "toggle pagination"),
),
toggleHelpMenu: key.NewBinding(
key.WithKeys("H"),
key.WithHelp("H", "toggle help"),
),
}
}
func NewModel(config *cfg.Config, entries app.DbEntries) model {
var (
delegateKeys = newDelegateKeyMap()
listKeys = newListKeyMap()
loader = Loader{conf: config}
)
// Setup list
if err := loader.Update(); err != nil {
panic(err)
}
delegate := newItemDelegate(delegateKeys, config)
dbList := list.New(loader.items, delegate, 0, 0)
dbList.Title = "DB Entries"
dbList.Styles.Title = titleStyle
dbList.AdditionalFullHelpKeys = func() []key.Binding {
return []key.Binding{
listKeys.toggleSpinner,
listKeys.insertItem,
listKeys.toggleTitleBar,
listKeys.toggleStatusBar,
listKeys.togglePagination,
listKeys.toggleHelpMenu,
}
}
return model{
list: dbList,
keys: listKeys,
delegateKeys: delegateKeys,
}
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
h, v := appStyle.GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v)
case tea.KeyMsg:
// Don't match any of the keys below if we're actively filtering.
if m.list.FilterState() == list.Filtering {
break
}
switch {
case key.Matches(msg, m.keys.toggleSpinner):
cmd := m.list.ToggleSpinner()
return m, cmd
case key.Matches(msg, m.keys.toggleTitleBar):
v := !m.list.ShowTitle()
m.list.SetShowTitle(v)
m.list.SetShowFilter(v)
m.list.SetFilteringEnabled(v)
return m, nil
case key.Matches(msg, m.keys.toggleStatusBar):
m.list.SetShowStatusBar(!m.list.ShowStatusBar())
return m, nil
case key.Matches(msg, m.keys.togglePagination):
m.list.SetShowPagination(!m.list.ShowPagination())
return m, nil
case key.Matches(msg, m.keys.toggleHelpMenu):
m.list.SetShowHelp(!m.list.ShowHelp())
return m, nil
case key.Matches(msg, m.keys.insertItem):
panic(1)
}
}
// This will also call our delegate's update function.
newListModel, cmd := m.list.Update(msg)
m.list = newListModel
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
}
func (m model) View() string {
return appStyle.Render(m.list.View())
}