Skip to content

Commit

Permalink
Merge pull request #664 from sliverc/acquire-by-hash
Browse files Browse the repository at this point in the history
Support Acquire-By-Hash for index files
  • Loading branch information
smira committed Nov 30, 2017
2 parents a037615 + b2bf4f7 commit 565fcf4
Show file tree
Hide file tree
Showing 17 changed files with 397 additions and 33 deletions.
5 changes: 5 additions & 0 deletions api/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ func apiPublishUpdateSwitch(c *gin.Context) {
Component string `binding:"required"`
Name string `binding:"required"`
}
AcquireByHash *bool
}

if c.Bind(&b) != nil {
Expand Down Expand Up @@ -317,6 +318,10 @@ func apiPublishUpdateSwitch(c *gin.Context) {
published.SkipContents = *b.SkipContents
}

if b.AcquireByHash != nil {
published.AcquireByHash = *b.AcquireByHash
}

err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
Expand Down
8 changes: 8 additions & 0 deletions aptly/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ type PublishedStorage interface {
Filelist(prefix string) ([]string, error)
// RenameFile renames (moves) file
RenameFile(oldName, newName string) error
// SymLink creates a symbolic link, which can be read with ReadLink
SymLink(src string, dst string) error
// HardLink creates a hardlink of a file
HardLink(src string, dst string) error
// FileExists returns true if path exists
FileExists(path string) (bool, error)
// ReadLink returns the symbolic link pointed to by path
ReadLink(path string) (string, error)
}

// FileSystemPublishedStorage is published storage on filesystem
Expand Down
2 changes: 1 addition & 1 deletion bash_completion.d/aptly
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ _aptly()
"snapshot"|"repo")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-batch -force-overwrite -distribution= -component= -gpg-key= -keyring= -label= -origin= -notautomatic= -butautomaticupgrades= -passphrase= -passphrase-file= -secret-keyring= -skip-contents -skip-signing" -- ${cur}))
COMPREPLY=($(compgen -W "-acquire-by-hash -batch -butautomaticupgrades= -component= -distribution= -force-overwrite -gpg-key= -keyring= -label= -notautomatic= -origin= -passphrase= -passphrase-file= -secret-keyring= -skip-contents -skip-signing" -- ${cur}))
else
if [[ "$subcmd" == "snapshot" ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
Expand Down
1 change: 1 addition & 0 deletions cmd/publish_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Example:
cmd.Flag.String("butautomaticupgrades", "", "set value for ButAutomaticUpgrades field")
cmd.Flag.String("label", "", "label to publish")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash")

return cmd
}
5 changes: 5 additions & 0 deletions cmd/publish_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool)
}

if context.Flags().IsSet("acquire-by-hash") {
published.AcquireByHash = context.Flags().Lookup("acquire-by-hash").Value.Get().(bool)
}

duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
if duplicate != nil {
context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
Expand Down Expand Up @@ -227,6 +231,7 @@ Example:
cmd.Flag.String("butautomaticupgrades", "", "overwrite value for ButAutomaticUpgrades field")
cmd.Flag.String("label", "", "label to publish")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash")

return cmd
}
128 changes: 101 additions & 27 deletions deb/index_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"os"
"path"
"path/filepath"
"strings"

Expand All @@ -20,18 +21,20 @@ type indexFiles struct {
tempDir string
suffix string
indexes map[string]*indexFile
acquireByHash bool
}

type indexFile struct {
parent *indexFiles
discardable bool
compressable bool
onlyGzip bool
signable bool
relativePath string
tempFilename string
tempFile *os.File
w *bufio.Writer
parent *indexFiles
discardable bool
compressable bool
onlyGzip bool
signable bool
acquireByHash bool
relativePath string
tempFilename string
tempFile *os.File
w *bufio.Writer
}

func (file *indexFile) BufWriter() (*bufio.Writer, error) {
Expand Down Expand Up @@ -91,11 +94,22 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
file.parent.generatedFiles[file.relativePath+ext] = checksumInfo
}

err = file.parent.publishedStorage.MkDir(filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath)))
filedir := filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath))

