mirror of
https://codeberg.org/scip/anydb.git
synced 2025-12-17 04:20:59 +01:00
finalized conversion to protobuf:
- fixed import+export - generalized file options - always store keys as lowercase - fixed+enhanced docs - fixed tests
This commit is contained in:
16
app/attr.go
16
app/attr.go
@@ -35,16 +35,18 @@ type DbAttr struct {
|
||||
Binary bool
|
||||
}
|
||||
|
||||
// check if value is to be read from a file or stdin, setup preview
|
||||
// text according to flags, lowercase key
|
||||
func (attr *DbAttr) ParseKV() error {
|
||||
attr.Key = strings.ToLower(attr.Args[0])
|
||||
|
||||
switch len(attr.Args) {
|
||||
case 1:
|
||||
// 1 arg = key + read from file or stdin
|
||||
attr.Key = attr.Args[0]
|
||||
if attr.File == "" {
|
||||
attr.File = "-"
|
||||
}
|
||||
case 2:
|
||||
attr.Key = attr.Args[0]
|
||||
attr.Val = []byte(attr.Args[1])
|
||||
|
||||
if attr.Args[1] == "-" {
|
||||
@@ -58,9 +60,12 @@ func (attr *DbAttr) ParseKV() error {
|
||||
}
|
||||
}
|
||||
|
||||
if attr.Binary {
|
||||
switch {
|
||||
case attr.Binary:
|
||||
attr.Preview = "<binary-content>"
|
||||
case attr.Encrypted:
|
||||
attr.Preview = "<encrypted-content>"
|
||||
} else {
|
||||
default:
|
||||
if len(attr.Val) > MaxValueWidth {
|
||||
attr.Preview = string(attr.Val)[0:MaxValueWidth] + "..."
|
||||
|
||||
@@ -74,9 +79,6 @@ func (attr *DbAttr) ParseKV() error {
|
||||
attr.Preview = string(attr.Val)
|
||||
}
|
||||
}
|
||||
if attr.Encrypted {
|
||||
attr.Preview = "<encrypted-content>"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
87
app/db.go
87
app/db.go
@@ -85,7 +85,7 @@ func (db *DB) Close() error {
|
||||
return db.DB.Close()
|
||||
}
|
||||
|
||||
func (db *DB) List(attr *DbAttr) (DbEntries, error) {
|
||||
func (db *DB) List(attr *DbAttr, fulltext bool) (DbEntries, error) {
|
||||
if err := db.Open(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -99,7 +99,6 @@ func (db *DB) List(attr *DbAttr) (DbEntries, error) {
|
||||
}
|
||||
|
||||
err := db.DB.View(func(tx *bolt.Tx) error {
|
||||
|
||||
root := tx.Bucket([]byte(db.Bucket))
|
||||
if root == nil {
|
||||
return nil
|
||||
@@ -110,12 +109,19 @@ func (db *DB) List(attr *DbAttr) (DbEntries, error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
databucket := root.Bucket([]byte("data"))
|
||||
if databucket == nil {
|
||||
return fmt.Errorf("failed to retrieve data sub bucket")
|
||||
}
|
||||
|
||||
err := bucket.ForEach(func(key, pbentry []byte) error {
|
||||
var entry DbEntry
|
||||
if err := proto.Unmarshal(pbentry, &entry); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
|
||||
}
|
||||
|
||||
entry.Value = databucket.Get([]byte(entry.Key)) // empty is ok
|
||||
|
||||
var include bool
|
||||
|
||||
switch {
|
||||
@@ -124,6 +130,12 @@ func (db *DB) List(attr *DbAttr) (DbEntries, error) {
|
||||
filter.MatchString(strings.Join(entry.Tags, " ")) {
|
||||
include = true
|
||||
}
|
||||
|
||||
if !entry.Binary && !include && fulltext {
|
||||
if filter.MatchString(string(entry.Value)) {
|
||||
include = true
|
||||
}
|
||||
}
|
||||
case len(attr.Tags) > 0:
|
||||
for _, search := range attr.Tags {
|
||||
for _, tag := range entry.Tags {
|
||||
@@ -261,35 +273,48 @@ func (db *DB) Get(attr *DbAttr) (*DbEntry, error) {
|
||||
entry := DbEntry{}
|
||||
|
||||
err := db.DB.View(func(tx *bolt.Tx) error {
|
||||
// root bucket
|
||||
root := tx.Bucket([]byte(db.Bucket))
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get meta sub bucket
|
||||
bucket := root.Bucket([]byte("meta"))
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// retrieve meta data
|
||||
pbentry := bucket.Get([]byte(attr.Key))
|
||||
if pbentry == nil {
|
||||
return fmt.Errorf("no such key: %s", attr.Key)
|
||||
}
|
||||
|
||||
// put into struct
|
||||
if err := proto.Unmarshal(pbentry, &entry); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
|
||||
}
|
||||
|
||||
// get data sub bucket
|
||||
databucket := root.Bucket([]byte("data"))
|
||||
if databucket == nil {
|
||||
return fmt.Errorf("failed to retrieve data sub bucket")
|
||||
}
|
||||
|
||||
entry.Value = databucket.Get([]byte(attr.Key))
|
||||
if len(entry.Value) == 0 {
|
||||
// retrieve actual data value
|
||||
value := databucket.Get([]byte(attr.Key))
|
||||
if len(value) == 0 {
|
||||
return fmt.Errorf("no such key: %s", attr.Key)
|
||||
}
|
||||
|
||||
// we need to make a copy of it, otherwise we'll get an
|
||||
// "unexpected fault address" error
|
||||
vc := make([]byte, len(value))
|
||||
copy(vc, value)
|
||||
|
||||
entry.Value = vc
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -446,78 +471,50 @@ func (db *DB) Info() (*DbInfo, error) {
|
||||
return info, err
|
||||
}
|
||||
|
||||
func (db *DB) Find(attr *DbAttr) (DbEntries, error) {
|
||||
func (db *DB) Getall(attr *DbAttr) (DbEntries, error) {
|
||||
if err := db.Open(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
var entries DbEntries
|
||||
var filter *regexp.Regexp
|
||||
|
||||
if len(attr.Args) > 0 {
|
||||
filter = regexp.MustCompile(attr.Args[0])
|
||||
}
|
||||
|
||||
err := db.DB.View(func(tx *bolt.Tx) error {
|
||||
|
||||
// root bucket
|
||||
root := tx.Bucket([]byte(db.Bucket))
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get meta sub bucket
|
||||
bucket := root.Bucket([]byte("meta"))
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get data sub bucket
|
||||
databucket := root.Bucket([]byte("data"))
|
||||
if databucket == nil {
|
||||
return fmt.Errorf("failed to retrieve data sub bucket")
|
||||
}
|
||||
|
||||
// iterate over all db entries in meta sub bucket
|
||||
err := bucket.ForEach(func(key, pbentry []byte) error {
|
||||
var entry DbEntry
|
||||
if err := proto.Unmarshal(pbentry, &entry); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal from protobuf: %w", err)
|
||||
}
|
||||
|
||||
entry.Value = databucket.Get([]byte(entry.Key))
|
||||
// retrieve the value from the data sub bucket
|
||||
value := databucket.Get([]byte(entry.Key))
|
||||
|
||||
var include bool
|
||||
// we need to make a copy of it, otherwise we'll get an
|
||||
// "unexpected fault address" error
|
||||
vc := make([]byte, len(value))
|
||||
copy(vc, value)
|
||||
|
||||
switch {
|
||||
case filter != nil:
|
||||
if filter.MatchString(entry.Key) ||
|
||||
filter.MatchString(strings.Join(entry.Tags, " ")) {
|
||||
include = true
|
||||
}
|
||||
|
||||
if !entry.Binary && !include {
|
||||
if filter.MatchString(string(entry.Value)) {
|
||||
include = true
|
||||
}
|
||||
}
|
||||
case len(attr.Tags) > 0:
|
||||
for _, search := range attr.Tags {
|
||||
for _, tag := range entry.Tags {
|
||||
if tag == search {
|
||||
include = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if include {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
include = true
|
||||
}
|
||||
|
||||
if include {
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
entry.Value = vc
|
||||
entries = append(entries, entry)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user