#!/usr/bin/env python
"""Uploads the given files on the command line to S3. Much like the s3put command which is included with Boto, but
   allows for uploading of multiple files simultaneously, as well as uploading to a path within a bucket, instead
   of only the bucket root."""
import argparse
import glob
import os
import sys

from boto.s3.bucket import Bucket
from boto.s3.connection import S3Connection
from boto.s3.key import Key

from boto_utils.common import get_parser, parse_aws_credentials_file

if __name__ == '__main__':
    parser = get_parser(description='Upload files to Amazon S3')
    parser.add_argument('-b', '--bucket', metavar='BUCKET', dest='bucket', required=True,
                        help='Store files in BUCKET')
    parser.add_argument('source', metavar='PATH', nargs='+',
                        help='Files to be uploaded (directories too if -r is specified)')
    parser.add_argument('-d', '--dest', metavar='PATH', nargs='?',
                        help='Path inside the bucket to upload the files')
    parser.add_argument('-r', '--recursive', action='store_true',
                        help='If a directory is passed, recursively upload the entire contents')
    # --replace and --fail-if-exists are mutually exclusive
    replace_group = parser.add_mutually_exclusive_group(required=False)
    replace_group.add_argument('--replace', default=False, action='store_true',
                               help='Replace existing files')
    replace_group.add_argument('--fail-if-exists', dest='fail_if_exists', default=False, action='store_true',
                               help='Fail with an error if any of the files already exist at the destination (by ' \
                               'default a warning will be printed, but the upload won\'t be stopped)')
    
    args = parser.parse_args()
    credentials = parse_aws_credentials_file(args.credentials_file)
    s3 = S3Connection(
        debug=(2 if args.verbose else 0),
        **credentials
    )
    bucket = Bucket(connection=s3, name=args.bucket)
    
    # Build a list of the files to be uploaded and the paths where they should be uploaded
    source = []
    for p in args.source:
        source.extend(glob.glob(p))
    
    files = []
    for f in source:
        if os.path.isdir(f):
            if not args.recursive:
                parser.error('%r is a directory. To upload directories recursively, specify -r' % f)
            # Walk the directory to get all the files to be uploaded
            for dirpath, dirnames, filenames in os.walk(f):
                for filename in filenames:
                    filename = os.path.join(dirpath, filename)
                    files.append((filename, os.path.relpath(filename, f)))
        else:
            assert os.path.exists(f), '%s does not exist' % f
            files.append((f, os.path.basename(f)))
    
    for f, path in files:
        with open(f, 'rb') as f:
            dest = os.path.join((args.dest or ''), path)
            # If we're not allowed to replace, check for existence first
            print dest
            if (not args.replace) and bucket.lookup(dest):
                if args.fail_if_exists:
                    print 'File already exists at destination; exiting since you specified --fail-if-exists'
                    sys.exit(2)
                else:
                    print 'File already exists at destination; skipping. specify --replace to overwrite'
                    continue
            # Now, do the actual uploading
            key = Key(bucket=bucket, name=dest)
            key.set_contents_from_file(f, replace=args.replace)
            print 'Successfully uploaded %s to %s:%s' % (f.name, args.bucket, dest)
    
    sys.exit(0)
