2015-04-23 16:20:36 +00:00
|
|
|
package lfs
|
2013-10-04 15:22:32 +00:00
|
|
|
|
|
|
|
import (
|
2015-03-22 16:01:26 +00:00
|
|
|
"fmt"
|
2013-10-04 15:22:32 +00:00
|
|
|
"io"
|
2013-11-05 15:26:58 +00:00
|
|
|
"os"
|
2015-03-20 17:30:24 +00:00
|
|
|
"path/filepath"
|
2015-05-13 19:43:41 +00:00
|
|
|
|
2015-05-25 18:20:50 +00:00
|
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/cheggaaa/pb"
|
|
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
|
|
|
contentaddressable "github.com/github/git-lfs/vendor/_nuts/github.com/technoweenie/go-contentaddressable"
|
2013-10-04 15:22:32 +00:00
|
|
|
)
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
func PointerSmudge(writer io.Writer, ptr *Pointer, workingfile string, cb CopyCallback) error {
|
|
|
|
mediafile, err := LocalMediaPath(ptr.Oid)
|
2014-06-05 19:05:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-10-04 15:22:32 +00:00
|
|
|
|
2015-04-28 15:49:46 +00:00
|
|
|
stat, statErr := os.Stat(mediafile)
|
|
|
|
if statErr == nil && stat != nil {
|
|
|
|
fileSize := stat.Size()
|
|
|
|
if fileSize == 0 || fileSize != ptr.Size {
|
|
|
|
tracerx.Printf("Removing %s, size %d is invalid", mediafile, fileSize)
|
|
|
|
os.RemoveAll(mediafile)
|
|
|
|
stat = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
var wErr *WrappedError
|
2015-04-28 15:49:46 +00:00
|
|
|
if statErr != nil || stat == nil {
|
2015-03-22 16:01:26 +00:00
|
|
|
wErr = downloadFile(writer, ptr, workingfile, mediafile, cb)
|
2013-11-06 16:41:57 +00:00
|
|
|
} else {
|
2015-05-14 16:33:29 +00:00
|
|
|
sendApiEvent(apiEventSuccess)
|
2014-08-08 16:51:47 +00:00
|
|
|
wErr = readLocalFile(writer, ptr, mediafile, cb)
|
2013-11-05 15:26:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 16:51:47 +00:00
|
|
|
if wErr != nil {
|
|
|
|
return &SmudgeError{ptr.Oid, mediafile, wErr}
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
2015-05-12 08:45:06 +00:00
|
|
|
|
|
|
|
return nil
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 14:29:17 +00:00
|
|
|
// PointerSmudgeObject uses a Pointer and objectResource to download the object to the
|
|
|
|
// media directory. It does not write the file to the working directory.
|
|
|
|
func PointerSmudgeObject(ptr *Pointer, obj *objectResource, cb CopyCallback) error {
|
2015-05-14 18:56:30 +00:00
|
|
|
mediafile, err := LocalMediaPath(obj.Oid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
stat, statErr := os.Stat(mediafile)
|
|
|
|
if statErr == nil && stat != nil {
|
|
|
|
fileSize := stat.Size()
|
|
|
|
if fileSize == 0 || fileSize != obj.Size {
|
|
|
|
tracerx.Printf("Removing %s, size %d is invalid", mediafile, fileSize)
|
|
|
|
os.RemoveAll(mediafile)
|
|
|
|
stat = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if statErr != nil || stat == nil {
|
2015-05-21 14:29:17 +00:00
|
|
|
wErr := downloadObject(ptr, obj, mediafile, cb)
|
2015-05-14 18:56:30 +00:00
|
|
|
|
2015-05-21 14:29:17 +00:00
|
|
|
if wErr != nil {
|
|
|
|
sendApiEvent(apiEventFail)
|
|
|
|
return &SmudgeError{obj.Oid, mediafile, wErr}
|
|
|
|
}
|
2015-05-14 18:56:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sendApiEvent(apiEventSuccess)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-05-21 14:29:17 +00:00
|
|
|
func downloadObject(ptr *Pointer, obj *objectResource, mediafile string, cb CopyCallback) *WrappedError {
|
2015-05-14 18:56:30 +00:00
|
|
|
reader, size, wErr := DownloadObject(obj)
|
|
|
|
if reader != nil {
|
|
|
|
defer reader.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO this can be unified with the same code in downloadFile
|
|
|
|
if wErr != nil {
|
|
|
|
wErr.Errorf("Error downloading %s.", mediafile)
|
|
|
|
return wErr
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
2015-05-14 18:56:30 +00:00
|
|
|
|
|
|
|
if ptr.Size == 0 {
|
|
|
|
ptr.Size = size
|
|
|
|
}
|
|
|
|
|
|
|
|
mediaFile, err := contentaddressable.NewFile(mediafile)
|
|
|
|
if err != nil {
|
|
|
|
return Errorf(err, "Error opening media file buffer.")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = CopyWithCallback(mediaFile, reader, ptr.Size, cb)
|
|
|
|
if err == nil {
|
|
|
|
err = mediaFile.Accept()
|
|
|
|
}
|
|
|
|
mediaFile.Close()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return Errorf(err, "Error buffering media file.")
|
|
|
|
}
|
|
|
|
|
2015-05-21 14:29:17 +00:00
|
|
|
return nil
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
func downloadFile(writer io.Writer, ptr *Pointer, workingfile, mediafile string, cb CopyCallback) *WrappedError {
|
2015-03-22 18:10:12 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "Downloading %s (%s)\n", workingfile, pb.FormatBytes(ptr.Size))
|
2015-04-23 16:20:36 +00:00
|
|
|
reader, size, wErr := Download(filepath.Base(mediafile))
|
2014-08-08 17:31:33 +00:00
|
|
|
if reader != nil {
|
|
|
|
defer reader.Close()
|
|
|
|
}
|
|
|
|
|
2014-08-07 22:04:04 +00:00
|
|
|
if wErr != nil {
|
2014-08-08 16:51:47 +00:00
|
|
|
wErr.Errorf("Error downloading %s.", mediafile)
|
2014-08-07 22:04:04 +00:00
|
|
|
return wErr
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 16:25:26 +00:00
|
|
|
if ptr.Size == 0 {
|
|
|
|
ptr.Size = size
|
|
|
|
}
|
|
|
|
|
2014-08-18 16:43:16 +00:00
|
|
|
mediaFile, err := contentaddressable.NewFile(mediafile)
|
2014-07-28 19:35:25 +00:00
|
|
|
if err != nil {
|
2015-04-23 16:20:36 +00:00
|
|
|
return Errorf(err, "Error opening media file buffer.")
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
_, err = CopyWithCallback(mediaFile, reader, ptr.Size, cb)
|
2014-08-19 17:24:42 +00:00
|
|
|
if err == nil {
|
2014-08-18 16:43:16 +00:00
|
|
|
err = mediaFile.Accept()
|
|
|
|
}
|
2014-08-21 20:36:39 +00:00
|
|
|
mediaFile.Close()
|
2014-07-28 20:31:30 +00:00
|
|
|
|
2014-08-18 16:43:16 +00:00
|
|
|
if err != nil {
|
2015-04-23 16:20:36 +00:00
|
|
|
return Errorf(err, "Error buffering media file.")
|
2014-07-28 20:31:30 +00:00
|
|
|
}
|
|
|
|
|
2014-08-18 16:43:16 +00:00
|
|
|
return readLocalFile(writer, ptr, mediafile, nil)
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
func readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, cb CopyCallback) *WrappedError {
|
2014-07-28 19:35:25 +00:00
|
|
|
reader, err := os.Open(mediafile)
|
|
|
|
if err != nil {
|
2015-04-23 16:20:36 +00:00
|
|
|
return Errorf(err, "Error opening media file.")
|
2014-07-28 19:35:25 +00:00
|
|
|
}
|
|
|
|
defer reader.Close()
|
|
|
|
|
2014-08-07 16:25:26 +00:00
|
|
|
if ptr.Size == 0 {
|
|
|
|
if stat, _ := os.Stat(mediafile); stat != nil {
|
|
|
|
ptr.Size = stat.Size()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:20:36 +00:00
|
|
|
_, err = CopyWithCallback(writer, reader, ptr.Size, cb)
|
|
|
|
return Errorf(err, "Error reading from media file.")
|
2013-10-04 15:22:32 +00:00
|
|
|
}
|
2013-10-22 18:09:06 +00:00
|
|
|
|
|
|
|
type SmudgeError struct {
|
2014-08-08 16:51:47 +00:00
|
|
|
Oid string
|
|
|
|
Filename string
|
2015-04-23 16:20:36 +00:00
|
|
|
*WrappedError
|
2013-10-22 18:09:06 +00:00
|
|
|
}
|