Package _setup :: Package make :: Module _make
[hide private]
[frames] | no frames]

Source Code for Module _setup.make._make

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2007, 2008, 2009, 2010 
  4  # Andr\xe9 Malo or his licensors, as applicable 
  5  # 
  6  # Licensed under the Apache License, Version 2.0 (the "License"); 
  7  # you may not use this file except in compliance with the License. 
  8  # You may obtain a copy of the License at 
  9  # 
 10  #     http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, software 
 13  # distributed under the License is distributed on an "AS IS" BASIS, 
 14  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 15  # See the License for the specific language governing permissions and 
 16  # limitations under the License. 
 17  """ 
 18  ================== 
 19   Simple make base 
 20  ================== 
 21   
 22  Simple make base. 
 23  """ 
 24  __author__ = u"Andr\xe9 Malo" 
 25  __docformat__ = "restructuredtext en" 
 26   
 27  import sys as _sys 
 28   
 29  from _setup import term as _term 
 30   
 31   
32 -class Failure(SystemExit):
33 """ Failure exception """
34 35
36 -def fail(reason):
37 """ Fail for a reason """ 38 raise Failure(reason)
39 40
41 -def warn(message, name=None):
42 """ Warn """ 43 _term.red("%(NAME)sWarning: %(msg)s", 44 NAME=name and "%s:" % name or '', msg=message 45 )
46 47
48 -def fatal(reason):
49 """ Fatal error, immediate stop """ 50 print >> _sys.stderr, reason 51 _sys.exit(1)
52 53
54 -class Target(object):
55 """ Target base class """ 56 NAME = None 57 DEPS = None 58 HIDDEN = False 59 60 ERROR = None 61
62 - def __init__(self, runner):
63 """ Base __init__ """ 64 self.runner = runner 65 self.init()
66
67 - def init(self):
68 """ Default init hook """ 69 pass
70
71 - def run(self):
72 """ Default run hook """ 73 pass
74
75 - def clean(self, scm=True, dist=False):
76 """ Default clean hook """ 77 pass
78 79
80 -class _Runner(object):
81 """ Runner """ 82
83 - def __init__(self, *targetscollection):
84 """ Initialization """ 85 tdict = {} 86 if not targetscollection: 87 import __main__ 88 targetscollection = [__main__] 89 90 from _setup.make import default_targets 91 if default_targets not in targetscollection: 92 targetscollection.append(default_targets) 93 94 for targets in targetscollection: 95 for value in vars(targets).values(): 96 if isinstance(value, type) and issubclass(value, Target) and \ 97 value.NAME is not None: 98 if value.NAME in tdict: 99 if issubclass(value, tdict[value.NAME]): 100 pass # override base target 101 elif issubclass(tdict[value.NAME], value): 102 continue # found base later. ignore 103 else: 104 warn('Ambigious target name', value.NAME) 105 continue 106 tdict[value.NAME] = value 107 self._tdict = tdict 108 self._itdict = {}
109
110 - def print_help(self):
111 """ Print make help """ 112 import textwrap as _textwrap 113 114 targets = self.targetinfo() 115 keys = [] 116 for key, info in targets.items(): 117 if not info['hide']: 118 keys.append(key) 119 keys.sort() 120 length = max(map(len, keys)) 121 info = [] 122 for key in keys: 123 info.append("%s%s" % ( 124 (key + " " * length)[:length + 2], 125 _textwrap.fill( 126 targets[key]['desc'].strip(), 127 subsequent_indent=" " * (length + 2) 128 ), 129 )) 130 print "Available targets:\n\n" + "\n".join(info)
131
132 - def targetinfo(self):
133 """ Extract target information """ 134 result = {} 135 for name, cls in self._tdict.items(): 136 result[name] = { 137 'desc': cls.__doc__ or "no description", 138 'hide': cls.HIDDEN, 139 'deps': cls.DEPS or (), 140 } 141 return result
142
143 - def _topleveltargets(self):
144 """ Find all top level targets """ 145 rev = {} # key is a dep of [values] 146 all_ = self.targetinfo() 147 for target, info in all_.items(): 148 for dep in info['deps']: 149 if dep not in all_: 150 fatal("Unknown target '%s' (dep of %s) -> exit" % ( 151 dep, target 152 )) 153 rev.setdefault(dep, []).append(target) 154 return [target for target, info in rev.items() if not info]
155
156 - def _run(self, target, seen=None):
157 """ Run a target """ 158 if target.DEPS: 159 self(*target.DEPS, **{'seen': seen}) 160 161 if not target.HIDDEN: 162 _term.yellow(">>> %(name)s", name=target.NAME) 163 164 try: 165 result = target.run() 166 except KeyboardInterrupt: 167 result, target.ERROR = False, "^C -> exit" 168 except Failure, e: 169 result, target.ERROR = False, "%s: %s" % (target.NAME, e) 170 except (SystemExit, MemoryError): 171 raise 172 except: 173 import traceback 174 target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join( 175 traceback.format_exception(*_sys.exc_info()) 176 )) 177 result = False 178 else: 179 if result is None: 180 result = True 181 return result
182
183 - def _clean(self, target, scm, dist, seen=None):
184 """ Run a target """ 185 if target.DEPS: 186 self.run_clean( 187 *target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen} 188 ) 189 190 try: 191 result = target.clean(scm, dist) 192 except KeyboardInterrupt: 193 result, target.ERROR = False, "^C -> exit" 194 except Failure, e: 195 result, target.ERROR = False, "%s: %s" % (target.NAME, e) 196 except (SystemExit, MemoryError): 197 raise 198 except: 199 import traceback 200 target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join( 201 traceback.format_exception(*_sys.exc_info()) 202 )) 203 result = False 204 else: 205 if result is None: 206 result = True 207 return result
208
209 - def _make_init(self, seen):
210 """ Make init mapper """ 211 def init(target): 212 """ Return initialized target """ 213 if target not in seen: 214 try: 215 seen[target] = self._tdict[target](self) 216 except KeyError: 217 fatal("Unknown target '%s' -> exit" % target) 218 else: 219 seen[target] = None 220 return seen[target]
221 return init
222
223 - def run_clean(self, *targets, **kwargs):
224 """ Run targets """ 225 def pop(name, default=None): 226 """ Pop """ 227 if name in kwargs: 228 value = kwargs[name] 229 del kwargs[name] 230 if value is None: 231 return default 232 return value 233 else: 234 return default
235 seen = pop('seen', {}) 236 scm = pop('scm', True) 237 dist = pop('dist', False) 238 if kwargs: 239 raise TypeError('Unknown keyword parameters') 240 241 if not targets: 242 top_targets = self._topleveltargets() 243 targets = self.targetinfo() 244 for item in top_targets: 245 del targets[item] 246 targets = targets.keys() 247 targets.sort() 248 top_targets.sort() 249 targets = top_targets + targets 250 251 init = self._make_init(seen) 252 for name in targets: 253 target = init(name) 254 if target is not None: 255 if not self._clean(target, scm=scm, dist=dist, seen=seen): 256 msg = target.ERROR 257 if msg is None: 258 msg = "Clean target %s returned error -> exit" % name 259 fatal(msg) 260
261 - def __call__(self, *targets, **kwargs):
262 """ Run targets """ 263 if 'seen' in kwargs: 264 seen = kwargs['seen'] 265 del kwargs['seen'] 266 else: 267 seen = None 268 if seen is None: 269 seen = self._itdict 270 if kwargs: 271 raise TypeError('Unknown keyword parameters') 272 273 init = self._make_init(seen) 274 for name in targets: 275 target = init(name) 276 if target is not None: 277 if not self._run(target, seen): 278 msg = target.ERROR 279 if msg is None: 280 msg = "Target %s returned error -> exit" % name 281 fatal(msg)
282 283
284 -def main(*args, **kwargs):
285 """ 286 main(argv=None, *args, name=None) 287 288 Main start point. This function parses the command line and executes the 289 targets given through `argv`. If there are no targets given, a help output 290 is generated. 291 292 :Parameters: 293 `argv` : sequence 294 Command line arguments. If omitted or ``None``, they are picked from 295 ``sys.argv``. 296 297 `args` : ``tuple`` 298 The list of modules with targets. If omitted, ``__main__`` 299 is imported and treated as target module. Additionally the mechanism 300 always adds the `_setup.make` module (this one) to the list in order 301 to grab some default targets. 302 303 `name` : ``str`` 304 Name of the executing module. If omitted or ``None``, ``'__main__'`` 305 is assumed. If the final name is not ``'__main__'``, the function 306 returns immediately. 307 """ 308 try: 309 name = kwargs['name'] 310 except KeyError: 311 name = '__main__' 312 else: 313 del kwargs['name'] 314 if name is None: 315 name = '__main__' 316 317 try: 318 argv = kwargs['argv'] 319 except KeyError: 320 if not args: 321 args = (None,) 322 else: 323 del kwargs['argv'] 324 args = (argv,) + args 325 326 if kwargs: 327 raise TypeError("Unrecognized keyword arguments for main()") 328 329 if name == '__main__': 330 argv, args = args[0], args[1:] 331 if argv is None: 332 argv = _sys.argv[1:] 333 334 runner = _Runner(*args) 335 if argv: 336 runner(*argv) 337 else: 338 runner.print_help()
339