err = file.parent.publishedStorage.MkDir(filedir)
if err != nil {
return fmt.Errorf("unable to create dir: %s", err)
}

if file.acquireByHash {
for _, hash := range []string{"MD5Sum", "SHA1", "SHA256", "SHA512"} {
err = file.parent.publishedStorage.MkDir(filepath.Join(filedir, "by-hash", hash))
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)
Expand All @@ -107,6 +121,16 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext)] =
filepath.Join(file.parent.basePath, file.relativePath+ext)
}

if file.acquireByHash {
sums := file.parent.generatedFiles[file.relativePath+ext]
for hash, sum := range map[string]string{"SHA512": sums.SHA512, "SHA256": sums.SHA256, "SHA1": sums.SHA1, "MD5Sum": sums.MD5} {
err = packageIndexByHash(file, ext, hash, sum)
if err != nil {
return fmt.Errorf("unable to build hash file: %s", err)
}
}
}
}

if file.signable && signer != nil {
Expand Down Expand Up @@ -143,7 +167,53 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
return nil
}

func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, suffix string) *indexFiles {
func packageIndexByHash(file *indexFile, ext string, hash string, sum string) error {
src := filepath.Join(file.parent.basePath, file.relativePath)
indexfile := path.Base(src + ext)
src = src + file.parent.suffix + ext
filedir := filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath))
dst := filepath.Join(filedir, "by-hash", hash)
sumfilePath := filepath.Join(dst, sum)

// link already exists? do nothing
exists, err := file.parent.publishedStorage.FileExists(sumfilePath)
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error checking exists of file %s: %s", sumfilePath, err)
}
if exists {
return nil
}

// create the link
err = file.parent.publishedStorage.HardLink(src, sumfilePath)
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error creating hardlink %s: %s", sumfilePath, err)
}

// if a previous index file already exists exists, backup symlink
if exists, _ = file.parent.publishedStorage.FileExists(filepath.Join(dst, indexfile)); exists {
// if exists, remove old symlink
if exists, _ = file.parent.publishedStorage.FileExists(filepath.Join(dst, indexfile+".old")); exists {
var link string
link, err = file.parent.publishedStorage.ReadLink(filepath.Join(dst, indexfile+".old"))
if err != nil {
file.parent.publishedStorage.Remove(link)
}
file.parent.publishedStorage.Remove(filepath.Join(dst, indexfile+".old"))
}
file.parent.publishedStorage.RenameFile(filepath.Join(dst, indexfile),
filepath.Join(dst, indexfile+".old"))
}

// create symlink
err = file.parent.publishedStorage.SymLink(filepath.Join(dst, sum), filepath.Join(dst, indexfile))
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error creating symlink %s: %s", filepath.Join(dst, indexfile), err)
}
return nil
}

func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, suffix string, acquireByHash bool) *indexFiles {
return &indexFiles{
publishedStorage: publishedStorage,
basePath: basePath,
Expand All @@ -152,6 +222,7 @@ func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, s
tempDir: tempDir,
suffix: suffix,
indexes: make(map[string]*indexFile),
acquireByHash: acquireByHash,
}
}

Expand All @@ -175,11 +246,12 @@ func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexF
}

file = &indexFile{
parent: files,
discardable: false,
compressable: true,
signable: false,
relativePath: relativePath,
parent: files,
discardable: false,
compressable: true,
signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath,
}

files.indexes[key] = file
Expand Down Expand Up @@ -208,11 +280,12 @@ func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexF
}

file = &indexFile{
parent: files,
discardable: udeb,
compressable: false,
signable: false,
relativePath: relativePath,
parent: files,
discardable: udeb,
compressable: false,
signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath,
}

files.indexes[key] = file
Expand All @@ -237,12 +310,13 @@ func (files *indexFiles) ContentsIndex(component, arch string, udeb bool) *index
}

file = &indexFile{
parent: files,
discardable: true,
compressable: true,
onlyGzip: true,
signable: false,
relativePath: relativePath,
parent: files,
discardable: true,
compressable: true,
onlyGzip: true,
signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath,
}

