root/lang/python/tasktools/trunk/tasktools.py

Revision 6912, 3.8 kB (checked in by yuin, 8 months ago)

/lang/python/tasktools/trunk/tasktools.py: fix bug: when tasks created with "Standard Command" name(e.g. clean, build), could not see it in the --help-commands.

Line 
1#vim: fileencoding=utf8
2""" tasktools
3
4``tasktools`` is a collection of enhancement to Python ``distutils(setuptools)``
5that allow you to more easily create extra commands.
6
7"""
8from __future__ import with_statement
9import re, sys, imp, os
10from os.path import join, abspath, dirname
11from contextlib import contextmanager
12try:
13  from setuptools import setup
14  def _clear_commands():
15    from pkg_resources import working_set as ws
16    setattr(ws.by_key["setuptools"], "_ep_map", {})
17except ImportError,e:
18  from distutils.core import setup
19  def _clear_commands(): pass
20from distutils.core import Command
21import distutils.dist
22from distutils.dist import Distribution
23import distutils.command as scommands
24
25__version__ = "1.0.0"
26__author__  = "Yusuke Inuzuka"
27
28class _Odict(dict): keys = lambda self: sorted(dict.keys(self))
29_va = dict(global_description=None, cmd_args={}, nssep="_", load_path=[])
30_cmds = _Odict()
31_namespace = []
32_old_scommands = scommands.__all__
33
34_get_ns = lambda:_namespace and _va["nssep"].join(_namespace)+_va["nssep"] or ""
35def global_description(desc): _va["global_description"] = desc
36def cmd_args(**v): _va["cmd_args"] = v
37def load_path(*path): _va["load_path"] = _va["load_path"] + list(path)
38def use_without_standard():
39  if not use_without_standard.initialized:
40    _va["nssep"] = ":"
41    _clear_commands()
42    scommands.__all__ = []
43    distutils.dist.command_re = re.compile("[a-zA-Z0-9_:]+")
44    Distribution.common_usage = ""
45    def new_print_command_list (self, commands, header, max_length):
46      if header == "Standard commands" and not scommands.__all__ : return
47      if "extra" in header.lower() : header = "Commands"
48      return self.old_print_command_list(commands, header, max_length)
49    setattr(Distribution, "old_print_command_list", getattr(Distribution, "print_command_list"))
50    setattr(Distribution, "print_command_list", new_print_command_list)
51    use_without_standard.initialized = True
52use_without_standard.initialized = False
53
54
55def run():
56  if _va["load_path"]:
57    def tasks(path):
58      result = []
59      for root, dirs, files in os.walk(path):
60        map(result.append, (join(root, i) for i in files if i == "tasks.py"))
61      return result
62
63    idf = "tasktools_dynamic_task%d"
64    for pa in _va["load_path"]:
65      for i, path in enumerate((abspath(i) for i in tasks(pa))):
66        imp.load_source(idf%i, path)
67
68  if use_without_standard.initialized and _va["global_description"]:
69    _arg = sys.argv[1] if len(sys.argv) > 1 else ""
70    if _arg in ["--help-commands", "--help", "-h"] and _va["global_description"]:
71      print "\n".join([u"#"*60, _va["global_description"], u"#"*60])
72  _va["cmd_args"].update({"cmdclass":_cmds})
73  setup(**_va["cmd_args"])
74
75class _CommandType(type):
76  def __new__(cls, class_name, class_bases, classdict):
77    d = dict(user_options=[], finalize_options=lambda s:None)
78    d.update(classdict)
79    def _(self):
80      [setattr(self,i[0].rstrip("="),None) for i in d["user_options"]]
81    d["initialize_options"] = _
82    d["boolean_options"] = [i for i,j,k in d["user_options"] if not i.endswith("=")]
83    def _(self):
84      map(self.run_command, self.get_sub_commands())
85      return classdict["run"](self)
86    d["run"] = _
87    name = _get_ns()+class_name.lower()
88    cls = type.__new__(cls, name, class_bases + (object,), d)
89    cls.description = cls.__doc__ and cls.__doc__.strip() or ""
90    if "sub_commands" in d:
91      cls.description += "\n\tsub commands:\n"+"\n".join("\t\t"+i for i,j in d["sub_commands"])
92    if name in _old_scommands and name not in scommands.__all__: scommands.__all__.append(name)
93    if class_name != "Task" : _cmds[name] = cls
94    return cls
95class Task(Command): __metaclass__ = _CommandType
96
97@contextmanager
98def namespace(name):
99  _namespace.append(name)
100  yield _get_ns()
101  _namespace.pop()
102
103__all__ = filter(lambda i: not i.startswith("_"), locals())
Note: See TracBrowser for help on using the browser.