Skip to content

Commit

Permalink
initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
olt committed Jul 29, 2009
0 parents commit 1eb0913
Show file tree
Hide file tree
Showing 13 changed files with 2,095 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .hgignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.zip
.pyc
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License

Copyright (c) <2009> Oliver Tonnhofer <olt@omniscale.de>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
6 changes: 6 additions & 0 deletions scriptine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from scriptine.path import path
from scriptine.command import parse_and_run_commands, global_options

__version__ = '0.0.6'

__all__ = ['path', 'parse_and_run_commands']
239 changes: 239 additions & 0 deletions scriptine/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import sys
import types
import inspect
import re
import optparse
from textwrap import wrap

from scriptine import misc

_global_options = None

def global_options():
global _global_options
return _global_options

def parse_and_run_function(function, args=None, command_name=None,
global_options=None, add_dry_run_option=True):
#TODO refactor me, I'm too long
if args is None:
args = sys.argv

required_args, optional_args = inspect_args(function)

func_doc = function.__doc__ or ''
params_doc = parse_rst_params(func_doc)

usage = 'usage: %prog '
if command_name is not None:
usage += command_name + ' '
usage += '[options] ' + ' '.join(required_args)

if func_doc:
usage += '\n\n' + '\n'.join(wrap(func_doc.strip().split('\n')[0], 60))

if set(required_args).intersection(params_doc.keys()):
usage += '\n\nRequired arguments:'
for arg in required_args:
usage += '\n%s' % arg
if arg in params_doc:
usage += ': %s' % params_doc[arg]

add_help_option = True
if getattr(function, 'no_help', False):
add_help_option = False

fetch_all = None
if hasattr(function, 'fetch_all'):
fetch_all = function.fetch_all
optional_args = [(arg, default) for arg, default in optional_args
if arg != fetch_all]

parser = optparse.OptionParser
if getattr(function, 'non_strict', False):
parser = NonStrictOptionParser

parser = parser(usage, add_help_option=add_help_option)

for arg_name, default in optional_args:
options = {}
if isinstance(default, bool):
if default:
options = {'action': 'store_false'}
else:
options = {'action': 'store_true'}
elif isinstance(default, int):
options = {'type': 'int'}
elif isinstance(default, float):
options = {'type': 'float'}
parser.add_option('--' + arg_name.replace('_', '-'),
help=params_doc.get(arg_name, None),
dest=arg_name, default=default, metavar=default, **options)

if add_dry_run_option:
parser.add_option('--dry-run', '-n', dest='dry_run', default=False,
action='store_true', help='don\'t actually do anything')

if global_options:
if '--help' in args or '-h' in args:
group = optparse.OptionGroup(parser, 'Global options')
group.add_options(global_options)
parser.add_option_group(group)
else:
args = parse_global_options(args, global_options)

(options, args) = parser.parse_args(args)

if add_dry_run_option and options.dry_run:
misc.options.dry = True

args = args[1:]
if len(args) < len(required_args):
parser.error('number of arguments does not match')
kw = {}
for arg_name, _default in optional_args:
kw[arg_name] = getattr(options, arg_name)

if fetch_all:
kw[fetch_all] = args[len(required_args):]
return function(*args[:len(required_args)], **kw)

def no_help(cmd):
cmd.no_help = True
return cmd

def non_strict(cmd):
cmd.non_strict = True
return cmd

def fetch_all(arg_name):
def _fetch_all(cmd):
cmd.fetch_all = arg_name
return cmd
return _fetch_all

def parse_global_options(args, global_options):
parser = NonStrictOptionParser(add_help_option=False)
parser.add_options(global_options)
(options, args) = parser.parse_args(args)
global _global_options
_global_options = options
return args

class NonStrictOptionParser(optparse.OptionParser):
def _process_args(self, largs, rargs, values):
while rargs:
arg = rargs[0]
# We handle bare "--" explicitly, and bare "-" is handled by the
# standard arg handler since the short arg case ensures that the
# len of the opt string is greater than 1.
try:
if arg == "--":
del rargs[0]
return
elif arg[0:2] == "--":
# process a single long option (possibly with value(s))
self._process_long_opt(rargs, values)
elif arg[:1] == "-" and len(arg) > 1:
# process a cluster of short options (possibly with
# value(s) for the last one only)
self._process_short_opts(rargs, values)
elif self.allow_interspersed_args:
largs.append(arg)
del rargs[0]
else:
return
except optparse.BadOptionError:
largs.append(arg)

def inspect_args(function):
(args, _varargs, _varkw, defaults) = inspect.getargspec(function)

optional_args = []
if defaults is not None:
for default in defaults[::-1]:
optional_args.append((args.pop(), default))
optional_args.reverse()
return args, optional_args

def parse_and_run_commands(namespace=None, args=None, global_options=None,
add_dry_run_option=True, command_suffix='_command'):
if namespace is None:
namespace = sys._getframe(1).f_locals
elif type(namespace) is types.ModuleType:
namespace = namespace.__dict__

if args is None:
args = sys.argv

