mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-15 11:57:59 +00:00
Imported Upstream version 1.0.1
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/smira/aptly/aptly"
|
||||
)
|
||||
|
||||
// PackagePool is deduplicated storage of package files on filesystem
|
||||
type PackagePool struct {
|
||||
sync.Mutex
|
||||
rootPath string
|
||||
}
|
||||
|
||||
// Check interface
|
||||
var (
|
||||
_ aptly.PackagePool = (*PackagePool)(nil)
|
||||
)
|
||||
|
||||
// NewPackagePool creates new instance of PackagePool which specified root
|
||||
func NewPackagePool(root string) *PackagePool {
|
||||
return &PackagePool{rootPath: filepath.Join(root, "pool")}
|
||||
}
|
||||
|
||||
// RelativePath returns path relative to pool's root for package files given MD5 and original filename
|
||||
func (pool *PackagePool) RelativePath(filename string, hashMD5 string) (string, error) {
|
||||
filename = filepath.Base(filename)
|
||||
if filename == "." || filename == "/" {
|
||||
return "", fmt.Errorf("filename %s is invalid", filename)
|
||||
}
|
||||
|
||||
if len(hashMD5) < 4 {
|
||||
return "", fmt.Errorf("unable to compute pool location for filename %v, MD5 is missing", filename)
|
||||
}
|
||||
|
||||
return filepath.Join(hashMD5[0:2], hashMD5[2:4], filename), nil
|
||||
}
|
||||
|
||||
// Path returns full path to package file in pool given any name and hash of file contents
|
||||
func (pool *PackagePool) Path(filename string, hashMD5 string) (string, error) {
|
||||
relative, err := pool.RelativePath(filename, hashMD5)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Join(pool.rootPath, relative), nil
|
||||
}
|
||||
|
||||
// FilepathList returns file paths of all the files in the pool
|
||||
func (pool *PackagePool) FilepathList(progress aptly.Progress) ([]string, error) {
|
||||
pool.Lock()
|
||||
defer pool.Unlock()
|
||||
|
||||
dirs, err := ioutil.ReadDir(pool.rootPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(dirs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if progress != nil {
|
||||
progress.InitBar(int64(len(dirs)), false)
|
||||
defer progress.ShutdownBar()
|
||||
}
|
||||
|
||||
result := []string{}
|
||||
|
||||
for _, dir := range dirs {
|
||||
err = filepath.Walk(filepath.Join(pool.rootPath, dir.Name()), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
result = append(result, path[len(pool.rootPath)+1:])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if progress != nil {
|
||||
progress.AddBar(1)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Remove deletes file in package pool returns its size
|
||||
func (pool *PackagePool) Remove(path string) (size int64, err error) {
|
||||
pool.Lock()
|
||||
defer pool.Unlock()
|
||||
|
||||
path = filepath.Join(pool.rootPath, path)
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = os.Remove(path)
|
||||
return info.Size(), err
|
||||
}
|
||||
|
||||
// Import copies file into package pool
|
||||
func (pool *PackagePool) Import(path string, hashMD5 string) error {
|
||||
pool.Lock()
|
||||
defer pool.Unlock()
|
||||
|
||||
source, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
sourceInfo, err := source.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolPath, err := pool.Path(path, hashMD5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetInfo, err := os.Stat(poolPath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
// unable to stat target location?
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// target already exists
|
||||
if targetInfo.Size() != sourceInfo.Size() {
|
||||
// trying to overwrite file?
|
||||
return fmt.Errorf("unable to import into pool: file %s already exists", poolPath)
|
||||
}
|
||||
|
||||
// assume that target is already there
|
||||
return nil
|
||||
}
|
||||
|
||||
// create subdirs as necessary
|
||||
err = os.MkdirAll(filepath.Dir(poolPath), 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
target, err := os.Create(poolPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer target.Close()
|
||||
|
||||
_, err = io.Copy(target, source)
|
||||
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user