func (d *DAO) GetKnownUsages(name string) ([]string, error) {
	db, err := d.db()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer db.Close()
	res := []string{}
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(name))
		if b != nil {
			ub := b.Bucket([]byte(environmentsKey))
			if ub != nil {
				return ub.ForEach(func(k, _ []byte) error {
					res = append(res, string(k))
					return nil
				})
			}
		}
		return nil
	})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return res, nil
}
GetKnownUsages returns a list of bin directories where this package has been seen previously
package dao
import (
	"fmt"
	"io"
	"path/filepath"
	"strings"
	"time"
	"github.com/pkg/errors"
	bolt "go.etcd.io/bbolt"
)
const (
	usedAtKey          = "usedAt"
	updateCheckedAtKey = "updateCheckedAt"
	eTagKey            = "etag"
	environmentsKey    = "environments"
	timeformat         = time.RFC3339
)
type DAO struct {
	stateDir string
}
type Package struct {
	UsedAt          time.Time
	Etag            string
	UpdateCheckedAt time.Time
}
func Open(stateDir string) *DAO {
	return &DAO{stateDir: stateDir}
}
func (d *DAO) Dump(w io.Writer) error {
	db, err := d.db()
	if err != nil {
		return errors.WithStack(err)
	}
	tx, err := db.Begin(false)
	if err != nil {
		return errors.WithStack(err)
	}
	return errors.WithStack(tx.ForEach(func(name []byte, b *bolt.Bucket) error {
		fmt.Fprintf(w, "%s\n", name)
		return dumpBucket(w, 2, b)
	}))
}
func (d *DAO) GetPackage(name string) (*Package, error) {
	var pkg *Package
	err := d.view(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(name))
		pkg = packageAt(b)
		return nil
	})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return pkg, nil
}
func (d *DAO) GetUnusedSince(usedAt time.Time) ([]string, error) {
	res := []string{}
	err := d.view(func(tx *bolt.Tx) error {
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			pkg := packageAt(b)
			if pkg.UsedAt.Before(usedAt) {
				res = append(res, string(name))
			}
			return nil
		})
	})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return res, nil
}
func (d *DAO) UpdatePackageWithUsage(binDir string, name string, pkg *Package) error {
	return errors.WithStack(d.update(func(tx *bolt.Tx) error {
		now := time.Now()
		b, err := tx.CreateBucketIfNotExists([]byte(name))
		if err != nil {
			return errors.WithStack(err)
		}
		if err := putPackage(b, pkg); err != nil {
			return errors.WithStack(err)
		}
		ub, err := b.CreateBucketIfNotExists([]byte(environmentsKey))
		if err != nil {
			return errors.WithStack(err)
		}
		return putTime(ub, binDir, now)
	}))
}
func (d *DAO) UpdatePackage(name string, pkg *Package) error {
	return errors.WithStack(d.update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(name))
		if err != nil {
			return errors.WithStack(err)
		}
		return putPackage(b, pkg)
	}))
}
func (d *DAO) PackageRemovedAt(name string, binDir string) error {
	return errors.WithStack(d.update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(name))
		if b != nil {
			ub, err := b.CreateBucketIfNotExists([]byte(environmentsKey))
			if err != nil {
				return errors.WithStack(err)
			}
			return ub.Delete([]byte(binDir))
		}
		return nil
	}))
}