Commits

sodas tsai committed d5bcb69

Add soil 0.1.0

Comments (0)

Files changed (14)

+include README.md
+include MANIFEST.in
+Ground-soil
+from fabric.api import *
+
+
+@task(alias='2pypi')
+def distribute_to_pypi():
+    """
+    Distribute the eggplant to PyPI
+    """
+    local('python setup.py sdist upload')
+    local('rm -rf ground_soil.egg-info')
+    local('rm -rf dist')
+
+Fabric==1.5.1
+Jinja2==2.6
+paramiko==1.9.0
+pycrypto==2.6
+six==1.2.0
+wsgiref==0.1.2
+"""
+Copyright 2012 Dian-Je Tsai and Wantoto Inc
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+from distutils.core import setup
+from setuptools import find_packages
+from soil import __version__ as soil_version
+
+setup(
+    name='ground-soil',
+    version=soil_version,
+    author='sodas tsai',
+    author_email='sodas@sodas.tw',
+    packages=find_packages(),
+    url='https://bitbucket.org/sodastsai/ground-soil/',
+    license='Apache Software licence 2.0, see LICENCE.txt',
+    description='Django base for common use',
+    long_description=open('README.md').read(),
+    keywords='django',
+    zip_safe=False,
+    include_package_data=True,
+    install_requires=[
+        'Fabric>=1.5',
+        'Jinja2>=2.6',
+        'six>=1.2',
+    ],
+    classifiers=[
+        'Development Status :: 2 - Pre-Alpha',
+        'License :: OSI Approved :: Apache Software License',
+        'Intended Audience :: Developers',
+        'Environment :: Web Environment',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Topic :: Internet',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+    ],
+)
+
+
+__version__ = '0.1.0.4'
+VERSION = tuple(map(lambda x: int(x), __version__.split('.')))

soil/console/__init__.py

+

soil/console/color.py

+class Colors(object):
+    BOLD = 1
+    DARK = 2
+    UNDERLINE = 4
+    BLINK = 5
+    REVERSE = 7
+    CONCEALED = 8
+    ###
+    GREY = 30
+    RED = 31
+    GREEN = 32
+    YELLOW = 33
+    BLUE = 34
+    MAGENTA = 35
+    CYAN = 36
+    WHITE = 37
+    ###
+    BG_GREY = 40
+    BG_RED = 41
+    BG_GREEN = 42
+    BG_YELLOW = 43
+    BG_BLUE = 44
+    BG_MAGENTA = 45
+    BG_CYAN = 46
+    BG_WHITE = 47
+
+    @staticmethod
+    def c(text, *attributes):
+        for attribute in attributes:
+            text = '\033[%dm' % attribute + text
+        return text + '\033[0m'
+
+
+color = Colors.c

soil/datastucture/__init__.py

+from soil.datastucture.settings_dict import SettingsDict
+from soil.datastucture.modules import load_module_as_dict, dict_from_module_attr
+
+__all__ = [
+    SettingsDict.__name__,
+    load_module_as_dict.__name__,
+    dict_from_module_attr.__name__,
+]

soil/datastucture/modules.py

+import imp
+import os
+
+
+def dict_from_module_attr(module_object, key_filter=None):
+    if key_filter is None:
+        key_filter = lambda x: True
+
+    result = {}
+    for attribute in dir(module_object):
+        if key_filter(attribute):
+            result[attribute] = getattr(module_object, attribute)
+    return result
+
+
+def load_module_as_dict(path, key_filter=None):
+    if not os.path.exists(path):
+        return {}
+
+    file_name = os.path.split(os.path.splitext(path)[0])[1]
+    module_object = imp.load_source(file_name, path)
+
+    return dict_from_module_attr(module_object, key_filter)

soil/datastucture/settings_dict.py

+import types
+from six import callable
+from soil.datastucture.modules import dict_from_module_attr, load_module_as_dict
+
+
+class SettingsDict(dict):
+    def __init__(self, *setting_components, **setting_patches):
+        super(SettingsDict, self).__init__()
+
+        for setting_component in (setting_components + (setting_patches,)):
+            if isinstance(setting_component, (str, unicode)):
+                settings = load_module_as_dict(setting_component, lambda key: key.isupper())
+            elif isinstance(setting_component, types.ModuleType):
+                settings = dict_from_module_attr(setting_component, lambda key: key.isupper())
+            elif isinstance(setting_component, dict):
+                settings = dict([(key, value) for key, value in setting_component.items() if key.isupper()])
+            else:
+                continue
+
+            if settings is not None:
+                self.update(settings)
+
+    def get(self, *args):
+        if len(args) == 1:
+            return self[args[0]]
+        elif len(args) == 2:
+            try:
+                return self[args[0]]
+            except KeyError:
+                return args[1]
+        else:
+            raise TypeError('get() takes exactly 1 or 2 arguments (%s given)' % len(args))
+
+    def __getattr__(self, item):
+        return self[item]
+
+    def __getitem__(self, item):
+        if item in self:
+            target = super(SettingsDict, self).__getitem__(item)
+            return target() if callable(target) else target
+        else:
+            raise KeyError(item)

soil/fabric/__init__.py

+import ast
+import json
+from fabric.api import local, prefix
+
+
+def lsudo(command, capture=False):
+    return local('sudo %s' % command, capture=capture)
+
+
+def virtual_env(venv_path):
+    return prefix('source %s/bin/activate'%venv_path)
+
+
+def eval_arg(raw_value, is_json=False):
+    if is_json:
+        try:
+            return json.loads(raw_value)
+        except ValueError:
+            return raw_value
+    else:
+        try:
+            return ast.literal_eval(raw_value)
+        except (SyntaxError, ValueError):
+            return raw_value
+
+
+def eval_args(args):
+    return map(eval_arg, args)
+
+
+def eval_kwargs(kwargs):
+    return dict(map(lambda x: (x[0], eval_arg(x[1])), kwargs.items()))

soil/filesystem.py

+import os
+import re
+import tempfile
+from contextlib import contextmanager
+from jinja2 import FileSystemLoader, Environment
+
+
+@contextmanager
+def temporary_directory(identifier='com.wantoto.ground-soil', prefix=None, suffix=None):
+    """Generate a temporary directory with identifier, usage, and name under system's temporary root.
+    :param identifier: Bundle identifier or Java package
+    :param prefix: prefix in the name of this temporary folder
+    :param suffix: suffix in the name of this temporary folder
+    :return: This is a context manager. It returns the path of the temporary directory
+    """
+    # Get temporary room
+    os_temp_dir = os.path.join(tempfile.gettempdir(), identifier)
+    if not os.path.exists(os_temp_dir):
+        os.mkdir(os_temp_dir)
+    # Make temporary folder in room
+    path = tempfile.mkdtemp(prefix=(prefix or 'tmp'), dir=os_temp_dir, suffix=(suffix or ''))
+
+    try:
+        yield path
+    finally:
+        os.system('rm -rf %s' % path)
+
+
+def rsync(source, destination, rsync_schema=None, rsync_argument='-rlpctzD', expand_to_destination=False):
+    """Using rsync as cp or scp. Note both source and destination do not support ":" (colon)
+    :param source:
+        path of source. (local path or remote path like scp/rsync)
+    :param destination:
+        path of destination. (local path or remote path like scp/rsync)
+    :param rsync_schema:
+        rsync schema. if one of source and destination is remote path, we use ssh.
+    :param rsync_argument:
+        rsync schema. default is "-rlpctzD"
+    :return
+        composed rsync command
+    """
+    rsync = 'rsync %s' % rsync_argument
+
+    if source.startswith('localhost:'):
+        source = source.replace('localhost:', '')
+    elif source.startswith('127.0.0.1:'):
+        source = source.replace('127.0.0.1:', '')
+    if expand_to_destination and os.path.isdir(source) and not source.endswith('/'):
+        source += '/'
+
+    if destination.startswith('localhost:'):
+        destination = destination.replace('localhost:', '')
+    elif destination.startswith('127.0.0.1:'):
+        destination = destination.replace('127.0.0.1:', '')
+
+    if (':' in source or ':' in destination) and rsync_schema is None:
+        rsync_schema = 'ssh'
+
+    if rsync_schema:
+        rsync += ' -e "%s"' % rsync_schema
+
+    rsync += ' %s %s' % (source, destination)
+
+    return rsync
+
+
+def render_file(file_path, context, optimize=False):
+    """
+    Render Jinja2-compatible templates with context
+    :param file_path: The path of template file
+    :param context: The context used to render the template
+    :param optimize: Reduce empty line and strip
+    :return: Rendered result
+    """
+    templates_folder, template_filename = os.path.split(file_path)
+    env = Environment(loader=FileSystemLoader(templates_folder))
+    t = env.get_template(template_filename)
+    result = t.render(**context)
+    if optimize:
+        result = re.sub(r'( *\n){2,}', '\n\n', result.strip()) + '\n'
+    return result
+import os
+import threading
+import xmlrpclib
+from soil.console.color import Colors
+from soil.console import color
+
+
+def check_update(app_name, local_version_string, data_folder, quiet=False):
+    local_version_file_path = os.path.join(data_folder, 'pypi-version')
+
+    def check_update_core():
+        pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')
+        with open(local_version_file_path, 'w') as f:
+            try:
+                pypi_version = pypi.package_releases(app_name)[0]
+                f.write(pypi_version)
+            except (IndexError, ValueError):
+                f.write('')
+    thread1 = threading.Thread(target=check_update_core)
+    thread1.start()
+
+    if os.path.exists(local_version_file_path):
+        with open(local_version_file_path, 'r') as f:
+            try:
+                version_string = f.read()
+                pypi_version = tuple(map(lambda x: int(x), version_string.split('.')))
+                local_version = tuple(map(lambda x: int(x), local_version_string.split('.')))
+                if pypi_version > local_version:
+                    msg = '%s %s has been released, please update it.' % (app_name, version_string)
+                    print color(msg, Colors.YELLOW)
+                    print ''
+                    return 1
+                else:
+                    raise ValueError
+            except ValueError:
+                pass
+
+    if not quiet:
+        print color('Beanstalk-Stack is update to date. (version=%s)' % local_version_string, Colors.GREEN)
+    return 0