merge latest master
This commit is contained in:
commit
4e4dac25c5
1
Nut.toml
1
Nut.toml
@ -19,4 +19,3 @@ authors = [
|
|||||||
"github.com/spf13/cobra" = "c55cdf33856a08e4822738728b41783292812889"
|
"github.com/spf13/cobra" = "c55cdf33856a08e4822738728b41783292812889"
|
||||||
"github.com/spf13/pflag" = "580b9be06c33d8ba9dcc8757ea56b7642472c2f5"
|
"github.com/spf13/pflag" = "580b9be06c33d8ba9dcc8757ea56b7642472c2f5"
|
||||||
"github.com/technoweenie/assert" = "b25ea301d127043ffacf3b2545726e79b6632139"
|
"github.com/technoweenie/assert" = "b25ea301d127043ffacf3b2545726e79b6632139"
|
||||||
"github.com/technoweenie/go-contentaddressable" = "38171def3cd15e3b76eb156219b3d48704643899"
|
|
||||||
|
26
git-lfs.go
26
git-lfs.go
@ -1,11 +1,37 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/github/git-lfs/commands"
|
"github.com/github/git-lfs/commands"
|
||||||
"github.com/github/git-lfs/lfs"
|
"github.com/github/git-lfs/lfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
c := make(chan os.Signal)
|
||||||
|
signal.Notify(c, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
|
var once sync.Once
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
sig := <-c
|
||||||
|
once.Do(lfs.ClearTempObjects)
|
||||||
|
fmt.Fprintf(os.Stderr, "\nExiting because of %q signal.\n", sig)
|
||||||
|
|
||||||
|
exitCode := 1
|
||||||
|
if sysSig, ok := sig.(syscall.Signal); ok {
|
||||||
|
exitCode = int(sysSig)
|
||||||
|
}
|
||||||
|
os.Exit(exitCode + 128)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
commands.Run()
|
commands.Run()
|
||||||
lfs.LogHttpStats()
|
lfs.LogHttpStats()
|
||||||
|
once.Do(lfs.ClearTempObjects)
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ func doApiBatchRequest(req *http.Request) (*http.Response, []*objectResource, er
|
|||||||
res, err := doAPIRequest(req, Config.PrivateAccess())
|
res, err := doAPIRequest(req, Config.PrivateAccess())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if res.StatusCode == 401 {
|
if res != nil && res.StatusCode == 401 {
|
||||||
return res, nil, newAuthError(err)
|
return res, nil, newAuthError(err)
|
||||||
}
|
}
|
||||||
return res, nil, err
|
return res, nil, err
|
||||||
|
@ -337,7 +337,7 @@ func (c *Configuration) loadGitConfig() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool, whitelisted bool) {
|
func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool, onlySafe bool) {
|
||||||
lines := strings.Split(output, "\n")
|
lines := strings.Split(output, "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
pieces := strings.SplitN(line, "=", 2)
|
pieces := strings.SplitN(line, "=", 2)
|
||||||
@ -345,7 +345,7 @@ func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed := !whitelisted
|
allowed := !onlySafe
|
||||||
key := strings.ToLower(pieces[0])
|
key := strings.ToLower(pieces[0])
|
||||||
value := pieces[1]
|
value := pieces[1]
|
||||||
|
|
||||||
@ -355,12 +355,12 @@ func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool
|
|||||||
ext := c.extensions[name]
|
ext := c.extensions[name]
|
||||||
switch keyParts[3] {
|
switch keyParts[3] {
|
||||||
case "clean":
|
case "clean":
|
||||||
if whitelisted {
|
if onlySafe {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ext.Clean = value
|
ext.Clean = value
|
||||||
case "smudge":
|
case "smudge":
|
||||||
if whitelisted {
|
if onlySafe {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ext.Smudge = value
|
ext.Smudge = value
|
||||||
@ -375,7 +375,7 @@ func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool
|
|||||||
ext.Name = name
|
ext.Name = name
|
||||||
c.extensions[name] = ext
|
c.extensions[name] = ext
|
||||||
} else if len(keyParts) > 1 && keyParts[0] == "remote" {
|
} else if len(keyParts) > 1 && keyParts[0] == "remote" {
|
||||||
if whitelisted && (len(keyParts) < 3 || keyParts[2] != "lfsurl") {
|
if onlySafe && (len(keyParts) == 3 && keyParts[2] != "lfsurl") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +384,7 @@ func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool
|
|||||||
uniqRemotes[remote] = remote == "origin"
|
uniqRemotes[remote] = remote == "origin"
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowed && key != "lfs.url" {
|
if !allowed && keyIsUnsafe(key) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,3 +403,18 @@ func (c *Configuration) readGitConfig(output string, uniqRemotes map[string]bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keyIsUnsafe(key string) bool {
|
||||||
|
for _, safe := range safeKeys {
|
||||||
|
if safe == key {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var safeKeys = []string{
|
||||||
|
"lfs.url",
|
||||||
|
"lfs.fetchinclude",
|
||||||
|
"lfs.fetchexclude",
|
||||||
|
}
|
||||||
|
@ -84,7 +84,9 @@ func TestSuccessfulDownload(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
@ -213,6 +215,7 @@ func TestSuccessfulDownloadWithRedirects(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
Config.SetConfig("lfs.url", server.URL+"/redirect")
|
||||||
|
|
||||||
for _, redirect := range redirectCodes {
|
for _, redirect := range redirectCodes {
|
||||||
@ -319,6 +322,7 @@ func TestSuccessfulDownloadWithAuthorization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -419,6 +423,7 @@ func TestSuccessfulDownloadFromSeparateHost(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
reader, size, err := Download("oid")
|
reader, size, err := Download("oid")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -550,6 +555,7 @@ func TestSuccessfulDownloadFromSeparateRedirectedHost(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
|
|
||||||
for _, redirect := range redirectCodes {
|
for _, redirect := range redirectCodes {
|
||||||
@ -587,6 +593,7 @@ func TestDownloadAPIError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
_, _, err := Download("oid")
|
_, _, err := Download("oid")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -655,6 +662,7 @@ func TestDownloadStorageError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defer Config.ResetConfig()
|
defer Config.ResetConfig()
|
||||||
|
Config.SetConfig("lfs.batch", "false")
|
||||||
Config.SetConfig("lfs.url", server.URL+"/media")
|
Config.SetConfig("lfs.url", server.URL+"/media")
|
||||||
_, _, err := Download("oid")
|
_, _, err := Download("oid")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -28,6 +28,7 @@ var (
|
|||||||
LocalGitDir string // parent of index / config / hooks etc
|
LocalGitDir string // parent of index / config / hooks etc
|
||||||
LocalGitStorageDir string // parent of objects/lfs (may be same as LocalGitDir but may not)
|
LocalGitStorageDir string // parent of objects/lfs (may be same as LocalGitDir but may not)
|
||||||
LocalMediaDir string // root of lfs objects
|
LocalMediaDir string // root of lfs objects
|
||||||
|
LocalObjectTempDir string // where temporarily downloading objects are stored
|
||||||
LocalLogDir string
|
LocalLogDir string
|
||||||
checkedTempDir string
|
checkedTempDir string
|
||||||
)
|
)
|
||||||
@ -112,7 +113,8 @@ func ResolveDirs() {
|
|||||||
panic(fmt.Errorf("Error trying to create log directory in '%s': %s", LocalLogDir, err))
|
panic(fmt.Errorf("Error trying to create log directory in '%s': %s", LocalLogDir, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(TempDir, tempDirPerms); err != nil {
|
LocalObjectTempDir = filepath.Join(TempDir, "objects")
|
||||||
|
if err := os.MkdirAll(LocalObjectTempDir, tempDirPerms); err != nil {
|
||||||
panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
|
panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
62
lfs/localstorage.go
Normal file
62
lfs/localstorage.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package lfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ClearTempObjects() {
|
||||||
|
if len(LocalObjectTempDir) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := os.Open(LocalObjectTempDir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error opening %q to clear old temp files: %s\n", LocalObjectTempDir, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filenames, _ := d.Readdirnames(-1)
|
||||||
|
for _, filename := range filenames {
|
||||||
|
path := filepath.Join(LocalObjectTempDir, filename)
|
||||||
|
if shouldDeleteTempObject(path) {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldDeleteTempObject(path string) bool {
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
base := filepath.Base(path)
|
||||||
|
parts := strings.SplitN(base, "-", 2)
|
||||||
|
oid := parts[0]
|
||||||
|
if len(parts) < 2 || len(oid) != 64 {
|
||||||
|
tracerx.Printf("Removing invalid tmp object file: %s", path)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if FileExists(localMediaPathNoCreate(oid)) {
|
||||||
|
tracerx.Printf("Removing existing tmp object file: %s", path)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.Since(info.ModTime()) > time.Hour {
|
||||||
|
tracerx.Printf("Removing old tmp object file: %s", path)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -1,14 +1,17 @@
|
|||||||
package lfs
|
package lfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/github/git-lfs/vendor/_nuts/github.com/cheggaaa/pb"
|
"github.com/github/git-lfs/vendor/_nuts/github.com/cheggaaa/pb"
|
||||||
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
||||||
contentaddressable "github.com/github/git-lfs/vendor/_nuts/github.com/technoweenie/go-contentaddressable"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func PointerSmudgeToFile(filename string, ptr *Pointer, download bool, cb CopyCallback) error {
|
func PointerSmudgeToFile(filename string, ptr *Pointer, download bool, cb CopyCallback) error {
|
||||||
@ -99,7 +102,6 @@ func downloadObject(ptr *Pointer, obj *objectResource, mediafile string, cb Copy
|
|||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this can be unified with the same code in downloadFile
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errorf(err, "Error downloading %s", mediafile)
|
return Errorf(err, "Error downloading %s", mediafile)
|
||||||
}
|
}
|
||||||
@ -108,18 +110,7 @@ func downloadObject(ptr *Pointer, obj *objectResource, mediafile string, cb Copy
|
|||||||
ptr.Size = size
|
ptr.Size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaFile, err := contentaddressable.NewFile(mediafile)
|
if err := bufferDownloadedFile(mediafile, reader, ptr.Size, cb); err != nil {
|
||||||
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.")
|
return Errorf(err, "Error buffering media file.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,31 +125,84 @@ func downloadFile(writer io.Writer, ptr *Pointer, workingfile, mediafile string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errorf(err, "Error downloading %s.", mediafile)
|
return Errorf(err, "Error downloading %s: %s", filepath.Base(mediafile), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ptr.Size == 0 {
|
if ptr.Size == 0 {
|
||||||
ptr.Size = size
|
ptr.Size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaFile, err := contentaddressable.NewFile(mediafile)
|
if err := bufferDownloadedFile(mediafile, reader, ptr.Size, cb); err != nil {
|
||||||
if err != nil {
|
return Errorf(err, "Error buffering media file: %s", err)
|
||||||
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.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return readLocalFile(writer, ptr, mediafile, workingfile, nil)
|
return readLocalFile(writer, ptr, mediafile, workingfile, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writes the content of reader to filename atomically by writing to a temp file
|
||||||
|
// first, and confirming the content SHA-256 is valid. This is basically a copy
|
||||||
|
// of atomic.WriteFile() at:
|
||||||
|
//
|
||||||
|
// https://github.com/natefinch/atomic/blob/a62ce929ffcc871a51e98c6eba7b20321e3ed62d/atomic.go#L12-L17
|
||||||
|
//
|
||||||
|
// filename - Absolute path to a file to write, with the filename a 64 character
|
||||||
|
// SHA-256 hex signature.
|
||||||
|
// reader - Any io.Reader
|
||||||
|
// size - Expected byte size of the content. Used for the progress bar in
|
||||||
|
// the optional CopyCallback.
|
||||||
|
// cb - Optional CopyCallback object for providing download progress to
|
||||||
|
// external Git LFS tools.
|
||||||
|
func bufferDownloadedFile(filename string, reader io.Reader, size int64, cb CopyCallback) error {
|
||||||
|
oid := filepath.Base(filename)
|
||||||
|
f, err := ioutil.TempFile(LocalObjectTempDir, oid+"-")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot create temp file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
// Don't leave the temp file lying around on error.
|
||||||
|
_ = os.Remove(f.Name()) // yes, ignore the error, not much we can do about it.
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
hasher := newHashingReader(reader)
|
||||||
|
|
||||||
|
// ensure we always close f. Note that this does not conflict with the
|
||||||
|
// close below, as close is idempotent.
|
||||||
|
defer f.Close()
|
||||||
|
name := f.Name()
|
||||||
|
written, err := CopyWithCallback(f, hasher, size, cb)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot write data to tempfile %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return fmt.Errorf("can't close tempfile %q: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual := hasher.Hash(); actual != oid {
|
||||||
|
return fmt.Errorf("Expected OID %s, got %s after %d bytes written", oid, actual, written)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the file mode from the original file and use that for the replacement
|
||||||
|
// file, too.
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// no original file
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if err := os.Chmod(name, info.Mode()); err != nil {
|
||||||
|
return fmt.Errorf("can't set filemode on tempfile %q: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Rename(name, filename); err != nil {
|
||||||
|
return fmt.Errorf("cannot replace %q with tempfile %q: %v", filename, name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, workingfile string, cb CopyCallback) error {
|
func readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, workingfile string, cb CopyCallback) error {
|
||||||
reader, err := os.Open(mediafile)
|
reader, err := os.Open(mediafile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -191,7 +235,7 @@ func readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, workingfile
|
|||||||
|
|
||||||
// pipe extensions in reverse order
|
// pipe extensions in reverse order
|
||||||
var extsR []Extension
|
var extsR []Extension
|
||||||
for i, _ := range exts {
|
for i := range exts {
|
||||||
ext := exts[len(exts)-1-i]
|
ext := exts[len(exts)-1-i]
|
||||||
extsR = append(extsR, ext)
|
extsR = append(extsR, ext)
|
||||||
}
|
}
|
||||||
@ -230,15 +274,41 @@ func readLocalFile(writer io.Writer, ptr *Pointer, mediafile string, workingfile
|
|||||||
// setup reader
|
// setup reader
|
||||||
reader, err = os.Open(response.file.Name())
|
reader, err = os.Open(response.file.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errorf(err, "Error opening smudged file.")
|
return Errorf(err, "Error opening smudged file: %s", err)
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = CopyWithCallback(writer, reader, ptr.Size, cb)
|
_, err = CopyWithCallback(writer, reader, ptr.Size, cb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errorf(err, "Error reading from media file.")
|
return Errorf(err, "Error reading from media file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type hashingReader struct {
|
||||||
|
reader io.Reader
|
||||||
|
hasher hash.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHashingReader(r io.Reader) *hashingReader {
|
||||||
|
tracerx.Printf("NEW HASHING READER")
|
||||||
|
return &hashingReader{r, sha256.New()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *hashingReader) Hash() string {
|
||||||
|
return hex.EncodeToString(r.hasher.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *hashingReader) Read(b []byte) (int, error) {
|
||||||
|
w, err := r.reader.Read(b)
|
||||||
|
if err == nil || err == io.EOF {
|
||||||
|
_, e := r.hasher.Write(b[0:w])
|
||||||
|
if e != nil && err == nil {
|
||||||
|
return w, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, err
|
||||||
|
}
|
||||||
|
@ -30,7 +30,6 @@ $ script/test lfs -run TestSuccessStatus -v
|
|||||||
github.com/kr/text
|
github.com/kr/text
|
||||||
github.com/cheggaaa/pb
|
github.com/cheggaaa/pb
|
||||||
github.com/rubyist/tracerx
|
github.com/rubyist/tracerx
|
||||||
github.com/technoweenie/go-contentaddressable
|
|
||||||
github.com/kr/pretty
|
github.com/kr/pretty
|
||||||
github.com/github/git-lfs/git
|
github.com/github/git-lfs/git
|
||||||
github.com/technoweenie/assert
|
github.com/technoweenie/assert
|
||||||
|
@ -18,7 +18,7 @@ begin_test "checkout"
|
|||||||
contentsize=19
|
contentsize=19
|
||||||
contents_oid=$(calc_oid "$contents")
|
contents_oid=$(calc_oid "$contents")
|
||||||
|
|
||||||
# Same content everywhere is ok, just one object in lfs db
|
echo "Same content everywhere is ok, just one object in lfs db"
|
||||||
printf "$contents" > file1.dat
|
printf "$contents" > file1.dat
|
||||||
printf "$contents" > file2.dat
|
printf "$contents" > file2.dat
|
||||||
printf "$contents" > file3.dat
|
printf "$contents" > file3.dat
|
||||||
@ -40,7 +40,7 @@ begin_test "checkout"
|
|||||||
# Remove the working directory
|
# Remove the working directory
|
||||||
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
||||||
|
|
||||||
# checkout should replace all
|
echo "checkout should replace all"
|
||||||
git lfs checkout
|
git lfs checkout
|
||||||
[ "$contents" = "$(cat file1.dat)" ]
|
[ "$contents" = "$(cat file1.dat)" ]
|
||||||
[ "$contents" = "$(cat file2.dat)" ]
|
[ "$contents" = "$(cat file2.dat)" ]
|
||||||
@ -51,7 +51,7 @@ begin_test "checkout"
|
|||||||
# Remove again
|
# Remove again
|
||||||
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
||||||
|
|
||||||
# checkout with filters
|
echo "checkout with filters"
|
||||||
git lfs checkout file2.dat
|
git lfs checkout file2.dat
|
||||||
[ "$contents" = "$(cat file2.dat)" ]
|
[ "$contents" = "$(cat file2.dat)" ]
|
||||||
[ ! -f file1.dat ]
|
[ ! -f file1.dat ]
|
||||||
@ -59,14 +59,14 @@ begin_test "checkout"
|
|||||||
[ ! -f folder1/nested.dat ]
|
[ ! -f folder1/nested.dat ]
|
||||||
[ ! -f folder2/nested.dat ]
|
[ ! -f folder2/nested.dat ]
|
||||||
|
|
||||||
# quotes to avoid shell globbing
|
echo "quotes to avoid shell globbing"
|
||||||
git lfs checkout "file*.dat"
|
git lfs checkout "file*.dat"
|
||||||
[ "$contents" = "$(cat file1.dat)" ]
|
[ "$contents" = "$(cat file1.dat)" ]
|
||||||
[ "$contents" = "$(cat file3.dat)" ]
|
[ "$contents" = "$(cat file3.dat)" ]
|
||||||
[ ! -f folder1/nested.dat ]
|
[ ! -f folder1/nested.dat ]
|
||||||
[ ! -f folder2/nested.dat ]
|
[ ! -f folder2/nested.dat ]
|
||||||
|
|
||||||
# test subdir context
|
echo "test subdir context"
|
||||||
pushd folder1
|
pushd folder1
|
||||||
git lfs checkout nested.dat
|
git lfs checkout nested.dat
|
||||||
[ "$contents" = "$(cat nested.dat)" ]
|
[ "$contents" = "$(cat nested.dat)" ]
|
||||||
@ -77,11 +77,11 @@ begin_test "checkout"
|
|||||||
[ "$contents" = "$(cat nested.dat)" ]
|
[ "$contents" = "$(cat nested.dat)" ]
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# test folder param
|
echo "test folder param"
|
||||||
git lfs checkout folder2
|
git lfs checkout folder2
|
||||||
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
||||||
|
|
||||||
# test '.' in current dir
|
echo "test '.' in current dir"
|
||||||
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
|
||||||
git lfs checkout .
|
git lfs checkout .
|
||||||
[ "$contents" = "$(cat file1.dat)" ]
|
[ "$contents" = "$(cat file1.dat)" ]
|
||||||
@ -90,7 +90,7 @@ begin_test "checkout"
|
|||||||
[ "$contents" = "$(cat folder1/nested.dat)" ]
|
[ "$contents" = "$(cat folder1/nested.dat)" ]
|
||||||
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
[ "$contents" = "$(cat folder2/nested.dat)" ]
|
||||||
|
|
||||||
# test checkout with missing data doesn't fail
|
echo "test checkout with missing data doesn't fail"
|
||||||
git push origin master
|
git push origin master
|
||||||
rm -rf .git/lfs/objects
|
rm -rf .git/lfs/objects
|
||||||
rm file*.dat
|
rm file*.dat
|
||||||
|
360
test/test-env.sh
360
test/test-env.sh
@ -13,19 +13,29 @@ begin_test "env with no remote"
|
|||||||
cd $reponame
|
cd $reponame
|
||||||
git init
|
git init
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
|
LocalWorkingDir=%s
|
||||||
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
|
||||||
|
contains_same_elements "$expected" "$actual"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -38,25 +48,34 @@ begin_test "env with origin remote"
|
|||||||
git init
|
git init
|
||||||
git remote add origin "$GITSERVER/env-origin-remote"
|
git remote add origin "$GITSERVER/env-origin-remote"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
endpoint="$GITSERVER/$reponame.git/info/lfs (auth=none)"
|
||||||
Endpoint=$GITSERVER/$reponame.git/info/lfs (auth=none)
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
|
Endpoint=%s
|
||||||
|
LocalWorkingDir=%s
|
||||||
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -70,26 +89,36 @@ begin_test "env with multiple remotes"
|
|||||||
git remote add origin "$GITSERVER/env-origin-remote"
|
git remote add origin "$GITSERVER/env-origin-remote"
|
||||||
git remote add other "$GITSERVER/env-other-remote"
|
git remote add other "$GITSERVER/env-other-remote"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
endpoint="$GITSERVER/env-origin-remote.git/info/lfs (auth=none)"
|
||||||
Endpoint=$GITSERVER/env-origin-remote.git/info/lfs (auth=none)
|
endpoint2="$GITSERVER/env-other-remote.git/info/lfs (auth=none)"
|
||||||
Endpoint (other)=$GITSERVER/env-other-remote.git/info/lfs (auth=none)
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
|
Endpoint=%s
|
||||||
|
Endpoint (other)=%s
|
||||||
|
LocalWorkingDir=%s
|
||||||
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$endpoint2" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -102,25 +131,35 @@ begin_test "env with other remote"
|
|||||||
git init
|
git init
|
||||||
git remote add other "$GITSERVER/env-other-remote"
|
git remote add other "$GITSERVER/env-other-remote"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
endpoint="$GITSERVER/env-other-remote.git/info/lfs (auth=none)"
|
||||||
Endpoint (other)=$GITSERVER/env-other-remote.git/info/lfs (auth=none)
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
|
Endpoint (other)=%s
|
||||||
|
LocalWorkingDir=%s
|
||||||
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -135,26 +174,35 @@ begin_test "env with multiple remotes and lfs.url config"
|
|||||||
git remote add other "$GITSERVER/env-other-remote"
|
git remote add other "$GITSERVER/env-other-remote"
|
||||||
git config lfs.url "http://foo/bar"
|
git config lfs.url "http://foo/bar"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
endpoint="$GITSERVER/env-other-remote.git/info/lfs (auth=none)"
|
||||||
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
Endpoint=http://foo/bar (auth=none)
|
Endpoint=http://foo/bar (auth=none)
|
||||||
Endpoint (other)=$GITSERVER/env-other-remote.git/info/lfs (auth=none)
|
Endpoint (other)=%s
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
LocalWorkingDir=%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
LocalGitDir=%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=%s
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$endpoint" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -171,26 +219,34 @@ begin_test "env with multiple remotes and lfs configs"
|
|||||||
git config remote.origin.lfsurl "http://custom/origin"
|
git config remote.origin.lfsurl "http://custom/origin"
|
||||||
git config remote.other.lfsurl "http://custom/other"
|
git config remote.other.lfsurl "http://custom/other"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
Endpoint=http://foo/bar (auth=none)
|
Endpoint=http://foo/bar (auth=none)
|
||||||
Endpoint (other)=http://custom/other (auth=none)
|
Endpoint (other)=http://custom/other (auth=none)
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
LocalWorkingDir=%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
LocalGitDir=%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=%s
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -209,26 +265,34 @@ begin_test "env with multiple remotes and lfs url and batch configs"
|
|||||||
git config remote.origin.lfsurl "http://custom/origin"
|
git config remote.origin.lfsurl "http://custom/origin"
|
||||||
git config remote.other.lfsurl "http://custom/other"
|
git config remote.other.lfsurl "http://custom/other"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
Endpoint=http://foo/bar (auth=none)
|
Endpoint=http://foo/bar (auth=none)
|
||||||
Endpoint (other)=http://custom/other (auth=none)
|
Endpoint (other)=http://custom/other (auth=none)
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
LocalWorkingDir=%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
LocalGitDir=%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=%s
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
TempDir=%s
|
||||||
ConcurrentTransfers=5
|
ConcurrentTransfers=5
|
||||||
BatchTransfer=false
|
BatchTransfer=false
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
expected2=$(echo "$expected" | sed -e 's/LocalWorkingDir=.*/LocalWorkingDir=/')
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected2" = "$actual2" ]
|
contains_same_elements "$expected2" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -248,26 +312,33 @@ begin_test "env with .gitconfig"
|
|||||||
concurrenttransfers = 5
|
concurrenttransfers = 5
|
||||||
' > .gitconfig
|
' > .gitconfig
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
localwd=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
Endpoint=http://foobar:8080/ (auth=none)
|
Endpoint=http://foobar:8080/ (auth=none)
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
LocalWorkingDir=%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
LocalGitDir=%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=%s
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
mkdir a
|
mkdir a
|
||||||
cd a
|
cd a
|
||||||
actual2=$(git lfs env)
|
actual2=$(git lfs env)
|
||||||
[ "$expected" = "$actual2" ]
|
contains_same_elements "$expected" "$actual2"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -278,80 +349,97 @@ begin_test "env with environment variables"
|
|||||||
git init $reponame
|
git init $reponame
|
||||||
mkdir -p $reponame/a/b/c
|
mkdir -p $reponame/a/b/c
|
||||||
|
|
||||||
gitDir=$TRASHDIR/$reponame/.git
|
gitDir=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
workTree=$TRASHDIR/$reponame/a/b
|
workTree=$(native_path "$TRASHDIR/$reponame/a/b")
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
localwd=$(native_path "$TRASHDIR/$reponame/a/b")
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame/a/b
|
localgit=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
localgitstore=$(native_path "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
localmedia=$(native_path "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
tempdir=$(native_path "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
envVars="$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree env | grep "^GIT" | sort)"
|
||||||
|
expected=$(printf '%s
|
||||||
|
%s
|
||||||
|
|
||||||
|
LocalWorkingDir=%s
|
||||||
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
|
|
||||||
actual=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame
|
cd $TRASHDIR/$reponame
|
||||||
actual2=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual2=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
||||||
[ "$expected" = "$actual2" ]
|
contains_same_elements "$expected" "$actual2"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/.git
|
cd $TRASHDIR/$reponame/.git
|
||||||
actual3=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual3=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
||||||
[ "$expected" = "$actual3" ]
|
contains_same_elements "$expected" "$actual3"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a/b/c
|
cd $TRASHDIR/$reponame/a/b/c
|
||||||
actual4=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
actual4=$(GIT_DIR=$gitDir GIT_WORK_TREE=$workTree git lfs env)
|
||||||
[ "$expected" = "$actual4" ]
|
contains_same_elements "$expected" "$actual4"
|
||||||
|
|
||||||
expected5=$(printf "%s\n%s\n
|
envVars="$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b env | grep "^GIT" | sort)"
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame/a/b
|
expected5=$(printf '%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalWorkingDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b env | grep "^GIT")
|
%s
|
||||||
git config filter.lfs.smudge = \"\"
|
git config filter.lfs.smudge = \"\"
|
||||||
git config filter.lfs.clean = \"\"
|
git config filter.lfs.clean = \"\"
|
||||||
" "$(git lfs version)" "$(git version)")
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars")
|
||||||
actual5=$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b git lfs env)
|
actual5=$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b git lfs env)
|
||||||
[ "$expected5" = "$actual5" ]
|
contains_same_elements "$expected5" "$actual5"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a/b
|
cd $TRASHDIR/$reponame/a/b
|
||||||
expected7=$(printf "%s\n%s\n
|
envVars="$(GIT_DIR=$gitDir env | grep "^GIT" | sort)"
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame/a/b
|
expected7=$(printf '%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalWorkingDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(GIT_DIR=$gitDir env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual7=$(GIT_DIR=$gitDir git lfs env)
|
actual7=$(GIT_DIR=$gitDir git lfs env)
|
||||||
[ "$expected7" = "$actual7" ]
|
contains_same_elements "$expected7" "$actual7"
|
||||||
|
|
||||||
cd $TRASHDIR/$reponame/a
|
cd $TRASHDIR/$reponame/a
|
||||||
expected8=$(printf "%s\n%s\n
|
envVars="$(GIT_WORK_TREE=$workTree env | grep "^GIT" | sort)"
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame/a/b
|
expected8=$(printf '%s
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalWorkingDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
LocalGitDir=%s
|
||||||
|
LocalGitStorageDir=%s
|
||||||
|
LocalMediaDir=%s
|
||||||
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(GIT_WORK_TREE=$workTree env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual8=$(GIT_WORK_TREE=$workTree git lfs env)
|
actual8=$(GIT_WORK_TREE=$workTree git lfs env)
|
||||||
[ "$expected8" = "$actual8" ]
|
contains_same_elements "$expected8" "$actual8"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -363,19 +451,25 @@ begin_test "env with bare repo"
|
|||||||
git init --bare $reponame
|
git init --bare $reponame
|
||||||
cd $reponame
|
cd $reponame
|
||||||
|
|
||||||
|
localgit=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localgitstore=$(native_path "$TRASHDIR/$reponame")
|
||||||
|
localmedia=$(native_path "$TRASHDIR/$reponame/lfs/objects")
|
||||||
|
tempdir=$(native_path "$TRASHDIR/$reponame/lfs/tmp")
|
||||||
|
envVars=$(printf "%s" "$(env | grep "^GIT")")
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
expected=$(printf "%s\n%s\n
|
||||||
LocalWorkingDir=
|
LocalWorkingDir=
|
||||||
LocalGitDir=$TRASHDIR/$reponame
|
LocalGitDir=%s
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame
|
LocalGitStorageDir=%s
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/lfs/objects
|
LocalMediaDir=%s
|
||||||
TempDir=$TRASHDIR/$reponame/lfs/tmp
|
TempDir=%s
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
%s
|
||||||
|
" "$(git lfs version)" "$(git version)" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$envVars" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -22,7 +22,7 @@ begin_test "fsck default"
|
|||||||
aOid=$(git log --patch a.dat | grep "^+oid" | cut -d ":" -f 2)
|
aOid=$(git log --patch a.dat | grep "^+oid" | cut -d ":" -f 2)
|
||||||
aOid12=$(echo $aOid | cut -b 1-2)
|
aOid12=$(echo $aOid | cut -b 1-2)
|
||||||
aOid34=$(echo $aOid | cut -b 3-4)
|
aOid34=$(echo $aOid | cut -b 3-4)
|
||||||
if [ "$aOid .git/lfs/objects/$aOid12/$aOid34/$aOid" != "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid)" ]; then
|
if [ "$aOid" != "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for a.dat does not match"
|
echo "oid for a.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -30,7 +30,7 @@ begin_test "fsck default"
|
|||||||
bOid=$(git log --patch b.dat | grep "^+oid" | cut -d ":" -f 2)
|
bOid=$(git log --patch b.dat | grep "^+oid" | cut -d ":" -f 2)
|
||||||
bOid12=$(echo $bOid | cut -b 1-2)
|
bOid12=$(echo $bOid | cut -b 1-2)
|
||||||
bOid34=$(echo $bOid | cut -b 3-4)
|
bOid34=$(echo $bOid | cut -b 3-4)
|
||||||
if [ "$bOid ".git/lfs/objects/$bOid12/$bOid34/$bOid != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid)" ]; then
|
if [ "$bOid" != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for b.dat does not match"
|
echo "oid for b.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -38,8 +38,9 @@ begin_test "fsck default"
|
|||||||
|
|
||||||
echo "CORRUPTION" >> .git/lfs/objects/$aOid12/$aOid34/$aOid
|
echo "CORRUPTION" >> .git/lfs/objects/$aOid12/$aOid34/$aOid
|
||||||
|
|
||||||
expected="Object a.dat ($aOid) is corrupt
|
moved=$(native_path "$TRASHDIR/$reponame/.git/lfs/bad/$aOid")
|
||||||
moved to $TRASHDIR/$reponame/.git/lfs/bad/$aOid"
|
expected="$(printf 'Object a.dat (%s) is corrupt
|
||||||
|
moved to %s' "$aOid" "$moved")"
|
||||||
[ "$expected" = "$(git lfs fsck)" ]
|
[ "$expected" = "$(git lfs fsck)" ]
|
||||||
|
|
||||||
if [ -e .git/lfs/objects/$aOid12/$aOid34/$aOid ]; then
|
if [ -e .git/lfs/objects/$aOid12/$aOid34/$aOid ]; then
|
||||||
@ -47,7 +48,7 @@ begin_test "fsck default"
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$bOid ".git/lfs/objects/$bOid12/$bOid34/$bOid != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid)" ]; then
|
if [ "$bOid" != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for b.dat does not match"
|
echo "oid for b.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -74,7 +75,7 @@ begin_test "fsck dry run"
|
|||||||
aOid=$(git log --patch a.dat | grep "^+oid" | cut -d ":" -f 2)
|
aOid=$(git log --patch a.dat | grep "^+oid" | cut -d ":" -f 2)
|
||||||
aOid12=$(echo $aOid | cut -b 1-2)
|
aOid12=$(echo $aOid | cut -b 1-2)
|
||||||
aOid34=$(echo $aOid | cut -b 3-4)
|
aOid34=$(echo $aOid | cut -b 3-4)
|
||||||
if [ "$aOid .git/lfs/objects/$aOid12/$aOid34/$aOid" != "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid)" ]; then
|
if [ "$aOid" != "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for a.dat does not match"
|
echo "oid for a.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -82,7 +83,7 @@ begin_test "fsck dry run"
|
|||||||
bOid=$(git log --patch b.dat | grep "^+oid" | cut -d ":" -f 2)
|
bOid=$(git log --patch b.dat | grep "^+oid" | cut -d ":" -f 2)
|
||||||
bOid12=$(echo $bOid | cut -b 1-2)
|
bOid12=$(echo $bOid | cut -b 1-2)
|
||||||
bOid34=$(echo $bOid | cut -b 3-4)
|
bOid34=$(echo $bOid | cut -b 3-4)
|
||||||
if [ "$bOid ".git/lfs/objects/$bOid12/$bOid34/$bOid != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid)" ]; then
|
if [ "$bOid" != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for b.dat does not match"
|
echo "oid for b.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -91,12 +92,12 @@ begin_test "fsck dry run"
|
|||||||
|
|
||||||
[ "Object a.dat ($aOid) is corrupt" = "$(git lfs fsck --dry-run)" ]
|
[ "Object a.dat ($aOid) is corrupt" = "$(git lfs fsck --dry-run)" ]
|
||||||
|
|
||||||
if [ "$aOid .git/lfs/objects/$aOid12/$aOid34/$aOid" = "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid)" ]; then
|
if [ "$aOid" = "$(shasum -a 256 .git/lfs/objects/$aOid12/$aOid34/$aOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for a.dat still matches match"
|
echo "oid for a.dat still matches match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$bOid ".git/lfs/objects/$bOid12/$bOid34/$bOid != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid)" ]; then
|
if [ "$bOid" != "$(shasum -a 256 .git/lfs/objects/$bOid12/$bOid34/$bOid | cut -d " " -f 1)" ]; then
|
||||||
echo "oid for b.dat does not match"
|
echo "oid for b.dat does not match"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -4,6 +4,41 @@
|
|||||||
|
|
||||||
. "test/testlib.sh"
|
. "test/testlib.sh"
|
||||||
|
|
||||||
|
begin_test "clears local temp objects"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
mkdir repo-temp-objects
|
||||||
|
cd repo-temp-objects
|
||||||
|
git init
|
||||||
|
|
||||||
|
# abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01
|
||||||
|
mkdir -p .git/lfs/objects/go/od
|
||||||
|
mkdir -p .git/lfs/tmp/objects
|
||||||
|
|
||||||
|
touch .git/lfs/objects/go/od/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx
|
||||||
|
touch .git/lfs/tmp/objects/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx-rand123
|
||||||
|
touch .git/lfs/tmp/objects/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx-rand456
|
||||||
|
touch .git/lfs/tmp/objects/badabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxy-rand123
|
||||||
|
touch .git/lfs/tmp/objects/badabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxy-rand456
|
||||||
|
|
||||||
|
GIT_TRACE=5 git lfs env
|
||||||
|
|
||||||
|
# object file exists
|
||||||
|
[ -e ".git/lfs/objects/go/od/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx" ]
|
||||||
|
|
||||||
|
# newer tmp files exist
|
||||||
|
[ -e ".git/lfs/tmp/objects/badabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxy-rand123" ]
|
||||||
|
[ -e ".git/lfs/tmp/objects/badabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxy-rand456" ]
|
||||||
|
|
||||||
|
# existing tmp files were cleaned up
|
||||||
|
[ ! -e ".git/lfs/tmp/objects/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx-rand123" ]
|
||||||
|
[ ! -e ".git/lfs/tmp/objects/goodabcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx-rand456" ]
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
begin_test "happy path"
|
begin_test "happy path"
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
|
@ -161,6 +161,12 @@ end_test
|
|||||||
|
|
||||||
begin_test "init --local outside repository"
|
begin_test "init --local outside repository"
|
||||||
(
|
(
|
||||||
|
# If run inside the git-lfs source dir this will update its .git/config & cause issues
|
||||||
|
if [ "$GIT_LFS_TEST_DIR" == "" ]; then
|
||||||
|
echo "Skipping init --local because GIT_LFS_TEST_DIR is not set"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
[ -n "$LFS_DOCKER" ] && exit 0
|
[ -n "$LFS_DOCKER" ] && exit 0
|
||||||
|
@ -93,7 +93,13 @@ end_test
|
|||||||
|
|
||||||
begin_test "pointer --stdin without stdin"
|
begin_test "pointer --stdin without stdin"
|
||||||
(
|
(
|
||||||
output=$(git lfs pointer --stdin 2>&1)
|
# this test doesn't work on Windows, it just operates like 'bad pointer' case
|
||||||
|
# stdin isn't detectable as detached, it just times out with no content
|
||||||
|
if [[ "$(is_stdin_attached)" == "0" ]]; then
|
||||||
|
echo "Skipping pointer without stdin because STDIN attached"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
output=$(echo "" | git lfs pointer --stdin 2>&1)
|
||||||
status=$?
|
status=$?
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@ -212,7 +218,7 @@ begin_test "pointer missing --pointer"
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
[ "1" = "$status" ]
|
[ "1" = "$status" ]
|
||||||
[ "open missing-pointer: no such file or directory" = "$output" ]
|
[[ "$output" == open missing-pointer:* ]]
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
@ -38,6 +38,24 @@ begin_test "smudge --info"
|
|||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "smudge with temp file"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd repo
|
||||||
|
|
||||||
|
rm -rf .git/lfs/objects
|
||||||
|
mkdir -p .git/lfs/tmp/objects
|
||||||
|
touch .git/lfs/tmp/objects/fcf5015df7a9089a7aa7fe74139d4b8f7d62e52d5a34f9a87aeffc8e8c668254-1
|
||||||
|
pointer fcf5015df7a9089a7aa7fe74139d4b8f7d62e52d5a34f9a87aeffc8e8c668254 9 | GIT_TRACE=5 git lfs smudge | tee smudge.log
|
||||||
|
[ "smudge a" = "$(cat smudge.log)" ] || {
|
||||||
|
rm -rf .git/lfs/tmp
|
||||||
|
git lfs logs last
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
begin_test "smudge with invalid pointer"
|
begin_test "smudge with invalid pointer"
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
|
@ -41,43 +41,44 @@ begin_test "submodule env"
|
|||||||
|
|
||||||
git lfs env | tee env.log
|
git lfs env | tee env.log
|
||||||
grep "Endpoint=$GITSERVER/$reponame.git/info/lfs (auth=none)$" env.log
|
grep "Endpoint=$GITSERVER/$reponame.git/info/lfs (auth=none)$" env.log
|
||||||
grep "LocalWorkingDir=$TRASHDIR/repo$" env.log
|
grep "LocalWorkingDir=$(native_path_escaped "$TRASHDIR/repo$")" env.log
|
||||||
grep "LocalGitDir=$TRASHDIR/repo/.git$" env.log
|
grep "LocalGitDir=$(native_path_escaped "$TRASHDIR/repo/.git$")" env.log
|
||||||
grep "LocalGitStorageDir=$TRASHDIR/repo/.git$" env.log
|
grep "LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/repo/.git$")" env.log
|
||||||
grep "LocalMediaDir=$TRASHDIR/repo/.git/lfs/objects$" env.log
|
grep "LocalMediaDir=$(native_path_escaped "$TRASHDIR/repo/.git/lfs/objects$")" env.log
|
||||||
grep "TempDir=$TRASHDIR/repo/.git/lfs/tmp$" env.log
|
grep "TempDir=$(native_path_escaped "$TRASHDIR/repo/.git/lfs/tmp$")" env.log
|
||||||
|
|
||||||
cd .git
|
cd .git
|
||||||
|
|
||||||
echo "./.git"
|
echo "./.git"
|
||||||
git lfs env | tee env.log
|
git lfs env | tee env.log
|
||||||
|
cat env.log
|
||||||
grep "Endpoint=$GITSERVER/$reponame.git/info/lfs (auth=none)$" env.log
|
grep "Endpoint=$GITSERVER/$reponame.git/info/lfs (auth=none)$" env.log
|
||||||
grep "LocalWorkingDir=$" env.log
|
grep "LocalWorkingDir=$" env.log
|
||||||
grep "LocalGitDir=$TRASHDIR/repo/.git$" env.log
|
grep "LocalGitDir=$(native_path_escaped "$TRASHDIR/repo/.git$")" env.log
|
||||||
grep "LocalGitStorageDir=$TRASHDIR/repo/.git$" env.log
|
grep "LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/repo/.git$")" env.log
|
||||||
grep "LocalMediaDir=$TRASHDIR/repo/.git/lfs/objects$" env.log
|
grep "LocalMediaDir=$(native_path_escaped "$TRASHDIR/repo/.git/lfs/objects$")" env.log
|
||||||
grep "TempDir=$TRASHDIR/repo/.git/lfs/tmp$" env.log
|
grep "TempDir=$(native_path_escaped "$TRASHDIR/repo/.git/lfs/tmp$")" env.log
|
||||||
|
|
||||||
cd ../sub
|
cd ../sub
|
||||||
|
|
||||||
echo "./sub"
|
echo "./sub"
|
||||||
git lfs env | tee env.log
|
git lfs env | tee env.log
|
||||||
grep "Endpoint=$GITSERVER/$submodname.git/info/lfs (auth=none)$" env.log
|
grep "Endpoint=$GITSERVER/$submodname.git/info/lfs (auth=none)$" env.log
|
||||||
grep "LocalWorkingDir=$TRASHDIR/repo/sub$" env.log
|
grep "LocalWorkingDir=$(native_path_escaped "$TRASHDIR/repo/sub$")" env.log
|
||||||
grep "LocalGitDir=$TRASHDIR/repo/.git/modules/sub$" env.log
|
grep "LocalGitDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub$")" env.log
|
||||||
grep "LocalGitStorageDir=$TRASHDIR/repo/.git/modules/sub$" env.log
|
grep "LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub$")" env.log
|
||||||
grep "LocalMediaDir=$TRASHDIR/repo/.git/modules/sub/lfs/objects$" env.log
|
grep "LocalMediaDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub/lfs/objects$")" env.log
|
||||||
grep "TempDir=$TRASHDIR/repo/.git/modules/sub/lfs/tmp$" env.log
|
grep "TempDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub/lfs/tmp$")" env.log
|
||||||
|
|
||||||
cd dir
|
cd dir
|
||||||
|
|
||||||
echo "./sub/dir"
|
echo "./sub/dir"
|
||||||
git lfs env | tee env.log
|
git lfs env | tee env.log
|
||||||
grep "Endpoint=$GITSERVER/$submodname.git/info/lfs (auth=none)$" env.log
|
grep "Endpoint=$GITSERVER/$submodname.git/info/lfs (auth=none)$" env.log
|
||||||
grep "LocalWorkingDir=$TRASHDIR/repo/sub$" env.log
|
grep "LocalWorkingDir=$(native_path_escaped "$TRASHDIR/repo/sub$")" env.log
|
||||||
grep "LocalGitDir=$TRASHDIR/repo/.git/modules/sub$" env.log
|
grep "LocalGitDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub$")" env.log
|
||||||
grep "LocalGitStorageDir=$TRASHDIR/repo/.git/modules/sub$" env.log
|
grep "LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub$")" env.log
|
||||||
grep "LocalMediaDir=$TRASHDIR/repo/.git/modules/sub/lfs/objects$" env.log
|
grep "LocalMediaDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub/lfs/objects$")" env.log
|
||||||
grep "TempDir=$TRASHDIR/repo/.git/modules/sub/lfs/tmp$" env.log
|
grep "TempDir=$(native_path_escaped "$TRASHDIR/repo/.git/modules/sub/lfs/tmp$")" env.log
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -38,10 +38,10 @@ begin_test "track"
|
|||||||
|
|
||||||
out=$(git lfs track)
|
out=$(git lfs track)
|
||||||
echo "$out" | grep "Listing tracked paths"
|
echo "$out" | grep "Listing tracked paths"
|
||||||
echo "$out" | grep "*.mov (.git/info/attributes)"
|
echo "$out" | grep "*.mov ($(native_path_escaped ".git/info/attributes"))"
|
||||||
echo "$out" | grep "*.jpg (.gitattributes)"
|
echo "$out" | grep "*.jpg (.gitattributes)"
|
||||||
echo "$out" | grep "*.gif (a/.gitattributes)"
|
echo "$out" | grep "*.gif ($(native_path_escaped "a/.gitattributes"))"
|
||||||
echo "$out" | grep "*.png (a/b/.gitattributes)"
|
echo "$out" | grep "*.png ($(native_path_escaped "a/b/.gitattributes"))"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
@ -134,9 +134,9 @@ begin_test "track representation"
|
|||||||
cd track-representation
|
cd track-representation
|
||||||
|
|
||||||
git lfs track "*.jpg"
|
git lfs track "*.jpg"
|
||||||
out=$(git lfs track "$PWD/*.jpg")
|
out=$(git lfs track "$(native_path "$PWD/")*.jpg")
|
||||||
|
|
||||||
if [ "$out" != "$PWD/*.jpg already supported" ]; then
|
if [ "$out" != "$(native_path "$PWD/")*.jpg already supported" ]; then
|
||||||
echo "Track didn't recognize duplicate path"
|
echo "Track didn't recognize duplicate path"
|
||||||
cat .gitattributes
|
cat .gitattributes
|
||||||
exit 1
|
exit 1
|
||||||
@ -179,7 +179,7 @@ begin_test "track absolute"
|
|||||||
git init track-absolute
|
git init track-absolute
|
||||||
cd track-absolute
|
cd track-absolute
|
||||||
|
|
||||||
git lfs track "$PWD/*.jpg"
|
git lfs track "$(native_path "$PWD/")*.jpg"
|
||||||
grep "^*.jpg" .gitattributes || {
|
grep "^*.jpg" .gitattributes || {
|
||||||
echo ".gitattributes doesn't contain the expected relative path *.jpg:"
|
echo ".gitattributes doesn't contain the expected relative path *.jpg:"
|
||||||
cat .gitattributes
|
cat .gitattributes
|
||||||
|
@ -20,18 +20,18 @@ begin_test "git worktree"
|
|||||||
git commit -m "Initial commit"
|
git commit -m "Initial commit"
|
||||||
|
|
||||||
expected=$(printf "%s\n%s\n
|
expected=$(printf "%s\n%s\n
|
||||||
LocalWorkingDir=$TRASHDIR/$reponame
|
LocalWorkingDir=$(native_path_escaped "$TRASHDIR/$reponame")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git
|
LocalGitDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/lfs/tmp
|
TempDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/tmp")
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
$(escape_path "$(env | grep "^GIT")")
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
|
|
||||||
worktreename="worktree-2"
|
worktreename="worktree-2"
|
||||||
git worktree add "$TRASHDIR/$worktreename"
|
git worktree add "$TRASHDIR/$worktreename"
|
||||||
@ -41,17 +41,17 @@ $(env | grep "^GIT")
|
|||||||
# is only for index, temp etc
|
# is only for index, temp etc
|
||||||
# storage of git objects and lfs objects is in the original .git
|
# storage of git objects and lfs objects is in the original .git
|
||||||
expected=$(printf "%s\n%s\n
|
expected=$(printf "%s\n%s\n
|
||||||
LocalWorkingDir=$TRASHDIR/$worktreename
|
LocalWorkingDir=$(native_path_escaped "$TRASHDIR/$worktreename")
|
||||||
LocalGitDir=$TRASHDIR/$reponame/.git/worktrees/$worktreename
|
LocalGitDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/worktrees/$worktreename")
|
||||||
LocalGitStorageDir=$TRASHDIR/$reponame/.git
|
LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
|
||||||
LocalMediaDir=$TRASHDIR/$reponame/.git/lfs/objects
|
LocalMediaDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/objects")
|
||||||
TempDir=$TRASHDIR/$reponame/.git/worktrees/$worktreename/lfs/tmp
|
TempDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/worktrees/$worktreename/lfs/tmp")
|
||||||
ConcurrentTransfers=3
|
ConcurrentTransfers=3
|
||||||
BatchTransfer=true
|
BatchTransfer=true
|
||||||
$(env | grep "^GIT")
|
$(escape_path "$(env | grep "^GIT")")
|
||||||
%s
|
%s
|
||||||
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
" "$(git lfs version)" "$(git version)" "$envInitConfig")
|
||||||
actual=$(git lfs env)
|
actual=$(git lfs env)
|
||||||
[ "$expected" = "$actual" ]
|
contains_same_elements "$expected" "$actual"
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -49,6 +49,13 @@ TESTHOME="$REMOTEDIR/home"
|
|||||||
|
|
||||||
GIT_CONFIG_NOSYSTEM=1
|
GIT_CONFIG_NOSYSTEM=1
|
||||||
|
|
||||||
|
UNAME=$(uname -s)
|
||||||
|
IS_WINDOWS=0
|
||||||
|
if [[ $UNAME == MINGW* || $UNAME == CYGWIN* ]]
|
||||||
|
then
|
||||||
|
IS_WINDOWS=1
|
||||||
|
fi
|
||||||
|
|
||||||
export CREDSDIR
|
export CREDSDIR
|
||||||
|
|
||||||
if [[ `git config --system credential.helper | grep osxkeychain` == "osxkeychain" ]]
|
if [[ `git config --system credential.helper | grep osxkeychain` == "osxkeychain" ]]
|
||||||
|
@ -382,3 +382,51 @@ get_date() {
|
|||||||
date $ARGS -u +%Y-%m-%dT%TZ
|
date $ARGS -u +%Y-%m-%dT%TZ
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Convert potentially MinGW bash paths to native Windows paths
|
||||||
|
# Needed to match generic built paths in test scripts to native paths generated from Go
|
||||||
|
native_path() {
|
||||||
|
local arg=$1
|
||||||
|
if [ $IS_WINDOWS == "1" ]; then
|
||||||
|
# Use params form to avoid interpreting any '\' characters
|
||||||
|
printf '%s' "$(cygpath -w $arg)"
|
||||||
|
else
|
||||||
|
printf '%s' "$arg"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# escape any instance of '\' with '\\' on Windows
|
||||||
|
escape_path() {
|
||||||
|
local unescaped="$1"
|
||||||
|
if [ $IS_WINDOWS == "1" ]; then
|
||||||
|
printf '%s' "${unescaped//\\/\\\\}"
|
||||||
|
else
|
||||||
|
printf '%s' "$unescaped"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# As native_path but escape all backslash characters to "\\"
|
||||||
|
native_path_escaped() {
|
||||||
|
local unescaped=$(native_path "$1")
|
||||||
|
escape_path "$unescaped"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare 2 lists which are newline-delimited in a string, ignoring ordering and blank lines
|
||||||
|
contains_same_elements() {
|
||||||
|
# Remove blank lines then sort
|
||||||
|
printf '%s' "$1" | grep -v '^$' | sort > a.txt
|
||||||
|
printf '%s' "$2" | grep -v '^$' | sort > b.txt
|
||||||
|
|
||||||
|
set +e
|
||||||
|
diff -u a.txt b.txt 1>&2
|
||||||
|
res=$?
|
||||||
|
set -e
|
||||||
|
rm a.txt b.txt
|
||||||
|
exit $res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_stdin_attached() {
|
||||||
|
test -t0
|
||||||
|
echo $?
|
||||||
|
}
|
@ -75,11 +75,17 @@ begin_test () {
|
|||||||
err="$TRASHDIR/err"
|
err="$TRASHDIR/err"
|
||||||
trace="$TRASHDIR/trace"
|
trace="$TRASHDIR/trace"
|
||||||
|
|
||||||
exec 1>"$out" 2>"$err" 5>"$trace"
|
exec 1>"$out" 2>"$err"
|
||||||
|
|
||||||
|
# enabling GIT_TRACE can cause Windows git to stall, esp with fd 5
|
||||||
|
# other fd numbers like 8/9 don't stall but still don't work, so disable
|
||||||
|
if [ $IS_WINDOWS == "0" ]; then
|
||||||
|
exec 5>"$trace"
|
||||||
|
export GIT_TRACE=5
|
||||||
|
fi
|
||||||
|
|
||||||
# reset global git config
|
# reset global git config
|
||||||
HOME="$TRASHDIR/home"
|
HOME="$TRASHDIR/home"
|
||||||
export GIT_TRACE=5
|
|
||||||
rm -rf "$TRASHDIR/home"
|
rm -rf "$TRASHDIR/home"
|
||||||
mkdir "$HOME"
|
mkdir "$HOME"
|
||||||
cp "$TESTHOME/.gitconfig" "$HOME/.gitconfig"
|
cp "$TESTHOME/.gitconfig" "$HOME/.gitconfig"
|
||||||
@ -97,6 +103,8 @@ end_test () {
|
|||||||
test_status="${1:-$?}"
|
test_status="${1:-$?}"
|
||||||
set +x -e
|
set +x -e
|
||||||
exec 1>&3 2>&4
|
exec 1>&3 2>&4
|
||||||
|
# close fd 5 (GIT_TRACE)
|
||||||
|
exec 5>&-
|
||||||
|
|
||||||
if [ "$test_status" -eq 0 ]; then
|
if [ "$test_status" -eq 0 ]; then
|
||||||
printf "test: %-60s OK\n" "$test_description ..."
|
printf "test: %-60s OK\n" "$test_description ..."
|
||||||
@ -109,8 +117,10 @@ end_test () {
|
|||||||
echo "-- stderr --"
|
echo "-- stderr --"
|
||||||
grep -v -e '^\+ end_test' -e '^+ set +x' <"$TRASHDIR/err" |
|
grep -v -e '^\+ end_test' -e '^+ set +x' <"$TRASHDIR/err" |
|
||||||
sed 's/^/ /'
|
sed 's/^/ /'
|
||||||
echo "-- git trace --"
|
if [ "$IS_WINDOWS" == "0" ]; then
|
||||||
sed 's/^/ /' <"$TRASHDIR/trace"
|
echo "-- git trace --"
|
||||||
|
sed 's/^/ /' <"$TRASHDIR/trace"
|
||||||
|
fi
|
||||||
) 1>&2
|
) 1>&2
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2014 rick olson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,49 +0,0 @@
|
|||||||
# Content Addressable
|
|
||||||
|
|
||||||
Package contentaddressable contains tools for writing content addressable files.
|
|
||||||
Files are written to a temporary location, and only renamed to the final
|
|
||||||
location after the file's OID (Object ID) has been verified.
|
|
||||||
|
|
||||||
```go
|
|
||||||
filename := "path/to/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"
|
|
||||||
file, err := contentaddressable.NewFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
file.Oid // 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
|
|
||||||
|
|
||||||
written, err := io.Copy(file, someReader)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
// Move file to final location if OID is verified.
|
|
||||||
err = file.Accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [godocs](http://godoc.org/github.com/technoweenie/go-contentaddressable)
|
|
||||||
for details.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
$ go get github.com/technoweenie/go-contentaddressable
|
|
||||||
|
|
||||||
Then import it:
|
|
||||||
|
|
||||||
import "github.com/technoweenie/go-contentaddressable"
|
|
||||||
|
|
||||||
## Note on Patches/Pull Requests
|
|
||||||
|
|
||||||
1. Fork the project on GitHub.
|
|
||||||
2. Make your feature addition or bug fix.
|
|
||||||
3. Add tests for it. This is important so I don't break it in a future version
|
|
||||||
unintentionally.
|
|
||||||
4. Commit, do not mess with version or history. (if you want to have
|
|
||||||
your own version, that is fine but bump version in a commit by itself I can
|
|
||||||
ignore when I pull)
|
|
||||||
5. Send me a pull request. Bonus points for topic branches.
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
Package contentaddressable contains tools for writing content addressable files.
|
|
||||||
Files are written to a temporary location, and only renamed to the final
|
|
||||||
location after the file's OID (Object ID) has been verified.
|
|
||||||
|
|
||||||
filename := "path/to/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"
|
|
||||||
file, err := contentaddressable.NewFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
file.Oid // 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
|
|
||||||
|
|
||||||
written, err := io.Copy(file, someReader)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
// Move file to final location if OID is verified.
|
|
||||||
err = file.Accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Currently SHA-256 is used for a file's OID.
|
|
||||||
*/
|
|
||||||
package contentaddressable
|
|
@ -1,131 +0,0 @@
|
|||||||
package contentaddressable
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
AlreadyClosed = errors.New("Already closed.")
|
|
||||||
HasData = errors.New("Destination file already has data.")
|
|
||||||
)
|
|
||||||
|
|
||||||
// File handles the atomic writing of a content addressable file. It writes to
|
|
||||||
// a temp file, and then renames to the final location after Accept().
|
|
||||||
type File struct {
|
|
||||||
Oid string
|
|
||||||
filename string
|
|
||||||
tempFilename string
|
|
||||||
file *os.File
|
|
||||||
tempFile *os.File
|
|
||||||
hasher hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFile initializes a content addressable file for writing. It opens both
|
|
||||||
// the given filename, and a temp filename in exclusive mode. The *File OID
|
|
||||||
// is taken from the base name of the given filename.
|
|
||||||
func NewFile(filename string) (*File, error) {
|
|
||||||
oid := filepath.Base(filename)
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFilename := filename + "-temp"
|
|
||||||
tempFile, err := os.OpenFile(tempFilename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
|
|
||||||
if err != nil {
|
|
||||||
cleanupFile(tempFile)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
caw := &File{
|
|
||||||
Oid: oid,
|
|
||||||
filename: filename,
|
|
||||||
tempFilename: tempFilename,
|
|
||||||
file: file,
|
|
||||||
tempFile: tempFile,
|
|
||||||
hasher: sha256.New(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return caw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write sends data to the temporary file.
|
|
||||||
func (w *File) Write(p []byte) (int, error) {
|
|
||||||
if w.Closed() {
|
|
||||||
return 0, AlreadyClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
w.hasher.Write(p)
|
|
||||||
return w.tempFile.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept verifies the written content SHA-256 signature matches the given OID.
|
|
||||||
// If it matches, the temp file is renamed to the original filename. If not,
|
|
||||||
// an error is returned.
|
|
||||||
func (w *File) Accept() error {
|
|
||||||
if w.Closed() {
|
|
||||||
return AlreadyClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
sig := hex.EncodeToString(w.hasher.Sum(nil))
|
|
||||||
if sig != w.Oid {
|
|
||||||
return fmt.Errorf("Content mismatch. Expected OID %s, got %s", w.Oid, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cleanupFile(w.file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.file = nil
|
|
||||||
|
|
||||||
w.tempFile.Close()
|
|
||||||
err := os.Rename(w.tempFilename, w.filename)
|
|
||||||
w.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cleans up the internal file objects.
|
|
||||||
func (w *File) Close() error {
|
|
||||||
if w.tempFile != nil {
|
|
||||||
if err := cleanupFile(w.tempFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.tempFile = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if w.file != nil {
|
|
||||||
if err := cleanupFile(w.file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.file = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closed reports whether this file object has been closed.
|
|
||||||
func (w *File) Closed() bool {
|
|
||||||
if w.tempFile == nil || w.file == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupFile(f *os.File) error {
|
|
||||||
err := f.Close()
|
|
||||||
if err := os.RemoveAll(f.Name()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
@ -1,176 +0,0 @@
|
|||||||
package contentaddressable
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
var supOid = "a2b71d6ee8997eb87b25ab42d566c44f6a32871752c7c73eb5578cb1182f7be0"
|
|
||||||
|
|
||||||
func TestFile(t *testing.T) {
|
|
||||||
test := SetupFile(t)
|
|
||||||
defer test.Teardown()
|
|
||||||
|
|
||||||
filename := filepath.Join(test.Path, supOid)
|
|
||||||
aw, err := NewFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
|
|
||||||
n, err := aw.Write([]byte("SUP"))
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, 3, n)
|
|
||||||
|
|
||||||
by, err := ioutil.ReadFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, 0, len(by))
|
|
||||||
|
|
||||||
assertEqual(t, nil, aw.Accept())
|
|
||||||
|
|
||||||
by, err = ioutil.ReadFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, "SUP", string(by))
|
|
||||||
|
|
||||||
assertEqual(t, nil, aw.Close())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileMismatch(t *testing.T) {
|
|
||||||
test := SetupFile(t)
|
|
||||||
defer test.Teardown()
|
|
||||||
|
|
||||||
filename := filepath.Join(test.Path, "b2b71d6ee8997eb87b25ab42d566c44f6a32871752c7c73eb5578cb1182f7be0")
|
|
||||||
aw, err := NewFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
|
|
||||||
n, err := aw.Write([]byte("SUP"))
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, 3, n)
|
|
||||||
|
|
||||||
by, err := ioutil.ReadFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, 0, len(by))
|
|
||||||
|
|
||||||
err = aw.Accept()
|
|
||||||
if err == nil || !strings.Contains(err.Error(), "Content mismatch") {
|
|
||||||
t.Errorf("Expected mismatch error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
by, err = ioutil.ReadFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, "", string(by))
|
|
||||||
|
|
||||||
assertEqual(t, nil, aw.Close())
|
|
||||||
|
|
||||||
_, err = ioutil.ReadFile(filename)
|
|
||||||
assertEqual(t, true, os.IsNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileCancel(t *testing.T) {
|
|
||||||
test := SetupFile(t)
|
|
||||||
defer test.Teardown()
|
|
||||||
|
|
||||||
filename := filepath.Join(test.Path, supOid)
|
|
||||||
aw, err := NewFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
|
|
||||||
n, err := aw.Write([]byte("SUP"))
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, 3, n)
|
|
||||||
|
|
||||||
assertEqual(t, nil, aw.Close())
|
|
||||||
|
|
||||||
for _, name := range []string{aw.filename, aw.tempFilename} {
|
|
||||||
if _, err := os.Stat(name); err == nil {
|
|
||||||
t.Errorf("%s exists?", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileLocks(t *testing.T) {
|
|
||||||
test := SetupFile(t)
|
|
||||||
defer test.Teardown()
|
|
||||||
|
|
||||||
filename := filepath.Join(test.Path, supOid)
|
|
||||||
aw, err := NewFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
assertEqual(t, filename, aw.filename)
|
|
||||||
assertEqual(t, filename+"-temp", aw.tempFilename)
|
|
||||||
|
|
||||||
files := []string{aw.filename, aw.tempFilename}
|
|
||||||
|
|
||||||
for _, name := range files {
|
|
||||||
if _, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0665); err == nil {
|
|
||||||
t.Errorf("Able to open %s!", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEqual(t, nil, aw.Close())
|
|
||||||
|
|
||||||
for _, name := range files {
|
|
||||||
f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0665)
|
|
||||||
assertEqualf(t, nil, err, "unable to open %s: %s", name, err)
|
|
||||||
cleanupFile(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileDuel(t *testing.T) {
|
|
||||||
test := SetupFile(t)
|
|
||||||
defer test.Teardown()
|
|
||||||
|
|
||||||
filename := filepath.Join(test.Path, supOid)
|
|
||||||
aw, err := NewFile(filename)
|
|
||||||
assertEqual(t, nil, err)
|
|
||||||
defer aw.Close()
|
|
||||||
|
|
||||||
if _, err := NewFile(filename); err == nil {
|
|
||||||
t.Errorf("Expected a file open conflict!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupFile(t *testing.T) *FileTest {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error getting wd: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &FileTest{filepath.Join(wd, "File"), t}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileTest struct {
|
|
||||||
Path string
|
|
||||||
*testing.T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *FileTest) Teardown() {
|
|
||||||
if err := os.RemoveAll(t.Path); err != nil {
|
|
||||||
t.Fatalf("Error removing %s: %s", t.Path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertEqual(t *testing.T, expected, actual interface{}) {
|
|
||||||
checkAssertion(t, expected, actual, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertEqualf(t *testing.T, expected, actual interface{}, format string, args ...interface{}) {
|
|
||||||
checkAssertion(t, expected, actual, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAssertion(t *testing.T, expected, actual interface{}, format string, args ...interface{}) {
|
|
||||||
if expected == nil {
|
|
||||||
if actual == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if reflect.DeepEqual(expected, actual) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, file, line, _ := runtime.Caller(2) // assertEqual + checkAssertion
|
|
||||||
t.Logf("%s:%d\nExpected: %v\nActual: %v", file, line, expected, actual)
|
|
||||||
if len(args) > 0 {
|
|
||||||
t.Logf("! - "+format, args...)
|
|
||||||
}
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user