aptly/deb/contents.go

132 lines
2.8 KiB
Go

package deb
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/aptly-dev/aptly/database"
"github.com/pborman/uuid"
)
// ContentsIndex calculates mapping from files to packages, with sorting and aggregation
type ContentsIndex struct {
db database.Storage
prefix []byte
}
// NewContentsIndex creates empty ContentsIndex
func NewContentsIndex(db database.Storage) *ContentsIndex {
return &ContentsIndex{
db: db,
prefix: []byte(uuid.New()),
}
}
// Push adds package to contents index, calculating package contents as required
func (index *ContentsIndex) Push(qualifiedName []byte, contents []string, dbw database.Writer) error {
for _, path := range contents {
// for performance reasons we only write to leveldb during push.
// merging of qualified names per path will be done in WriteTo
err := dbw.Put(append(append(append(index.prefix, []byte(path)...), byte(0)), qualifiedName...), nil)
if err != nil {
return err
}
}
return nil
}
// Empty checks whether index contains no packages
func (index *ContentsIndex) Empty() bool {
return !index.db.HasPrefix(index.prefix)
}
// WriteTo dumps sorted mapping of files to qualified package names
func (index *ContentsIndex) WriteTo(w io.Writer) (int64, error) {
// For performance reasons push method wrote on key per path and package
// in this method we now need to merge all packages which have the same path
// and write it to contents index file
var n int64
nn, err := fmt.Fprintf(w, "%s %s\n", "FILE", "LOCATION")
n += int64(nn)
if err != nil {
return n, err
}
prefixLen := len(index.prefix)
var (
currentPath []byte
currentPkgs [][]byte
)
err = index.db.ProcessByPrefix(index.prefix, func(key []byte, _ []byte) error {
// cut prefix
key = key[prefixLen:]
i := bytes.Index(key, []byte{0})
if i == -1 {
return errors.New("corrupted index entry")
}
path := key[:i]
pkg := key[i+1:]
if !bytes.Equal(path, currentPath) {
if currentPath != nil {
nn, err = w.Write(append(currentPath, ' '))
n += int64(nn)
if err != nil {
return err
}
nn, err = w.Write(bytes.Join(currentPkgs, []byte{','}))
n += int64(nn)
if err != nil {
return err
}
nn, err = w.Write([]byte{'\n'})
n += int64(nn)
if err != nil {
return err
}
}
currentPath = append([]byte(nil), path...)
currentPkgs = nil
}
currentPkgs = append(currentPkgs, append([]byte(nil), pkg...))
return nil
})
if err != nil {
return n, err
}
if currentPath != nil {
nn, err = w.Write(append(currentPath, ' '))
n += int64(nn)
if err != nil {
return n, err
}
nn, err = w.Write(bytes.Join(currentPkgs, []byte{','}))
n += int64(nn)
if err != nil {
return n, err
}
nn, err = w.Write([]byte{'\n'})
n += int64(nn)
}
return n, err
}