mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-04-20 19:38:39 +00:00
296 lines
7.3 KiB
Go
296 lines
7.3 KiB
Go
package deb
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/smira/aptly/aptly"
|
|
"github.com/smira/aptly/utils"
|
|
)
|
|
|
|
type indexFiles struct {
|
|
publishedStorage aptly.PublishedStorage
|
|
basePath string
|
|
renameMap map[string]string
|
|
generatedFiles map[string]utils.ChecksumInfo
|
|
tempDir string
|
|
suffix string
|
|
indexes map[string]*indexFile
|
|
}
|
|
|
|
type indexFile struct {
|
|
parent *indexFiles
|
|
discardable bool
|
|
compressable bool
|
|
onlyGzip bool
|
|
signable bool
|
|
relativePath string
|
|
tempFilename string
|
|
tempFile *os.File
|
|
w *bufio.Writer
|
|
}
|
|
|
|
func (file *indexFile) BufWriter() (*bufio.Writer, error) {
|
|
if file.w == nil {
|
|
var err error
|
|
file.tempFilename = filepath.Join(file.parent.tempDir, strings.Replace(file.relativePath, "/", "_", -1))
|
|
file.tempFile, err = os.Create(file.tempFilename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to create temporary index file: %s", err)
|
|
}
|
|
|
|
file.w = bufio.NewWriter(file.tempFile)
|
|
}
|
|
|
|
return file.w, nil
|
|
}
|
|
|
|
func (file *indexFile) Finalize(signer utils.Signer) error {
|
|
if file.w == nil {
|
|
if file.discardable {
|
|
return nil
|
|
}
|
|
file.BufWriter()
|
|
}
|
|
|
|
err := file.w.Flush()
|
|
if err != nil {
|
|
file.tempFile.Close()
|
|
return fmt.Errorf("unable to write to index file: %s", err)
|
|
}
|
|
|
|
if file.compressable {
|
|
err = utils.CompressFile(file.tempFile, file.onlyGzip)
|
|
if err != nil {
|
|
file.tempFile.Close()
|
|
return fmt.Errorf("unable to compress index file: %s", err)
|
|
}
|
|
}
|
|
|
|
file.tempFile.Close()
|
|
|
|
exts := []string{""}
|
|
if file.compressable {
|
|
exts = append(exts, ".gz", ".bz2")
|
|
if file.onlyGzip {
|
|
exts = []string{".gz"}
|
|
}
|
|
}
|
|
|
|
for _, ext := range exts {
|
|
var checksumInfo utils.ChecksumInfo
|
|
|
|
checksumInfo, err = utils.ChecksumsForFile(file.tempFilename + ext)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to collect checksums: %s", err)
|
|
}
|
|
file.parent.generatedFiles[file.relativePath+ext] = checksumInfo
|
|
}
|
|
|
|
err = file.parent.publishedStorage.MkDir(filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath)))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to create dir: %s", err)
|
|
}
|
|
|
|
for _, ext := range exts {
|
|
err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext),
|
|
file.tempFilename+ext)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to publish file: %s", err)
|
|
}
|
|
|
|
if file.parent.suffix != "" {
|
|
file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext)] =
|
|
filepath.Join(file.parent.basePath, file.relativePath+ext)
|
|
}
|
|
}
|
|
|
|
if file.signable && signer != nil {
|
|
err = signer.DetachedSign(file.tempFilename, file.tempFilename+".gpg")
|
|
if err != nil {
|
|
return fmt.Errorf("unable to detached sign file: %s", err)
|
|
}
|
|
|
|
err = signer.ClearSign(file.tempFilename, filepath.Join(filepath.Dir(file.tempFilename), "In"+filepath.Base(file.tempFilename)))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to clearsign file: %s", err)
|
|
}
|
|
|
|
if file.parent.suffix != "" {
|
|
file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+".gpg")] =
|
|
filepath.Join(file.parent.basePath, file.relativePath+".gpg")
|
|
file.parent.renameMap[filepath.Join(file.parent.basePath, "In"+file.relativePath+file.parent.suffix)] =
|
|
filepath.Join(file.parent.basePath, "In"+file.relativePath)
|
|
}
|
|
|
|
err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+".gpg"),
|
|
file.tempFilename+".gpg")
|
|
if err != nil {
|
|
return fmt.Errorf("unable to publish file: %s", err)
|
|
}
|
|
|
|
err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, "In"+file.relativePath+file.parent.suffix),
|
|
filepath.Join(filepath.Dir(file.tempFilename), "In"+filepath.Base(file.tempFilename)))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to publish file: %s", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, suffix string) *indexFiles {
|
|
return &indexFiles{
|
|
publishedStorage: publishedStorage,
|
|
basePath: basePath,
|
|
renameMap: make(map[string]string),
|
|
generatedFiles: make(map[string]utils.ChecksumInfo),
|
|
tempDir: tempDir,
|
|
suffix: suffix,
|
|
indexes: make(map[string]*indexFile),
|
|
}
|
|
}
|
|
|
|
func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexFile {
|
|
if arch == ArchitectureSource {
|
|
udeb = false
|
|
}
|
|
key := fmt.Sprintf("pi-%s-%s-%v", component, arch, udeb)
|
|
file, ok := files.indexes[key]
|
|
if !ok {
|
|
var relativePath string
|
|
|
|
if arch == ArchitectureSource {
|
|
relativePath = filepath.Join(component, "source", "Sources")
|
|
} else {
|
|
if udeb {
|
|
relativePath = filepath.Join(component, "debian-installer", fmt.Sprintf("binary-%s", arch), "Packages")
|
|
} else {
|
|
relativePath = filepath.Join(component, fmt.Sprintf("binary-%s", arch), "Packages")
|
|
}
|
|
}
|
|
|
|
file = &indexFile{
|
|
parent: files,
|
|
discardable: false,
|
|
compressable: true,
|
|
signable: false,
|
|
relativePath: relativePath,
|
|
}
|
|
|
|
files.indexes[key] = file
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexFile {
|
|
if arch == ArchitectureSource {
|
|
udeb = false
|
|
}
|
|
key := fmt.Sprintf("ri-%s-%s-%v", component, arch, udeb)
|
|
file, ok := files.indexes[key]
|
|
if !ok {
|
|
var relativePath string
|
|
|
|
if arch == ArchitectureSource {
|
|
relativePath = filepath.Join(component, "source", "Release")
|
|
} else {
|
|
if udeb {
|
|
relativePath = filepath.Join(component, "debian-installer", fmt.Sprintf("binary-%s", arch), "Release")
|
|
} else {
|
|
relativePath = filepath.Join(component, fmt.Sprintf("binary-%s", arch), "Release")
|
|
}
|
|
}
|
|
|
|
file = &indexFile{
|
|
parent: files,
|
|
discardable: udeb,
|
|
compressable: false,
|
|
signable: false,
|
|
relativePath: relativePath,
|
|
}
|
|
|
|
files.indexes[key] = file
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
func (files *indexFiles) ContentsIndex(component, arch string, udeb bool) *indexFile {
|
|
if arch == ArchitectureSource {
|
|
udeb = false
|
|
}
|
|
key := fmt.Sprintf("ci-%s-%s-%v", component, arch, udeb)
|
|
file, ok := files.indexes[key]
|
|
if !ok {
|
|
var relativePath string
|
|
|
|
if udeb {
|
|
relativePath = filepath.Join(component, fmt.Sprintf("Contents-udeb-%s", arch))
|
|
} else {
|
|
relativePath = filepath.Join(component, fmt.Sprintf("Contents-%s", arch))
|
|
}
|
|
|
|
file = &indexFile{
|
|
parent: files,
|
|
discardable: true,
|
|
compressable: true,
|
|
onlyGzip: true,
|
|
signable: false,
|
|
relativePath: relativePath,
|
|
}
|
|
|
|
files.indexes[key] = file
|
|
}
|
|
|
|
return file
|
|
}
|
|
|
|
func (files *indexFiles) ReleaseFile() *indexFile {
|
|
return &indexFile{
|
|
parent: files,
|
|
discardable: false,
|
|
compressable: false,
|
|
signable: true,
|
|
relativePath: "Release",
|
|
}
|
|
}
|
|
|
|
func (files *indexFiles) FinalizeAll(progress aptly.Progress) (err error) {
|
|
if progress != nil {
|
|
progress.InitBar(int64(len(files.indexes)), false)
|
|
defer progress.ShutdownBar()
|
|
}
|
|
|
|
for _, file := range files.indexes {
|
|
err = file.Finalize(nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if progress != nil {
|
|
progress.AddBar(1)
|
|
}
|
|
}
|
|
|
|
files.indexes = make(map[string]*indexFile)
|
|
|
|
return
|
|
}
|
|
|
|
func (files *indexFiles) RenameFiles() error {
|
|
var err error
|
|
|
|
for oldName, newName := range files.renameMap {
|
|
err = files.publishedStorage.RenameFile(oldName, newName)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to rename: %s", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|