mirror of https://github.com/aptly-dev/aptly
132 lines
2.8 KiB
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
|
|
}
|