2015-05-14 16:33:29 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
2015-07-28 13:50:19 +00:00
|
|
|
"time"
|
|
|
|
|
2015-05-14 16:33:29 +00:00
|
|
|
"github.com/github/git-lfs/git"
|
|
|
|
"github.com/github/git-lfs/lfs"
|
2015-05-28 17:52:06 +00:00
|
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
|
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
|
2015-05-14 16:33:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2015-05-29 15:28:10 +00:00
|
|
|
fetchCmd = &cobra.Command{
|
|
|
|
Use: "fetch",
|
2015-07-24 14:25:43 +00:00
|
|
|
Short: "Downloads LFS files",
|
2015-05-29 15:28:10 +00:00
|
|
|
Run: fetchCommand,
|
2015-05-14 16:33:29 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2015-05-29 15:28:10 +00:00
|
|
|
func fetchCommand(cmd *cobra.Command, args []string) {
|
2015-07-29 15:34:15 +00:00
|
|
|
var refs []string
|
2015-05-14 16:33:29 +00:00
|
|
|
|
2015-07-29 15:34:15 +00:00
|
|
|
if len(args) > 0 {
|
|
|
|
refs = args
|
2015-05-14 16:33:29 +00:00
|
|
|
} else {
|
2015-07-29 15:34:15 +00:00
|
|
|
ref, err := git.CurrentRef()
|
2015-05-14 16:33:29 +00:00
|
|
|
if err != nil {
|
2015-05-29 15:28:10 +00:00
|
|
|
Panic(err, "Could not fetch")
|
2015-05-14 16:33:29 +00:00
|
|
|
}
|
2015-07-29 15:34:15 +00:00
|
|
|
refs = []string{ref}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch refs sequentially per arg order; duplicates in later refs will be ignored
|
|
|
|
for _, ref := range refs {
|
|
|
|
fetchRef(ref)
|
2015-05-14 16:33:29 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 16:53:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
RootCmd.AddCommand(fetchCmd)
|
|
|
|
}
|
|
|
|
|
2015-07-29 09:26:14 +00:00
|
|
|
func fetchRefToChan(ref string) chan *lfs.WrappedPointer {
|
|
|
|
c := make(chan *lfs.WrappedPointer)
|
|
|
|
pointers, err := lfs.ScanRefs(ref, "", nil)
|
|
|
|
if err != nil {
|
|
|
|
Panic(err, "Could not scan for Git LFS files")
|
|
|
|
}
|
|
|
|
|
|
|
|
go fetchAndReportToChan(pointers, c)
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2015-07-27 10:28:46 +00:00
|
|
|
// Fetch all binaries for a given ref (that we don't have already)
|
|
|
|
func fetchRef(ref string) {
|
|
|
|
pointers, err := lfs.ScanRefs(ref, "", nil)
|
|
|
|
if err != nil {
|
|
|
|
Panic(err, "Could not scan for Git LFS files")
|
|
|
|
}
|
|
|
|
fetchPointers(pointers)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchPointers(pointers []*lfs.WrappedPointer) {
|
2015-07-23 16:53:58 +00:00
|
|
|
fetchAndReportToChan(pointers, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch and report completion of each OID to a channel (optional, pass nil to skip)
|
|
|
|
func fetchAndReportToChan(pointers []*lfs.WrappedPointer, out chan<- *lfs.WrappedPointer) {
|
2015-05-14 16:33:29 +00:00
|
|
|
|
2015-07-27 20:41:57 +00:00
|
|
|
totalSize := int64(0)
|
|
|
|
for _, p := range pointers {
|
|
|
|
totalSize += p.Size
|
|
|
|
}
|
2015-07-30 14:43:50 +00:00
|
|
|
q := lfs.NewDownloadQueue(len(pointers), totalSize, false)
|
2015-05-14 16:33:29 +00:00
|
|
|
|
|
|
|
for _, p := range pointers {
|
2015-07-24 16:27:39 +00:00
|
|
|
// Only add to download queue if local file is not the right size already
|
|
|
|
// This avoids previous case of over-reporting a requirement for files we already have
|
|
|
|
// which would only be skipped by PointerSmudgeObject later
|
|
|
|
if !lfs.ObjectExistsOfSize(p.Oid, p.Size) {
|
|
|
|
q.Add(lfs.NewDownloadable(p))
|
2015-07-29 09:26:14 +00:00
|
|
|
} else {
|
|
|
|
// If we already have it, report it to chan immediately to support pull/checkout
|
2015-07-29 15:24:18 +00:00
|
|
|
if out != nil {
|
|
|
|
out <- p
|
|
|
|
}
|
|
|
|
|
2015-07-24 16:27:39 +00:00
|
|
|
}
|
2015-05-14 16:33:29 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 16:53:58 +00:00
|
|
|
if out != nil {
|
|
|
|
dlwatch := q.Watch()
|
2015-05-27 19:45:18 +00:00
|
|
|
|
|
|
|
go func() {
|
2015-07-23 16:53:58 +00:00
|
|
|
// fetch only reports single OID, but OID *might* be referenced by multiple
|
|
|
|
// WrappedPointers if same content is at multiple paths, so map oid->slice
|
|
|
|
oidToPointers := make(map[string][]*lfs.WrappedPointer, len(pointers))
|
2015-05-27 19:45:18 +00:00
|
|
|
for _, pointer := range pointers {
|
2015-07-23 16:53:58 +00:00
|
|
|
plist := oidToPointers[pointer.Oid]
|
|
|
|
oidToPointers[pointer.Oid] = append(plist, pointer)
|
2015-05-27 19:45:18 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 16:53:58 +00:00
|
|
|
for oid := range dlwatch {
|
|
|
|
plist, ok := oidToPointers[oid]
|
2015-05-27 19:45:18 +00:00
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2015-07-23 16:53:58 +00:00
|
|
|
for _, p := range plist {
|
|
|
|
out <- p
|
2015-05-27 19:45:18 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-23 16:53:58 +00:00
|
|
|
close(out)
|
2015-05-27 19:45:18 +00:00
|
|
|
}()
|
2015-06-20 16:10:54 +00:00
|
|
|
|
2015-07-23 16:53:58 +00:00
|
|
|
}
|
2015-06-20 16:10:54 +00:00
|
|
|
processQueue := time.Now()
|
2015-07-09 18:21:49 +00:00
|
|
|
q.Wait()
|
2015-06-20 16:10:54 +00:00
|
|
|
tracerx.PerformanceSince("process queue", processQueue)
|
2015-05-14 16:33:29 +00:00
|
|
|
}
|