Remove the TaskBase class hierarchy level

This commit is contained in:
Thomas Nagy 2017-02-11 15:04:25 +01:00
parent 62fe305d04
commit 5ac8e882e0
No known key found for this signature in database
GPG Key ID: 49B4C67C05277AAA
13 changed files with 83 additions and 142 deletions

View File

@ -39,16 +39,16 @@ def dump(bld):
bld.targets = []
# store the command executed
old_exec = Task.TaskBase.exec_command
old_exec = Task.Task.exec_command
def exec_command(self, *k, **kw):
ret = old_exec(self, *k, **kw)
self.command_executed = k[0]
self.path = kw['cwd'] or self.generator.bld.cwd
return ret
Task.TaskBase.exec_command = exec_command
Task.Task.exec_command = exec_command
# perform a fake build, and accumulate the makefile bits
old_process = Task.TaskBase.process
old_process = Task.Task.process
def process(self):
old_process(self)
@ -67,7 +67,7 @@ def dump(bld):
else:
bld.commands.append(' '.join(lst))
bld.commands.append('\tcd %s && %s' % (self.path, self.command_executed))
Task.TaskBase.process = process
Task.Task.process = process
# write the makefile after the build is complete
def output_makefile(self):

View File

@ -95,9 +95,9 @@ def process(self):
except Exception, e:
print type(e), e
Task.TaskBase.process_bound_maxjobs = Task.TaskBase.process
Task.Task.process_bound_maxjobs = Task.Task.process
Task.Task.process = process
Task.TaskBase.lock_maxjob = lock_maxjob
Task.TaskBase.release_maxjob = release_maxjob
Task.TaskBase.wait_maxjob = wait_maxjob
Task.Task.lock_maxjob = lock_maxjob
Task.Task.release_maxjob = release_maxjob
Task.Task.wait_maxjob = wait_maxjob

View File

@ -65,7 +65,7 @@ def build_all_at_once(ctx):
f(self)
sem.release()
return f2
Task.TaskBase.process = with_sem(Task.TaskBase.process)
Task.Task.process = with_sem(Task.Task.process)
threads = []
for var in ctx.all_envs:

View File

@ -587,7 +587,7 @@ class BuildContext(Context.Context):
def add_to_group(self, tgen, group=None):
"""Adds a task or a task generator to the build; there is no attempt to remove it if it was already added."""
assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.TaskBase))
assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.Task))
tgen.bld = self
self.get_group(group).append(tgen)
@ -761,7 +761,7 @@ class BuildContext(Context.Context):
Returns all task instances for the build group at position idx,
used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
:rtype: list of :py:class:`waflib.Task.TaskBase`
:rtype: list of :py:class:`waflib.Task.Task`
"""
tasks = []
for tg in self.groups[idx]:
@ -776,7 +776,7 @@ class BuildContext(Context.Context):
Creates a Python generator object that returns lists of tasks that may be processed in parallel.
:return: tasks which can be executed immediatly
:rtype: generator returning lists of :py:class:`waflib.Task.TaskBase`
:rtype: generator returning lists of :py:class:`waflib.Task.Task`
"""
self.cur = 0
@ -1366,7 +1366,7 @@ class StepContext(BuildContext):
for pat in self.files.split(','):
matcher = self.get_matcher(pat)
for tg in g:
if isinstance(tg, Task.TaskBase):
if isinstance(tg, Task.Task):
lst = [tg]
else:
lst = tg.tasks

View File

