import os
import sys
import argparse
import inspect

from termcolor import cprint, colored


print_err = colored("ERR", 'red')
print_warn = colored("WARN", 'yellow')
print_ok = colored("OK", 'green')

def run():
  """Entry point"""
  task_list = ("\n".join(['- ' + t + ': ' + (inspect.getdoc(task.all[t]) or "") for t in task.all]))
  parser = argparse.ArgumentParser(epilog="Available tasks:\n\n{}".format(task_list), formatter_class=argparse.RawDescriptionHelpFormatter)
  parser.add_argument('task', nargs='*')
  args = parser.parse_args()

  if args.task:
    for t in args.task:
      tprint = colored(t, 'blue')
      if t in task.all:
        print("Running task: -> [ {} ]".format(tprint))
        if t in dependsRegister:
          for d in dependsRegister[t][1]:
            if d in task.all:
              print("Running task dependency: -> [ {} ]\n".format(colored(d, 'blue')))
              task.all[d]()
              print("."*5 + print_ok)
            else:
              print(print_warn + " Task [ {} ] not found, skipping".format(colored(d, 'blue')))

        task.all[t]()
        print("\n" + print_ok + " task \"{}\" successfully completed".format(t))

      else:
        print("{} Could not find task [ {} ] in the craftfile.".format(err, tprint))

def execfile():
  """Execute a crafty.py file using exec(). Requires no user imports"""
  filename = os.path.join(os.getcwd(), 'crafty.py')
  exec(compile(open(filename).read(), filename, 'exec'), globals(), locals())


def TaskRegistrar():
    """Keeps a dict of all tasks in the craftfile"""
    registry = {}
    def registrar(func):
        registry[func.__name__] = func
        return func  

    registrar.all = registry
    return registrar

dependsRegister = {}

def dependsRegistrar(*dargs, **dkwargs):
    """ dependency register in global dict.
       If called as a function directly, we don't get
       the function name, just the decorator arguments.
    """
    def wrap(f):
        dependsRegister[f.__name__] = [f, dargs]
        return f
    return wrap

task = TaskRegistrar()
depends = dependsRegistrar




@@ -111,11 +111,13 @@
 ed(%22
+%5B
 ERR
+%5D
 %22, '
@@ -148,12 +148,14 @@
 ed(%22
+%5B
 WARN
+%5D
 %22, '
@@ -187,10 +187,12 @@
 ed(%22
+%5B
 OK
+%5D
 %22, '
@@ -555,24 +555,46 @@
  args.task:%0A
+    run_task('setup')%0A
     for t in
@@ -615,115 +615,25 @@
     
-tprint = colored(t, 'blue')%0A      if t in task.all:%0A        print(%22Running task: -%3E %5B %7B%7D %5D%22.format(tprint))
+if t in task.all:
 %0A   
@@ -782,12 +782,23 @@
 ency
-:
  -%3E
+  %5B %7B%7D %5D for
  %5B %7B
@@ -829,16 +829,19 @@
  'blue')
+, t
 ))%0A     
@@ -888,23 +888,11 @@
 nt(%22
-.%22*5 + print_ok
+%5Cn%22
 )%0A  
@@ -1016,198 +1016,400 @@
     
-task.all%5Bt%5D()%0A        print(%22%5Cn%22 + print_ok + %22 task %5C%22%7B%7D%5C%22 successfully completed%22.format(t))%0A%0A      else:%0A        print(%22%7B%7D Could not find
+run_task(t)%0A%0A      else:%0A        print(%22%7B%7D Could not find task %5B %7B%7D %5D in the craftfile.%22.format(print_err, t))%0A  else:%0A    run_task('setup')%0A    run_task('auto')%0A%0A%0Adef run_task(name):%0A  tprint = colored(name, 'blue')%0A  if name in task.all:%0A    print(%22Running
  task
+: -%3E
  %5B %7B%7D %5D
- in the craftfile.%22.format(err, tprint
+%22.format(tprint))%0A    task.all%5Bname%5D()%0A    print(%22%5Cn%22 + print_ok + %22 task %5C%22%7B%7D%5C%22 successfully completed%5Cn%22.format(name
 ))%0A%0A

Add support for setup() and auto() tasks.