files.indexes[key] = file
Expand Down
11 changes: 10 additions & 1 deletion deb/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type PublishedRepo struct {

// True if repo is being re-published
rePublishing bool

// Provide index files per hash also
AcquireByHash bool
}

// ParsePrefix splits [storage:]prefix into components
Expand Down Expand Up @@ -556,7 +559,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
}
defer os.RemoveAll(tempDir)

indexes := newIndexFiles(publishedStorage, basePath, tempDir, suffix)
indexes := newIndexFiles(publishedStorage, basePath, tempDir, suffix, p.AcquireByHash)

for component, list := range lists {
hadUdebs := false
Expand Down Expand Up @@ -683,6 +686,9 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
release["Component"] = component
release["Origin"] = p.GetOrigin()
release["Label"] = p.GetLabel()
if p.AcquireByHash {
release["Acquire-By-Hash"] = "yes"
}

var bufWriter *bufio.Writer
bufWriter, err = indexes.ReleaseIndex(component, arch, udeb).BufWriter()
Expand Down Expand Up @@ -720,6 +726,9 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
release["Codename"] = p.Distribution
release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST")
release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{ArchitectureSource}), " ")
if p.AcquireByHash {
release["Acquire-By-Hash"] = "yes"
}
release["Description"] = " Generated by aptly\n"
release["MD5Sum"] = ""
release["SHA1"] = ""
Expand Down
24 changes: 24 additions & 0 deletions files/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,27 @@ func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) {
func (storage *PublishedStorage) RenameFile(oldName, newName string) error {
return os.Rename(filepath.Join(storage.rootPath, oldName), filepath.Join(storage.rootPath, newName))
}

// SymLink creates a symbolic link, which can be read with ReadLink
func (storage *PublishedStorage) SymLink(src string, dst string) error {
return os.Symlink(filepath.Join(storage.rootPath, src), filepath.Join(storage.rootPath, dst))
}

// HardLink creates a hardlink of a file
func (storage *PublishedStorage) HardLink(src string, dst string) error {
return os.Link(filepath.Join(storage.rootPath, src), filepath.Join(storage.rootPath, dst))
}

// FileExists returns true if path exists
func (storage *PublishedStorage) FileExists(path string) (bool, error) {
if _, err := os.Lstat(filepath.Join(storage.rootPath, path)); os.IsNotExist(err) {
return false, nil
}

return true, nil
}

// ReadLink returns the symbolic link pointed to by path
func (storage *PublishedStorage) ReadLink(path string) (string, error) {
return os.Readlink(path)
}
42 changes: 42 additions & 0 deletions files/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,48 @@ func (s *PublishedStorageSuite) TestRenameFile(c *C) {
c.Assert(err, IsNil)
}

func (s *PublishedStorageSuite) TestFileExists(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)

exists, _ := s.storage.FileExists("ppa/dists/squeeze/Release")
c.Check(exists, Equals, false)

err = s.storage.PutFile("ppa/dists/squeeze/Release", "/dev/null")
c.Assert(err, IsNil)

exists, _ = s.storage.FileExists("ppa/dists/squeeze/Release")
c.Check(exists, Equals, true)
}

func (s *PublishedStorageSuite) TestSymLink(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)

err = s.storage.PutFile("ppa/dists/squeeze/Release", "/dev/null")
c.Assert(err, IsNil)

err = s.storage.SymLink("ppa/dists/squeeze/Release", "ppa/dists/squeeze/InRelease")
c.Assert(err, IsNil)

exists, _ := s.storage.FileExists("ppa/dists/squeeze/InRelease")
c.Check(exists, Equals, true)
}

func (s *PublishedStorageSuite) TestHardLink(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)

err = s.storage.PutFile("ppa/dists/squeeze/Release", "/dev/null")
c.Assert(err, IsNil)

err = s.storage.HardLink("ppa/dists/squeeze/Release", "ppa/dists/squeeze/InRelease")
c.Assert(err, IsNil)

exists, _ := s.storage.FileExists("ppa/dists/squeeze/InRelease")
c.Check(exists, Equals, true)
}

func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)
Expand Down
Loading

0 comments on commit 565fcf4

Please sign in to comment.