Permalink
Browse files

initial stuff

  • Loading branch information...
0 parents commit befd05e5092fa94b045eeb7d678b07a95c1c1317 @regadas committed Feb 3, 2013
Showing with 307 additions and 0 deletions.
  1. +36 −0 .gitignore
  2. +1 −0 MANIFEST.in
  3. 0 README.rst
  4. +4 −0 presstatic/__init__.py
  5. +47 −0 presstatic/__main__.py
  6. +24 −0 presstatic/help.py
  7. +83 −0 presstatic/storage/__init__.py
  8. +31 −0 presstatic/storage/s3.py
  9. +13 −0 presstatic/utils.py
  10. +68 −0 setup.py
@@ -0,0 +1,36 @@
+*.py[cod]
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+__pycache__
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
@@ -0,0 +1 @@
+include README.rst
No changes.
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+__author__ = 'Filipe Regadas'
+__version__ = '0.0.1'
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import argparse
+import SimpleHTTPServer
+import SocketServer
+
+from clint.textui import colored, puts, indent
+
+from presstatic import help
+from presstatic.storage import s3
+
+
+def http_server_on_dir(host, port, dir):
+ Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
+ os.chdir(dir)
+ httpd = SocketServer.TCPServer((host, int(port)), Handler)
+
+ with indent(4, quote='>>'):
+ puts(colored.green("Serving {path}".format(path=dir)))
+ puts(colored.yellow("@ {host}:{port} ".format(host=host, port=port)))
+ httpd.serve_forever()
+
+
+def main():
+ cli_parser = argparse.ArgumentParser(prog='presstatic')
+ cli_parser.add_argument('-http',
+ metavar='HOST:PORT',
+ help="creates an HTTP Server with <directory> as root dir.")
+ cli_parser.add_argument('-s3',
+ help="deploy on the specified S3 bucket.",
+ metavar='bucket')
+ cli_parser.add_argument('directory',
+ help='directory containing the static website.')
+
+ cli_args = cli_parser.parse_args()
+
+ if cli_args.http:
+ host, port = cli_args.http.split(':')
+ http_server_on_dir(host, port, cli_args.directory)
+ elif cli_args.s3:
+ s3.S3Storage(cli_args.s3).store(cli_args.directory)
+ puts(help.s3_setup(bucket=cli_args.s3))
+
+if __name__ == '__main__':
+ main()
@@ -0,0 +1,24 @@
+from string import Template
+
+s3_setup = Template("""
+Go to https://console.aws.amazon.com/s3 select your bucket and
+add a bucket policy. Here's an example:
+
+{
+ "Version":"2008-10-17",
+ "Statement":[{
+ "Sid":"AddPerm",
+ "Effect":"Allow",
+ "Principal": {
+ "AWS": "*"
+ },
+ "Action":["s3:GetObject"],
+ "Resource":["arn:aws:s3:::$bucket/*"
+ ]
+ }
+ ]
+}
+
+For more info you should see:
+http://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html
+""").substitute
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+
+import os
+import simplejson as json
+from glob import iglob
+
+from clint.textui import colored, puts, indent
+
+from presstatic.utils import hashfile
+
+
+class Manifest(object):
+
+ filename = 'manifest.json'
+
+ @classmethod
+ def read(self, path):
+ manifest_path = os.path.join(path, self.filename)
+ if not os.path.exists(manifest_path):
+ try:
+ open(manifest_path, "w").close()
+ except IOError:
+ pass
+ with open(manifest_path, 'r') as f:
+ try:
+ return json.load(f)
+ except:
+ return {}
+
+ @classmethod
+ def write(self, path, data):
+ manifest_path = os.path.join(path, self.filename)
+ with open(manifest_path, 'w') as f:
+ json.dump(data, f, indent=2)
+
+
+class Storage(object):
+
+ def _walk(self, base_path, inner_dir=''):
+ for path in iglob(base_path):
+ basename = os.path.basename(path)
+ if os.path.isdir(path):
+ for f in self._walk(base_path=os.path.join(path, '*'),
+ inner_dir=os.path.join(inner_dir, basename)):
+ yield f
+ else:
+ yield self.storage_intent(path, os.path.join(inner_dir, basename))
+
+ def store(self, base_path):
+ if os.path.isdir(base_path):
+ path = os.path.join(base_path, '*')
+ manifest_path = base_path
+ else:
+ manifest_path = os.path.dirname(base_path)
+ path = base_path
+
+ manifest_data = Manifest.read(manifest_path)
+ for f in self._walk(path):
+ if Manifest.filename in f.from_path:
+ continue
+
+ with indent(4, quote='>>'):
+ if f.hash != manifest_data.get(f.to_path, None):
+ manifest_data[f.to_path] = f.hash
+ puts(colored.yellow("uploading ... {path}".format(path=f.to_path)))
+ f.store()
+ else:
+ puts(colored.green("{path} not changed! ... skipping".format(path=f.to_path)))
+
+ Manifest.write(manifest_path, manifest_data)
+
+
+class FileStorageIntent(object):
+
+ hash_algorithm = 'md5'
+
+ def __init__(self, from_path, to_path):
+ self.from_path = from_path
+ self.to_path = to_path
+ self.hash = hashfile(from_path, self.hash_algorithm)
+
+ def store(self):
+ raise NotImplementedError()
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+import os
+
+from boto.s3.key import Key
+from boto.s3.connection import S3Connection
+
+from presstatic.storage import Storage, FileStorageIntent
+
+
+class S3FileStorageIntent(FileStorageIntent):
+
+ def __init__(self, from_path, to_path, bucket):
+ super(S3FileStorageIntent, self).__init__(from_path, to_path)
+ self.bucket = bucket
+
+ def store(self):
+ k = Key(self.bucket)
+ k.key = self.to_path
+ k.set_contents_from_filename(self.from_path)
+
+
+class S3Storage(Storage):
+
+ def __init__(self, bucket_name):
+ self.connection = S3Connection(os.environ.get('AWS_ACCESS_KEY_ID'),
+ os.environ.get('AWS_SECRET_ACCESS_KEY'))
+ self.bucket = self.connection.create_bucket(bucket_name)
+
+ def storage_intent(self, from_path, to_path):
+ return S3FileStorageIntent(from_path, to_path, self.bucket)
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+
+import hashlib
+
+
+def hashfile(path, algorithm='md5', blocksize=65536):
+ hasher = hashlib.new(algorithm)
+ with open(path, 'rb') as afile:
+ buf = afile.read(blocksize)
+ while len(buf) > 0:
+ hasher.update(buf)
+ buf = afile.read(blocksize)
+ return hasher.hexdigest()
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+
+import presstatic
+
+
+def publish():
+ """Publish to PyPi"""
+ os.system("python setup.py sdist upload")
+
+if sys.argv[-1] == "publish":
+ publish()
+ sys.exit()
+
+required = [
+ 'clint>=0.3.1',
+ 'simplejson>=3.0.7',
+ 'boto>=2.8.0',
+]
+
+setup(
+ name='presstatic',
+ version=presstatic.__version__,
+ description='Python Command-line Application Tools',
+ long_description=open('README.rst').read(),
+ author='Filipe Regadas',
+ author_email='filipe@regadas.org',
+ url='https://github.com/regadas/presstatic',
+ data_files=[
+ 'README.rst'
+ ],
+ packages=[
+ 'presstatic',
+ ],
+ entry_points={
+ 'console_scripts': [
+ 'pstatic = presstatic.__main__:main',
+ 'presstatic = presstatic.manage:main',
+ ],
+ },
+ install_requires=required,
+ license='BSD',
+ classifiers=(
+# 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Intended Audience :: Developers',
+ 'Natural Language :: English',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.1',
+ 'Programming Language :: Python :: 3.2',
+ 'License :: OSI Approved :: BSD License',
+ 'Topic :: Internet',
+ 'Topic :: Terminals',
+ 'Topic :: Utilities'
+ ),
+)

0 comments on commit befd05e

Please sign in to comment.