@ -49,7 +49,7 @@ class Spawner(Utils.threading.Thread):
"""
Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and
spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each
:py:class:`waflib.Task.TaskBase` instance.
:py:class:`waflib.Task.Task` instance.
"""
def __init__(self, master):
Utils.threading.Thread.__init__(self)
@ -103,16 +103,16 @@ class Parallel(object):
"""
self.outstanding = Utils.deque()
"""List of :py:class:`waflib.Task.TaskBase` that may be ready to be executed"""
"""List of :py:class:`waflib.Task.Task` that may be ready to be executed"""
self.frozen = Utils.deque()
"""List of :py:class:`waflib.Task.TaskBase` that are not ready yet"""
"""List of :py:class:`waflib.Task.Task` that are not ready yet"""
self.ready = Queue(0)
"""List of :py:class:`waflib.Task.TaskBase` ready to be executed by consumers"""
"""List of :py:class:`waflib.Task.Task` ready to be executed by consumers"""
self.out = Queue(0)
"""List of :py:class:`waflib.Task.TaskBase` returned by the task consumers"""
"""List of :py:class:`waflib.Task.Task` returned by the task consumers"""
self.count = 0
"""Amount of tasks that may be processed by :py:class:`waflib.Runner.TaskConsumer`"""
@ -143,7 +143,7 @@ class Parallel(object):
"""
Obtains the next Task instance to run
:rtype: :py:class:`waflib.Task.TaskBase`
:rtype: :py:class:`waflib.Task.Task`
"""
if not self.outstanding:
return None
@ -155,7 +155,7 @@ class Parallel(object):
The order is scrambled so as to consume as many tasks in parallel as possible.
:param tsk: task instance
:type tsk: :py:class:`waflib.Task.TaskBase`
:type tsk: :py:class:`waflib.Task.Task`
"""
if random.randint(0, 1):
self.frozen.appendleft(tsk)
@ -200,11 +200,11 @@ class Parallel(object):
def add_more_tasks(self, tsk):
"""
If a task provides :py:attr:`waflib.Task.TaskBase.more_tasks`, then the tasks contained
If a task provides :py:attr:`waflib.Task.Task.more_tasks`, then the tasks contained
in that list are added to the current build and will be processed before the next build group.
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
:type tsk: :py:attr:`waflib.Task.Task`
"""
if getattr(tsk, 'more_tasks', None):
self.outstanding.extend(tsk.more_tasks)
@ -215,7 +215,7 @@ class Parallel(object):
Waits for a Task that task consumers add to :py:attr:`waflib.Runner.Parallel.out` after execution.
Adds more Tasks if necessary through :py:attr:`waflib.Runner.Parallel.add_more_tasks`.
:rtype: :py:attr:`waflib.Task.TaskBase`
:rtype: :py:attr:`waflib.Task.Task`
"""
tsk = self.out.get()
if not self.stop:
@ -229,7 +229,7 @@ class Parallel(object):
Enqueue a Task to :py:attr:`waflib.Runner.Parallel.ready` so that consumers can run them.
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
:type tsk: :py:attr:`waflib.Task.Task`
"""
self.ready.put(tsk)
@ -253,7 +253,7 @@ class Parallel(object):
$ waf build -k
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
:type tsk: :py:attr:`waflib.Task.Task`
"""
if hasattr(tsk, 'scan') and hasattr(tsk, 'uid'):
# TODO waf 2.0 - this breaks encapsulation

View File

@ -92,7 +92,7 @@ class store_task_type(type):
super(store_task_type, cls).__init__(name, bases, dict)
name = cls.__name__
if name != 'evil' and name != 'TaskBase':
if name != 'evil' and name != 'Task':
global classes
if getattr(cls, 'run_str', None):
# if a string is provided, convert it to a method
@ -114,20 +114,21 @@ class store_task_type(type):
evil = store_task_type('evil', (object,), {})
"Base class provided to avoid writing a metaclass, so the code can run in python 2.6 and 3.x unmodified"
class TaskBase(evil):
class Task(evil):
"""
Base class for all Waf tasks, which should be seen as an interface.
For illustration purposes, instances of this class will execute the attribute
'fun' in :py:meth:`waflib.Task.TaskBase.run`. When in doubt, create
subclasses of :py:class:`waflib.Task.Task` instead.
Subclasses must override these methods:
#. __str__: string to display to the user
#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
#. run: what to do to execute the task
#. post_run: what to do after the task has been executed
This class deals with the filesystem (:py:class:`waflib.Node.Node`). The method :py:class:`waflib.Task.Task.runnable_status`
uses a hash value (from :py:class:`waflib.Task.Task.signature`) which is persistent from build to build. When the value changes,
the task has to be executed. The method :py:class:`waflib.Task.Task.post_run` will assign the task signature to the output
nodes (if present).
"""
vars = []
"""ConfigSet variables that should trigger a rebuild (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
always_run = False
"""Specify whether task instances must always be executed or not (class attribute)"""
shell = False
"""Execute the command with the shell (class attribute)"""
color = 'GREEN'
"""Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""
@ -152,32 +153,29 @@ class TaskBase(evil):
This may be useful for certain extensions but it can a lot of memory.
"""
__slots__ = ('hasrun', 'generator')
__slots__ = ('hasrun', 'generator', 'env', 'inputs', 'outputs', 'dep_nodes', 'run_after')
def __init__(self, *k, **kw):
"""
The base task class requires a task generator (set to *self* if missing)
"""
self.hasrun = NOT_RUN
try:
self.generator = kw['generator']
except KeyError:
self.generator = self
def __repr__(self):
return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))
self.env = kw['env']
""":py:class:`waflib.ConfigSet.ConfigSet` object (make sure to provide one)"""
def __str__(self):
"String to display to the user"
if hasattr(self, 'fun'):
return self.fun.__name__
return self.__class__.__name__
self.inputs = []
"""List of input nodes, which represent the files used by the task instance"""
def keyword(self):
"Display keyword used to prettify the console outputs"
if hasattr(self, 'fun'):
return 'Function'
return 'Processing'
self.outputs = []
"""List of output nodes, which represent the files created by the task instance"""
self.dep_nodes = []
"""List of additional nodes to depend on"""
self.run_after = set()
"""Set of tasks that must be executed before this one"""
def get_cwd(self):
"""
@ -262,24 +260,6 @@ class TaskBase(evil):
else:
return self.generator.bld.exec_command(cmd, **kw)
def runnable_status(self):
"""
Returns the Task status
:return: a task state in :py:const:`waflib.Task.RUN_ME`,
:py:const:`waflib.Task.SKIP_ME`, :py:const:`waflib.Task.CANCEL_ME` or :py:const:`waflib.Task.ASK_LATER`.
:rtype: int
"""
return RUN_ME
def uid(self):
"""
Computes a unique identifier for the task
:rtype: string or bytes
"""
return Utils.SIG_NIL
def process(self):
"""
Assume that the task has had a ``master`` which is an instance of :py:class:`waflib.Runner.Parallel`.
@ -324,20 +304,6 @@ class TaskBase(evil):
if self.hasrun != SUCCESS:
m.error_handler(self)
def run(self):
"""
Called by threads to execute the tasks. The default is empty and meant to be overridden in subclasses.
.. warning:: It is a bad idea to create nodes in this method, so avoid :py:meth:`waflib.Node.Node.ant_glob`
:rtype: int
"""
if hasattr(self, 'fun'):
return self.fun(self)
return 0
def post_run(self):
"Update build data after successful Task execution. Override in subclasses."
pass
def log_display(self, bld):
@ -472,40 +438,6 @@ class TaskBase(evil):
lst.append(y)
return lst
class Task(TaskBase):
"""
This class deals with the filesystem (:py:class:`waflib.Node.Node`). The method :py:class:`waflib.Task.Task.runnable_status`
uses a hash value (from :py:class:`waflib.Task.Task.signature`) which is persistent from build to build. When the value changes,
the task has to be executed. The method :py:class:`waflib.Task.Task.post_run` will assign the task signature to the output
nodes (if present).
"""
vars = []
"""ConfigSet variables that should trigger a rebuild (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
always_run = False
"""Specify whether task instances must always be executed or not (class attribute)"""
shell = False
"""Execute the command with the shell (class attribute)"""
def __init__(self, *k, **kw):
TaskBase.__init__(self, *k, **kw)
self.env = kw['env']
""":py:class:`waflib.ConfigSet.ConfigSet` object (make sure to provide one)"""
self.inputs = []
"""List of input nodes, which represent the files used by the task instance"""
self.outputs = []
"""List of output nodes, which represent the files created by the task instance"""
self.dep_nodes = []
"""List of additional nodes to depend on"""
self.run_after = set()
"""Set of tasks that must be executed before this one"""
def __str__(self):
"string to display to the user"
name = self.__class__.__name__
@ -526,9 +458,7 @@ class Task(TaskBase):
return '%s: %s%s%s' % (self.__class__.__name__, src_str, sep, tgt_str)
def keyword(self):
"""
See :py:meth:`waflib.Task.TaskBase`
"""
"Display keyword used to prettify the console outputs"
name = self.__class__.__name__
if name.endswith(('lib', 'program')):
return 'Linking'
@ -605,7 +535,7 @@ class Task(TaskBase):
:param task: task
:type task: :py:class:`waflib.Task.Task`
"""
assert isinstance(task, TaskBase)
assert isinstance(task, Task)
self.run_after.add(task)
def signature(self):
@ -654,7 +584,11 @@ class Task(TaskBase):
def runnable_status(self):
"""
See :py:meth:`waflib.Task.TaskBase.runnable_status`
Returns the Task status
:return: a task state in :py:const:`waflib.Task.RUN_ME`,
:py:const:`waflib.Task.SKIP_ME`, :py:const:`waflib.Task.CANCEL_ME` or :py:const:`waflib.Task.ASK_LATER`.
:rtype: int
"""
bld = self.generator.bld
if bld.is_install < 0:
@ -897,9 +831,9 @@ def is_before(t1, t2):
waflib.Task.is_before(t1, t2) # True
:param t1: Task object
:type t1: :py:class:`waflib.Task.TaskBase`
:type t1: :py:class:`waflib.Task.Task`
:param t2: Task object
:type t2: :py:class:`waflib.Task.TaskBase`
:type t2: :py:class:`waflib.Task.Task`
"""
to_list = Utils.to_list
for k in to_list(t2.ext_in):
@ -919,7 +853,7 @@ def set_file_constraints(tasks):
Updates the ``run_after`` attribute of all tasks based on the task inputs and outputs
:param tasks: tasks
:type tasks: list of :py:class:`waflib.Task.TaskBase`
:type tasks: list of :py:class:`waflib.Task.Task`
"""
ins = Utils.defaultdict(set)
outs = Utils.defaultdict(set)
@ -939,7 +873,7 @@ def set_precedence_constraints(tasks):
Updates the ``run_after`` attribute of all tasks based on the after/before/ext_out/ext_in attributes
:param tasks: tasks
:type tasks: list of :py:class:`waflib.Task.TaskBase`
:type tasks: list of :py:class:`waflib.Task.Task`
"""
cstr_groups = Utils.defaultdict(list)
for x in tasks:
@ -1144,7 +1078,7 @@ def compile_fun(line, shell=False):
"""
Parses a string expression such as '${CC} ${SRC} -o ${TGT}' and returns a pair containing:
* The function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`
* The function created (compiled) for use as :py:meth:`waflib.Task.Task.run`
* The list of variables that must cause rebuilds when *env* data is modified
for example::
@ -1230,3 +1164,6 @@ def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[
return cls
TaskBase = Task
"Provided for compatibility reasons, TaskBase should not be used"

View File

@ -20,7 +20,7 @@ HEADER_EXTS = ['.h', '.hpp', '.hxx', '.hh']
class task_gen(object):
"""
Instances of this class create :py:class:`waflib.Task.TaskBase` when
Instances of this class create :py:class:`waflib.Task.Task` when
calling the method :py:meth:`waflib.TaskGen.task_gen.post` from the main thread.
A few notes:
@ -264,7 +264,7 @@ class task_gen(object):
:param tgt: output nodes
:type tgt: list of :py:class:`waflib.Tools.Node.Node`
:return: A task object
:rtype: :py:class:`waflib.Task.TaskBase`
:rtype: :py:class:`waflib.Task.Task`
"""
task = Task.classes[name](env=self.env.derive(), generator=self)
if src:

View File

@ -1160,14 +1160,14 @@ def add_as_needed(self):
# ============ parallel configuration
class cfgtask(Task.TaskBase):
class cfgtask(Task.Task):
"""
A task that executes build configuration tests (calls conf.check)
Make sure to use locks if concurrent access to the same conf.env data is necessary.
"""
def __init__(self, *k, **kw):
Task.TaskBase.__init__(self, *k, **kw)
Task.Task.__init__(self, *k, **kw)
self.run_after = set()
def display(self):
@ -1182,6 +1182,9 @@ class cfgtask(Task.TaskBase):
def uid(self):
return Utils.SIG_NIL
def signature(self):
return Utils.SIG_NIL
def run(self):
conf = self.conf
bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())
@ -1209,7 +1212,7 @@ class cfgtask(Task.TaskBase):
return 1
def process(self):
Task.TaskBase.process(self)
Task.Task.process(self)
if 'msg' in self.args:
with self.generator.bld.multicheck_lock:
self.conf.start_msg(self.args['msg'])
@ -1265,11 +1268,12 @@ def multicheck(self, *k, **kw):
bld = par()
bld.keep = kw.get('run_all_tests', True)
bld.imp_sigs = {} # TODO
tasks = []
id_to_task = {}
for dct in k:
x = Task.classes['cfgtask'](bld=bld)
x = Task.classes['cfgtask'](bld=bld, env=None)
tasks.append(x)
x.args = dct
x.bld = bld

View File

@ -17,7 +17,7 @@ Usage:
import sys, os, json, shlex, pipes
from waflib import Logs, TaskGen, Task
Task.TaskBase.keep_last_cmd = True
Task.Task.keep_last_cmd = True
if sys.hexversion >= 0x3030000:
quote = shlex.quote

View File

@ -122,7 +122,7 @@ Options.OptionsContext.tool_options = Context.Context.load
Options.Handler = Options.OptionsContext
Task.simple_task_type = Task.task_type_from_func = Task.task_factory
Task.TaskBase.classes = Task.classes
Task.Task.classes = Task.classes
def setitem(self, key, value):
if key.startswith('CCFLAGS'):

View File

@ -48,7 +48,7 @@ class MakeContext(BuildContext):
for pat in self.files.split(','):
matcher = self.get_matcher(pat)
for tg in g:
if isinstance(tg, Task.TaskBase):
if isinstance(tg, Task.Task):
lst = [tg]
else:
lst = tg.tasks

View File

@ -244,8 +244,8 @@ def process(self):
self.generator.bld.producer.set_running(-1, id(Utils.threading.currentThread()), self)
Task.TaskBase.process_back = Task.TaskBase.process
Task.TaskBase.process = process
Task.Task.process_back = Task.Task.process
Task.Task.process = process
old_start = Runner.Parallel.start
def do_start(self):

View File

@ -10,7 +10,7 @@ from waflib import Task, Runner
Task.CANCELED = 4
def cancel_next(self, tsk):
if not isinstance(tsk, Task.TaskBase):
if not isinstance(tsk, Task.Task):
return
if tsk.hasrun >= Task.SKIPPED:
# normal execution, no need to do anything here