2016-04-06 19:06:34 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
2017-01-12 23:39:53 +00:00
|
|
|
"sync/atomic"
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/errors"
|
|
|
|
"github.com/git-lfs/git-lfs/lfs"
|
2017-01-12 23:39:53 +00:00
|
|
|
"github.com/git-lfs/git-lfs/locking"
|
2016-12-29 21:30:23 +00:00
|
|
|
"github.com/git-lfs/git-lfs/progress"
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/tools"
|
2016-12-12 00:20:14 +00:00
|
|
|
"github.com/git-lfs/git-lfs/tq"
|
2016-04-06 19:06:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type uploadContext struct {
|
2017-01-04 15:56:09 +00:00
|
|
|
Remote string
|
2016-04-06 19:06:34 +00:00
|
|
|
DryRun bool
|
2017-01-04 15:56:09 +00:00
|
|
|
Manifest *tq.Manifest
|
2016-07-07 16:16:13 +00:00
|
|
|
uploadedOids tools.StringSet
|
2016-12-29 21:30:23 +00:00
|
|
|
|
|
|
|
meter progress.Meter
|
|
|
|
tq *tq.TransferQueue
|
2017-01-12 23:39:53 +00:00
|
|
|
|
|
|
|
committerName string
|
|
|
|
committerEmail string
|
|
|
|
unownedLocks uint64
|
2017-01-13 21:33:51 +00:00
|
|
|
locks map[string]locking.Lock
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 15:56:09 +00:00
|
|
|
func newUploadContext(remote string, dryRun bool) *uploadContext {
|
|
|
|
cfg.CurrentRemote = remote
|
2016-12-29 21:30:23 +00:00
|
|
|
|
2017-01-11 20:59:25 +00:00
|
|
|
ctx := &uploadContext{
|
2017-01-04 15:56:09 +00:00
|
|
|
Remote: remote,
|
2017-01-04 23:10:30 +00:00
|
|
|
Manifest: getTransferManifest(),
|
2016-04-07 16:52:24 +00:00
|
|
|
DryRun: dryRun,
|
2016-07-07 16:16:13 +00:00
|
|
|
uploadedOids: tools.NewStringSet(),
|
2017-01-13 21:33:51 +00:00
|
|
|
locks: make(map[string]locking.Lock),
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
2016-12-29 21:30:23 +00:00
|
|
|
|
|
|
|
ctx.meter = buildProgressMeter(ctx.DryRun)
|
2017-01-11 20:59:25 +00:00
|
|
|
ctx.tq = newUploadQueue(ctx.Manifest, ctx.Remote, tq.WithProgress(ctx.meter), tq.DryRun(ctx.DryRun))
|
2017-01-13 18:25:21 +00:00
|
|
|
ctx.committerName, ctx.committerEmail = cfg.CurrentCommitter()
|
2016-12-29 21:30:23 +00:00
|
|
|
|
2017-01-13 21:33:51 +00:00
|
|
|
lockClient := newLockClient(remote)
|
|
|
|
locks, err := lockClient.SearchLocks(nil, 0, false)
|
|
|
|
if err != nil {
|
|
|
|
ExitWithError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, l := range locks {
|
|
|
|
ctx.locks[l.Path] = l
|
|
|
|
}
|
|
|
|
|
2016-12-29 21:30:23 +00:00
|
|
|
return ctx
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 16:52:24 +00:00
|
|
|
// AddUpload adds the given oid to the set of oids that have been uploaded in
|
|
|
|
// the current process.
|
2016-04-08 15:59:02 +00:00
|
|
|
func (c *uploadContext) SetUploaded(oid string) {
|
2016-04-07 16:52:24 +00:00
|
|
|
c.uploadedOids.Add(oid)
|
|
|
|
}
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-04-07 16:52:24 +00:00
|
|
|
// HasUploaded determines if the given oid has already been uploaded in the
|
|
|
|
// current process.
|
|
|
|
func (c *uploadContext) HasUploaded(oid string) bool {
|
|
|
|
return c.uploadedOids.Contains(oid)
|
|
|
|
}
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-12-29 21:36:28 +00:00
|
|
|
func (c *uploadContext) prepareUpload(unfiltered ...*lfs.WrappedPointer) (*tq.TransferQueue, []*lfs.WrappedPointer) {
|
2016-04-07 16:52:24 +00:00
|
|
|
numUnfiltered := len(unfiltered)
|
|
|
|
uploadables := make([]*lfs.WrappedPointer, 0, numUnfiltered)
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-10-20 18:07:40 +00:00
|
|
|
// XXX(taylor): temporary measure to fix duplicate (broken) results from
|
|
|
|
// scanner
|
|
|
|
uniqOids := tools.NewStringSet()
|
|
|
|
|
2016-04-07 16:52:24 +00:00
|
|
|
// separate out objects that _should_ be uploaded, but don't exist in
|
|
|
|
// .git/lfs/objects. Those will skipped if the server already has them.
|
|
|
|
for _, p := range unfiltered {
|
2016-10-20 18:07:40 +00:00
|
|
|
// object already uploaded in this process, or we've already
|
|
|
|
// seen this OID (see above), skip!
|
|
|
|
if uniqOids.Contains(p.Oid) || c.HasUploaded(p.Oid) {
|
2016-04-07 16:52:24 +00:00
|
|
|
continue
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
2016-10-20 18:07:40 +00:00
|
|
|
uniqOids.Add(p.Oid)
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2017-01-12 23:39:53 +00:00
|
|
|
// canUpload determines whether the current pointer "p" can be
|
|
|
|
// uploaded through the TransferQueue below. It is set to false
|
|
|
|
// only when the file is locked by someone other than the
|
|
|
|
// current committer.
|
|
|
|
var canUpload bool = true
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2017-01-13 21:33:51 +00:00
|
|
|
if lock, ok := c.locks[p.Name]; ok {
|
2017-01-13 21:00:14 +00:00
|
|
|
owned := lock.Committer.Name == c.committerName &&
|
|
|
|
lock.Committer.Email == c.committerEmail
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2017-01-12 23:39:53 +00:00
|
|
|
if owned {
|
|
|
|
Print("Consider unlocking your locked file: %s", lock.Path)
|
|
|
|
} else {
|
2017-01-13 21:00:14 +00:00
|
|
|
Print("Unable to push file %s locked by: %s", lock.Path, &lock.Committer)
|
2016-04-07 16:52:24 +00:00
|
|
|
|
2017-01-12 23:39:53 +00:00
|
|
|
atomic.AddUint64(&c.unownedLocks, 1)
|
|
|
|
canUpload = false
|
|
|
|
}
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
2016-04-07 16:52:24 +00:00
|
|
|
|
2017-01-12 23:39:53 +00:00
|
|
|
if canUpload {
|
|
|
|
// estimate in meter early (even if it's not going into
|
|
|
|
// uploadables), since we will call Skip() based on the
|
|
|
|
// results of the download check queue.
|
|
|
|
c.meter.Add(p.Size)
|
|
|
|
|
|
|
|
uploadables = append(uploadables, p)
|
|
|
|
}
|
2016-11-17 15:08:18 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 21:30:23 +00:00
|
|
|
return c.tq, uploadables
|
2016-04-06 19:06:34 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 21:36:28 +00:00
|
|
|
func uploadPointers(c *uploadContext, unfiltered ...*lfs.WrappedPointer) {
|
2016-04-07 16:52:24 +00:00
|
|
|
if c.DryRun {
|
|
|
|
for _, p := range unfiltered {
|
|
|
|
if c.HasUploaded(p.Oid) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
Print("push %s => %s", p.Oid, p.Name)
|
2016-04-08 15:59:02 +00:00
|
|
|
c.SetUploaded(p.Oid)
|
2016-04-07 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-12-29 21:36:28 +00:00
|
|
|
q, pointers := c.prepareUpload(unfiltered...)
|
2016-04-07 16:52:24 +00:00
|
|
|
for _, p := range pointers {
|
2017-01-11 20:59:25 +00:00
|
|
|
t, err := uploadTransfer(p)
|
|
|
|
if err != nil && !errors.IsCleanPointerError(err) {
|
|
|
|
ExitWithError(err)
|
2016-04-07 16:52:24 +00:00
|
|
|
}
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-12-15 20:49:04 +00:00
|
|
|
q.Add(t.Name, t.Path, t.Oid, t.Size)
|
2016-04-08 15:59:02 +00:00
|
|
|
c.SetUploaded(p.Oid)
|
2016-04-07 16:52:24 +00:00
|
|
|
}
|
2016-12-29 21:30:23 +00:00
|
|
|
}
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-12-29 21:30:23 +00:00
|
|
|
func (c *uploadContext) Await() {
|
|
|
|
c.tq.Wait()
|
2016-04-06 19:06:34 +00:00
|
|
|
|
2016-12-29 21:30:23 +00:00
|
|
|
for _, err := range c.tq.Errors() {
|
2016-08-16 18:03:37 +00:00
|
|
|
FullError(err)
|
2016-04-07 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 21:30:23 +00:00
|
|
|
if len(c.tq.Errors()) > 0 {
|
2016-04-07 16:52:24 +00:00
|
|
|
os.Exit(2)
|
|
|
|
}
|
2017-01-12 23:39:53 +00:00
|
|
|
|
|
|
|
if nl := atomic.LoadUint64(&c.unownedLocks); nl > 0 {
|
|
|
|
ExitWithError(errors.Errorf("lfs: refusing to push %d un-owned lock(s)", nl))
|
|
|
|
}
|
2016-04-07 16:52:24 +00:00
|
|
|
}
|