130 lines
2.6 KiB
Go
130 lines
2.6 KiB
Go
package nixstore
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
|
|
"hg.lukegb.com/lukegb/depot/go/nix/nar/narinfo"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
const DefaultStoreDB = "/nix/var/nix/db/db.sqlite"
|
|
|
|
type DB struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func (d *DB) NARInfo(storePath string) (*narinfo.NarInfo, error) {
|
|
stmt, err := d.db.Prepare(`
|
|
SELECT
|
|
vp.id,
|
|
vp.path,
|
|
vp.hash,
|
|
vp.deriver,
|
|
vp.narSize,
|
|
vp.sigs,
|
|
1 FROM
|
|
ValidPaths vp
|
|
WHERE 1=1
|
|
AND vp.path = ?
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("preparing initial statement: %w", err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
ni := narinfo.NarInfo{}
|
|
|
|
var storePathID int
|
|
var dummy int
|
|
var hashStr string
|
|
var deriverStr *string
|
|
var sigsStr *string
|
|
err = stmt.QueryRow(storePath).Scan(
|
|
&storePathID,
|
|
&ni.StorePath,
|
|
&hashStr,
|
|
&deriverStr,
|
|
&ni.NarSize,
|
|
&sigsStr,
|
|
&dummy)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("scanning initial statement: %w", err)
|
|
}
|
|
|
|
ni.NarHash, err = narinfo.HashFromString(hashStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parsing hash %q: %w", hashStr, err)
|
|
}
|
|
|
|
if deriverStr != nil {
|
|
ni.Deriver = path.Base(*deriverStr)
|
|
}
|
|
|
|
if sigsStr != nil {
|
|
sigsBits := strings.Fields(*sigsStr)
|
|
sigs := make(map[string][]byte)
|
|
for _, sigsBit := range sigsBits {
|
|
sigsPieces := strings.Split(sigsBit, ":")
|
|
if len(sigsPieces) != 2 {
|
|
return nil, fmt.Errorf("parsing signature %q: wrong number of : separated pieces (%d)", sigsBit, len(sigsPieces))
|
|
}
|
|
var err error
|
|
sigs[sigsPieces[0]], err = base64.StdEncoding.DecodeString(sigsPieces[1])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parsing signature %q: invalid base64: %w", sigsBit, err)
|
|
}
|
|
}
|
|
ni.Sig = sigs
|
|
}
|
|
|
|
referencesStmt, err := d.db.Prepare(`
|
|
SELECT
|
|
refedvp.path
|
|
FROM
|
|
Refs r
|
|
INNER JOIN
|
|
ValidPaths refedvp ON refedvp.id = r.reference
|
|
WHERE
|
|
r.referrer = ?
|
|
ORDER BY 1
|
|
`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("preparing references statement: %w", err)
|
|
}
|
|
defer referencesStmt.Close()
|
|
|
|
referencesRows, err := referencesStmt.Query(storePathID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("querying references: %w", err)
|
|
}
|
|
defer referencesRows.Close()
|
|
|
|
for referencesRows.Next() {
|
|
var refStorePath string
|
|
if err := referencesRows.Scan(&refStorePath); err != nil {
|
|
return nil, fmt.Errorf("scanning references: %w", err)
|
|
}
|
|
ni.References = append(ni.References, path.Base(refStorePath))
|
|
}
|
|
|
|
return &ni, nil
|
|
}
|
|
|
|
func (d *DB) Close() error {
|
|
return d.db.Close()
|
|
}
|
|
|
|
func Open(dbPath string) (*DB, error) {
|
|
sqlDB, err := sql.Open("sqlite3", dbPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &DB{
|
|
db: sqlDB,
|
|
}, nil
|
|
}
|