if len(args) < 2 or args[1] in ('-h', '--help'):
print_help(namespace, command_suffix, global_options)
return

command_name = args.pop(1).replace('-', '_')
function = namespace[command_name + command_suffix]
parse_and_run_function(function, args, command_name, global_options,
add_dry_run_option=add_dry_run_option)

run = parse_and_run_commands

def print_help(namespace, command_suffix, global_options):
commands = []
for func_name, func in namespace.iteritems():
if func_name.endswith(command_suffix):
command_name = func_name[:-len(command_suffix)].replace('_', '-')
commands.append((command_name, func.__doc__))

if not commands:
print 'no commands found in', sys.argv[0]
return

usage = 'usage: %prog command [options]'
parser = optparse.OptionParser(usage)
if global_options:
parser.add_options(global_options)
parser.print_help()

print '\nCommands:'
cmd_len = max(len(cmd) for cmd, _ in commands)
for cmd, doc in commands:
if doc is not None:
doc = doc.strip().split('\n')[0]
else:
doc = ''
print (' %-' + str(cmd_len) + 's %s') % (cmd, doc)

def parse_rst_params(doc):
"""
Parse a reStructuredText docstring and return a dictionary
with parameter names and descriptions.
>>> doc = '''
... :param foo: foo parameter
... foo parameter
...
... :param bar: bar parameter
... :param baz: baz parameter
... baz parameter
... baz parameter
... Some text.
... '''
>>> params = parse_rst_params(doc)
>>> params['foo']
'foo parameter foo parameter'
>>> params['bar']
'bar parameter'
>>> params['baz']
'baz parameter baz parameter baz parameter'
"""
param_re = re.compile(r"""^([ \t]*):param\
(?P<param>\w+):\
(?P<body>.*\n(\1[ \t]+\w.*\n)*)""",
re.MULTILINE|re.VERBOSE)
params = {}
for match in param_re.finditer(doc):
parts = match.groupdict()
body_lines = parts['body'].strip().split('\n')
params[parts['param']] = ' '.join(s.strip() for s in body_lines)

return params
36 changes: 36 additions & 0 deletions scriptine/files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from scriptine import path, log
import tarfile

class file_collection(object):
def __init__(self):
self.files = []
self.base = path('.')

def include(self, patterns, recursive=False):
if isinstance(patterns, basestring): patterns = (patterns,)
for pattern in patterns:
if recursive:
for dirname in self.base.dirs(pattern):
self.files.extend((f for f in dirname.walk()))
else:
self.files.extend((f for f in self.base.listdir(pattern)))

def exclude(self, patterns):
if isinstance(patterns, basestring): patterns = (patterns,)
for pattern in patterns:
self.files = [f for f in self.files if not f.fnmatch(pattern)]

def __iter__(self):
return iter(self.files)

def tar(self, dest, archive_base=None):
dest = path(dest)
if archive_base is None:
archive_base = path(self.dest.basename()).splitext()[0]
tar = tarfile.open(dest, 'w:gz')

for f in self:
log.info('adding %s', f)
tar.add(f, arcname=archive_base/f, recursive=False)
tar.close()

49 changes: 49 additions & 0 deletions scriptine/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import sys

__all__ = ['warn', 'error', 'debug', 'info']

L_DEBUG = -1
L_INFO = 0
L_MARK = 1
L_WARN = 2
L_ERROR = 3

_level = 0

def inc_log_level():
global _level
_level -= 1

def dec_log_level():
global _level
_level += 1

def log(msg, *args):
print msg % args
sys.stdout.flush()

def mark(msg, *args):
if _level <= L_MARK:
log('---> ' + msg, *args)

def info(msg, *args):
if _level <= L_INFO:
log('INFO: ' + msg, *args)

def warn(msg, *args):
if _level <= L_WARN:
log('WARN: ' + msg, *args)

def error(msg, *args):
if _level <= L_ERROR:
log('ERROR: ' + msg, *args)

def fatal(msg, *args):
log('ERROR: ' + msg, *args)
log('aborting script...')
sys.exit(1)


def debug(msg, *args):
if _level <= L_DEBUG:
log('DEBUG: ' + msg, *args)
24 changes: 24 additions & 0 deletions scriptine/meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import scriptine
from scriptine import path

def version_command():
print 'scriptine ver.%s' % scriptine.__version__

def zipdist_command():
print 'creating scriptine.zip'
if __file__ is None:
print 'ERROR: creating zipdist from zipped scriptine is not supported.'
return 1
from zipfile import ZipFile, ZIP_DEFLATED
zipfile = ZipFile('scriptine.zip', 'w', compression=ZIP_DEFLATED)
scripyt_src = path(__file__).dirname()
for filename in path(scripyt_src).files('*.py'):
arcname = path().joinpath(*filename.splitall()[-2:])
zipfile.write(filename, arcname)
zipfile.close()

if __name__ == '__main__':
import sys
if sys.argv[0] is None:
sys.argv[0] = 'python -m scriptine.meta'
scriptine.parse_and_run_commands(globals())
Loading

0 comments on commit 1eb0913

Please sign in to comment.