#!/usr/bin/env python

import os
import time

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


class S3Sync(object):
    def __init__(self, bucket):
        self.conn = S3Connection(*self.get_auth())
        self.bucket = self.conn.get_bucket(bucket)

    def get_auth(self):
        fn = os.path.expanduser("~/.s3cfg")
        if not os.path.exists(fn):
            raise Exception("s3cmd config file not found")

        key = password = None

        for line in file(fn, "r"):
            parts = line.split("=", 1)
            if len(parts) != 2:
                continue

            k = parts[0].strip()
            v = parts[1].strip()

            if k == "access_key":
                key = v
            elif k == "secret_key":
                password = v

        return key, password

    def list_files(self):
        """Lists existing files as tuples (name, last_modified)."""
        for key in self.bucket.list():
            yield key.name, key.last_modified

    def update_from_folder(self, folder):
        """Updates remote files with a local folder."""
        files = {}
        for name, date in self.list_files():
            files[name] = {"rd": date}

        folder = folder.rstrip(os.path.sep)

        for _path, _folders, _files in os.walk(folder):
            for fn in _files:
                fpath = os.path.join(_path, fn)
                fname = fpath[len(folder)+1:]

                if fname.startswith("."):
                    continue

                fdate = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime(os.stat(fpath).st_mtime))

                if fname not in files:
                    files[fname] = {}
                files[fname]["ld"] = fdate

        for k, v in sorted(files.items()):
            key = Key(self.bucket, k)
            lpath = os.path.join(folder, k)

            if "ld" not in v:
                print "-", k
                key.delete()
            elif "rd" not in v:
                print "+", k
                key.set_contents_from_filename(lpath, replace=True)
                key.make_public()
            elif v["ld"] > v["rd"]:
                print "*", k
                key.set_contents_from_filename(lpath, replace=True)
                key.make_public()

    def move_to(self, path):
        for key in self.bucket.list():
            filename = os.path.join(path, key.name)

            dirname = os.path.dirname(filename)
            if not os.path.exists(dirname):
                os.makedirs(dirname)

            print >> sys.stderr, "Downloading %s (%u)" % (filename, key.size)
            with file(filename, "wb") as f:
                key.get_file(f)
            key.delete()


S3Sync("files.umonkey.net").update_from_folder(".")
