deb-simple/packages.go

259 lines
4.8 KiB
Go

package main
import (
"bufio"
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/blang/semver"
"github.com/spf13/afero"
"io"
"meow.tf/deb-simple/deb/archive"
"path"
"regexp"
"strings"
)
var (
variableRegexp = regexp.MustCompile("(.*?):\\s*(.*)")
)
type PackageFile struct {
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
MD5Hash string `json:"md5"`
SHA1Hash string `json:"sha1"`
SHA256Hash string `json:"sha256"`
ControlData string `json:"control"`
Info *Package `json:"info"`
}
type Package struct {
Package string `json:"package"`
Version string `json:"version"`
Architecture string `json:"architecture"`
}
func parsePackageData(ctlData string) *Package {
res := &Package{}
for _, match := range variableRegexp.FindAllStringSubmatch(ctlData, -1) {
switch match[1] {
case "Package":
res.Package = match[2]
case "Architecture":
res.Architecture = match[2]
case "Version":
res.Version = match[2]
}
}
return res
}
type Distro struct {
Name string `json:"name"`
Architectures map[string]map[string]*PackageFile `json:"architectures"`
}
var (
distros = make(map[string]*Distro)
)
func loadCache(dist string) error {
f, err := fs.Open(path.Join(conf.DistPath(dist), "dist.json"))
if err != nil {
return err
}
defer f.Close()
var distro Distro
if err := json.NewDecoder(f).Decode(&distro); err != nil {
return err
}
distros[dist] = &distro
return nil
}
func saveCache(dist *Distro) error {
f, err := fs.Create(path.Join(conf.DistPath(dist.Name), "dist.json"))
if err != nil {
return err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(dist); err != nil {
return err
}
return nil
}
func buildPackageList(config Conf, distro, arch string) (map[string]*PackageFile, error) {
m := make(map[string]*PackageFile)
if err := scanRecursive(config.PoolPath(distro, arch), m); err != nil {
return nil, err
}
return m, nil
}
func scanRecursive(base string, m map[string]*PackageFile) error {
dirList, err := afero.ReadDir(fs, base)
if err != nil {
return err
}
for _, file := range dirList {
if file.IsDir() {
if err := scanRecursive(path.Join(base, file.Name()), m); err != nil {
return err
}
continue
}
if !strings.HasSuffix(file.Name(), "deb") {
continue
}
p, err := newPackageFile(fs, path.Join(base, file.Name()))
if err != nil {
return err
}
if old, exists := m[p.Info.Package]; exists {
v1, err := semver.Parse(old.Info.Version)
v2, err2 := semver.Parse(p.Info.Version)
if err == nil && err2 == nil && v1.Compare(v2) > 0 {
// Use old version
continue
}
}
m[p.Info.Package] = p
}
return nil
}
func newPackageFile(sourceFs afero.Fs, filePath string) (*PackageFile, error) {
p := &PackageFile{
Name: path.Base(filePath),
Path: filePath,
}
var err error
stat, err := sourceFs.Stat(filePath)
if err != nil {
return nil, err
}
p.Size = stat.Size()
f, err := sourceFs.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
p.ControlData, err = archive.InspectPackage(f)
p.Info = parsePackageData(p.ControlData)
if err != nil {
return nil, err
}
if _, err = f.Seek(0, io.SeekStart); err != nil {
return nil, err
}
var (
md5hash = md5.New()
sha1hash = sha1.New()
sha256hash = sha256.New()
)
w := io.MultiWriter(md5hash, sha1hash, sha256hash)
if _, err := io.Copy(w, f); err != nil {
return nil, err
}
p.MD5Hash = hex.EncodeToString(md5hash.Sum(nil))
p.SHA1Hash = hex.EncodeToString(sha1hash.Sum(nil))
p.SHA256Hash = hex.EncodeToString(sha256hash.Sum(nil))
return p, nil
}
func createPackagesCached(config Conf, distro, arch string, packages map[string]*PackageFile) error {
stdFile, err := fs.Create(path.Join(config.ArchPath(distro, arch), "Packages"))
if err != nil {
return fmt.Errorf("failed to create packages: %s", err)
}
defer stdFile.Close()
stdOut := bufio.NewWriter(stdFile)
// loop through each directory
// run inspectPackage
for _, p := range packages {
var packBuf bytes.Buffer
packBuf.WriteString(p.ControlData)
dir := path.Join("pool/main", distro, arch, p.Info.Package[0:1], p.Info.Package, p.Name)
fmt.Fprintf(&packBuf, "Filename: %s\n", dir)
fmt.Fprintf(&packBuf, "Size: %d\n", p.Size)
fmt.Fprintf(&packBuf, "MD5sum: %s\n", p.MD5Hash)
fmt.Fprintf(&packBuf, "SHA1: %s\n", p.SHA1Hash)
fmt.Fprintf(&packBuf, "SHA256: %s\n", p.SHA256Hash)
packBuf.WriteString("\n\n")
stdOut.Write(packBuf.Bytes())
}
stdOut.Flush()
gzipFile, err := fs.Create(path.Join(config.ArchPath(distro, arch), "Packages.gz"))
if err != nil {
return fmt.Errorf("failed to create packages.gz: %s", err)
}
defer gzipFile.Close()
stdFile.Seek(0, io.SeekStart)
if _, err = io.Copy(gzipFile, stdFile); err != nil {
return err
}
return nil
}