Add sync command

## Problem

Syncing S3 buckets is long, it's hard to know how long it will take to sync a bucket, or what fails when it fails, what succeeds otherwise. Also, S3 sometimes has some crazy moments and errors on all requests. 
Which means this command should be pretty resilient to errors (it is).


## Solution

Reading a list of S3 keys from a file, we can track how far in the process we are and when it should be done. Saving the result to other files, we can track which key succeeded in syncing, which key failed to sync.

The work of syncing can also be distributed over many workers, since we can slice an S3 keys listing over many subfiles.

Reading and syncing at most `n` keys at a time means that the long process of syncing all the keys never use more than`O(n)` memory, which prevents running OOMs and swapping and pains.

## Implementation

Command `sync` reads the keys from a file and sync them from a __source__ bucket to a __destination__ bucket. Because S3 often errors, we retry errors on keys using a [triangular][1]* backoff, if they gave _retryable_ errors:

* Network errors
* S3 errors such as _SlowDown_, _Timeout_, _ServiceUnavailable_ and such.

By default, we retry 10 times. This means if 50% of S3 calls give retryable errors, the probability of missing out on an error that could have succeeded is 0.5**10 ~ 0.000975, or 9.75 times out of 10'000. Retrying 10 times will results in a short enough backoff to be worth it, wasting at most [55s][2] on a key that will never succeed to sync.

While 50% error rate seems big, I've observed (with previous version of this tool) spurious error periods from S3 that seem to resolve naturally after retrying a bit. I haven't observed such periods lasting more than 30s.

The sync command provides pluggable method for how the sync is to be done:

- PutCopy
- FetchPut intra AWS
- FetchPut, AWS -> GCS

Right now the only implementation is for PutCopy. The buckets can possibly be created with different AWS credentials, in which case PutCopy is impossible.

Test coverage is:

```bash
$ go test . -cover
ok  	github.com/Shopify/brigade/cmd/sync	5.482s	coverage: 87.8% of statements
```

Missing from the coverage are abort conditions and non-s3 errors. The non-s3 errors are usually network errors that are handled the same way as retryable errors: this class of error is tested.

It looks like this:

```insert pretty gif here```

r: @fbogsany, @camilo, @bouk, @boourns   
cc: @Shopify/webscale

`*` triangular backoff: I didn't actually know that was the name of the serie, wikipedia told me.
[1]: https://en.wikipedia.org/wiki/1_%2B_2_%2B_3_%2B_4_%2B_%E2%8B%AF
[2]: http://www.wolframalpha.com/input/?i=sum%281+to+10%29
Honestly I just don't like how go-fmt aligns cascading `if`. That's why I use a switch here. I find that this looks noisy:

```go
// Classify S3 errors that should be retried.
func shouldRetry(err error) bool {
	return s3.IsS3Error(err, s3.ErrExpiredToken) ||
		s3.IsS3Error(err, s3.ErrIncompleteBody) ||
		s3.IsS3Error(err, s3.ErrInternalError) ||
		s3.IsS3Error(err, s3.ErrInvalidBucketState) ||
		s3.IsS3Error(err, s3.ErrInvalidObjectState) ||
		s3.IsS3Error(err, s3.ErrInvalidPart) ||
		s3.IsS3Error(err, s3.ErrInvalidPartOrder) ||
		s3.IsS3Error(err, s3.ErrOperationAborted) ||
		s3.IsS3Error(err, s3.ErrPermanentRedirect) ||
		s3.IsS3Error(err, s3.ErrPreconditionFailed) ||
		s3.IsS3Error(err, s3.ErrRedirect) ||
		s3.IsS3Error(err, s3.ErrRequestTimeout) ||
		s3.IsS3Error(err, s3.ErrRequestTimeTooSkewed) ||
		s3.IsS3Error(err, s3.ErrServiceUnavailable) ||
		s3.IsS3Error(err, s3.ErrTemporaryRedirect) ||
		s3.IsS3Error(err, s3.ErrTokenRefreshRequired) ||
		s3.IsS3Error(err, s3.ErrUnexpectedContent) ||
		s3.IsS3Error(err, s3.ErrSlowDown)
}

// Classify S3 errors that require aborting the whole sync process.
func shouldAbort(err error) bool {
	return s3.IsS3Error(err, s3.ErrAccessDenied) ||
		s3.IsS3Error(err, s3.ErrAccountProblem) ||
		s3.IsS3Error(err, s3.ErrCredentialsNotSupported) ||
		s3.IsS3Error(err, s3.ErrInvalidAccessKeyID) ||
		s3.IsS3Error(err, s3.ErrInvalidBucketName) ||
		s3.IsS3Error(err, s3.ErrNoSuchBucket)
}

```

But it's just a slight preference, and if you prefer that way, I'll be happy to comply. =)