You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gump.apache.org by le...@apache.org on 2005/05/01 16:30:51 UTC
svn commit: r165511 - in /gump/branches/Gump3/pygump/python/gump: config.py
engine/algorithm.py plugins/__init__.py plugins/buildintelligence.py
Author: leosimons
Date: Sun May 1 07:30:50 2005
New Revision: 165511
URL: http://svn.apache.org/viewcvs?rev=165511&view=rev
Log:
Refactor build algorithms into their own location (GUMP-124).
* pygump/python/gump/plugins/__init__.py: move MultiCastPlugin and support code to gump.engine.algorithm.
* pygump/python/gump/plugins/buildintelligence.py: merge intelligent multicast plugins to gump.engine.algorithm.
* pygump/python/gump/engine/algorithm.py: merge multicast plugins and support code from pygump/python/gump/plugins/__init__.py and pygump/python/gump/plugins/buildintelligence.py into pygump/python/gump/engine/algorithm.py. Rename them to better reflect their purpose, and remove the dependency on AbstractPlugin. Also update to use UPDATE_xxx constants from pygump/python/gump/model/util.py.
Added:
gump/branches/Gump3/pygump/python/gump/engine/algorithm.py
- copied, changed from r165027, gump/branches/Gump3/pygump/python/gump/plugins/__init__.py
Removed:
gump/branches/Gump3/pygump/python/gump/plugins/buildintelligence.py
Modified:
gump/branches/Gump3/pygump/python/gump/config.py
gump/branches/Gump3/pygump/python/gump/plugins/__init__.py
Modified: gump/branches/Gump3/pygump/python/gump/config.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/config.py?rev=165511&r1=165510&r2=165511&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/config.py (original)
+++ gump/branches/Gump3/pygump/python/gump/config.py Sun May 1 07:30:50 2005
@@ -174,7 +174,7 @@
# TODO: implement an error handler that does actual recovery...
#from gump.plugins import LoggingErrorHandler
- from gump.plugins import OptimisticLoggingErrorHandler
+ from gump.engine.algorithm import OptimisticLoggingErrorHandler
log = get_logger(config, "plugin.error-handler")
return OptimisticLoggingErrorHandler(log)
@@ -287,16 +287,16 @@
def get_plugin(config):
"""Provide a Plugin implementation."""
- from gump.plugins import MulticastPlugin
- #from gump.plugins.buildintelligence import MoreEfficientMulticastPlugin
+ from gump.engine.algorithm import DumbAlgorithm
+ #from gump.engine.algorithm import MoreEfficientAlgorithm
(pre_process_plugins, plugins, post_process_plugins) = get_plugins(config)
error_handler = get_error_handler(config)
- return (MulticastPlugin(pre_process_plugins, error_handler),
- #MoreEfficientMulticastPlugin(plugins, error_handler),
- MulticastPlugin(plugins, error_handler),
- MulticastPlugin(post_process_plugins, error_handler))
+ return (DumbAlgorithm(pre_process_plugins, error_handler),
+ #MoreEfficientAlgorithm(plugins, error_handler),
+ DumbAlgorithm(plugins, error_handler),
+ DumbAlgorithm(post_process_plugins, error_handler))
#
# Miscellaneous configuration bits
Copied: gump/branches/Gump3/pygump/python/gump/engine/algorithm.py (from r165027, gump/branches/Gump3/pygump/python/gump/plugins/__init__.py)
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/engine/algorithm.py?p2=gump/branches/Gump3/pygump/python/gump/engine/algorithm.py&p1=gump/branches/Gump3/pygump/python/gump/plugins/__init__.py&r1=165027&r2=165511&rev=165511&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/plugins/__init__.py (original)
+++ gump/branches/Gump3/pygump/python/gump/engine/algorithm.py Sun May 1 07:30:50 2005
@@ -14,11 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Contains several modules which can be plugged into the pygump engine.
+"""Contains several algorithms which can be plugged into the Walker.
-A plugin is an instance of a class that extends AbstractPlugin. See the
-documentation for AbstractPlugin to learn more about the contracts
-surrounding plugins.
+Algorithms are a sort of "super-plugins" which are responsible for
+
+ a) actually firing up other plugins
+ b) implementing the "build algorithm"
+
+The walker handles dependency ordering and a depth-first traversal,
+after that its up to the algorithm implementation to provide all other
+build intelligence.
+
+The algorithm code is very similar to that of a plugin; make sure to
+read the plugin documentation for some additional details.
"""
__copyright__ = "Copyright (c) 2004-2005 The Apache Software Foundation"
@@ -26,7 +34,11 @@
import sys
-from gump.model import ModelObject
+from gump.model import ModelObject, CvsModule
+from gump.model.util import mark_failure, check_failure, mark_skip, check_skip
+from gump.model.util import mark_whether_module_was_updated
+
+from gump.model.util import UPDATE_TYPE_CHECKOUT, UPDATE_TYPE_UPDATE
class BaseErrorHandler:
"""Base error handler for use with the MulticastPlugin.
@@ -67,164 +79,115 @@
visited_model_object.exceptions = []
visited_model_object.exceptions.append( (type, value, traceback) )
-class AbstractPlugin:
- """Base class for all plugins.
-
- To create a concrete plugin, implement one or more of these methods:
-
- - initialize()
- - visit_workspace(workspace)
- - visit_repository(repository)
- - visit_module(module)
- - visit_project(project)
- - finalize()
-
- Ordering
- --------
- Each of these methods will be called in a "topologically sorted" order.
- Concretely, this means that:
-
- * initialize will be called first;
- * visit_workspace will be called first;
- * visit_repository will be called before any contained module or
- project is visited;
- * visit_module will be called before any contained project is
- visited;
- * visit_project will be called only after all dependencies of that
- project have already been visited;
- * finalize will be called last.
-
- More concretely, this means plugins usually do not have to worry about
- the correct ordering of events, since this is usually what you want.
-
- Error handling
- --------------
- Plugins are expected to raise an exception (usually gump.model.Error)
- if there is a problem with the model that prevents them from functioning
- as intended. If they are able to proceed but their execution results in
- a failure (which is not uncommon in the gump world at all), the plugin
- should *not* raise an exception but rather annotate the model with the
- information about that exception.
-
- Model annotation
- ----------------
- Plugins are expected to communicate with their environment through reading
- properties from the gump object model or setting properties on that model.
-
- In general, plugins that execute commands are expected to set the return
- code for that command as a "$action_exit_status" property on whatever part
- of the model makes most sense, for example a plugin that executes a Script
- model element should set the "build_exit_status" property on that element.
-
- Also in general, plugins that execute commands are expected to place the
- output (both stdout and stderr) of their commands as a "$action_log"
- property on the relevant part of the model, where "$action" is the
- conceptual task they are performing (update,build,...).
- """
- def __init__(self, log):
- self.log = log
-
- def _initialize(self):
- if not hasattr(self,'initialize'): return
- if not callable(self.initialize): return
- self.initialize()
-
- def _visit_workspace(self, workspace):
- if not hasattr(self,'visit_workspace'): return
- if not callable(self.visit_workspace): return
- self.visit_workspace(workspace)
-
- def _visit_repository(self, repository):
- if not hasattr(self,'visit_repository'): return
- if not callable(self.visit_repository): return
- self.visit_repository(repository)
-
- def _visit_module(self, module):
- if not hasattr(self,'visit_module'): return
- if not callable(self.visit_module): return
- self.visit_module(module)
-
- def _visit_project(self, project):
- if not hasattr(self,'visit_project'): return
- if not callable(self.visit_project): return
- self.visit_project(project)
-
- def _finalize(self):
- if not hasattr(self,'finalize'): return
- if not callable(self.finalize): return
- self.finalize()
-
- def __str__(self):
- return self.__class__.__name__
-
-class MulticastPlugin(AbstractPlugin):
+class DumbAlgorithm:
"""Core plugin that redirects visit_XXX calls to other plugins."""
def __init__(self, plugin_list, error_handler=BaseErrorHandler()):
self.list = plugin_list
self.error_handler = error_handler
- def initialize(self):
+ def _initialize(self):
for visitor in self.list:
try: visitor._initialize()
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, "{{{initialization stage}}}", type, value, traceback)
- def visit_workspace(self, workspace):
+ def _visit_workspace(self, workspace):
for visitor in self.list:
try: visitor._visit_workspace(workspace)
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, workspace, type, value, traceback)
- def visit_repository(self, repository):
+ def _visit_repository(self, repository):
for visitor in self.list:
try: visitor._visit_repository(repository)
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, repository, type, value, traceback)
- def visit_module(self, module):
+ def _visit_module(self, module):
for visitor in self.list:
try: visitor._visit_module(module)
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, module, type, value, traceback)
- def visit_project(self, project):
+ def _visit_project(self, project):
for visitor in self.list:
try: visitor._visit_project(project)
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, project, type, value, traceback)
- def finalize(self):
+ def _finalize(self):
for visitor in self.list:
try: visitor._finalize()
except:
(type, value, traceback) = sys.exc_info()
self.error_handler.handle(visitor, "{{{finalization stage}}}", type, value, traceback)
-class LoggingPlugin(AbstractPlugin):
- """Plugin that prints debug messages as it visits model objects."""
- def __init__(self, log):
- self.log = log
-
- def initialize(self):
- self.log.debug("Initializing...")
-
- def visit_workspace(self, workspace):
- self.log.debug("Visiting workspace.")
+class MoreEfficientAlgorithm(DumbAlgorithm):
+ """MulticastPlugin that implements a more efficient build algorithm.
+
+ This plugin detects "failure" for a particular step in the build, and when
+ it does, it sometimes skips a few steps.
- def visit_repository(self, repository):
- self.log.debug("Visiting repository '%s'." % repository.name)
+ The following rules are implemented:
+ - if a module fails to update, the projects it contains are not built
+ - if there were no changes to the module since the previous run, the projects
+ it contains are not built
+ - if a project fails to build, none of its dependees are built
+
+ If an element "fails", its "failed" property will be set to "True" and an
+ array named "failure_cause" will be created pointing to the elements that
+ "caused" them to fail.
+ """
+ #def __init__(self, plugin_list):
+ # MulticastPlugin.__init__(self, plugin_list, OptimisticLoggingErrorHandler())
def visit_module(self, module):
- self.log.debug("Visiting module '%s'." % module.name)
-
+ # run the delegates
+ try:
+ for visitor in self.list:
+ visitor._visit_module(module)
+ except:
+ (type, value, traceback) = sys.exc_info()
+ self.error_handler.handle(visitor, module, type, value, traceback)
+ mark_failure(module, module.exceptions[len(module.exceptions)-1])
+
+ # check for update errors
+ if getattr(module, "update_exit_status", False):
+ mark_failure(module, module)
+ # if module update failed, don't try and attempt to build contained
+ # projects either.
+ for project in module.projects.values():
+ mark_failure(project, module)
+
+ # check for changes
+ mark_whether_module_was_updated(module)
+ if not getattr(module, "was_updated", False):
+ for project in module.projects.values():
+ mark_skip(project)
+
def visit_project(self, project):
- self.log.debug("Visiting project '%s'." % project.name)
-
- def finalize(self):
- self.log.debug("Finishing up...")
-
+ # check for dependencies that failed to build
+ for relationship in project.dependencies:
+ if check_failure(relationship.dependency):
+ mark_failure(project, relationship)
+
+ # don't build if its not going to do any good
+ if not check_failure(project) and not check_skip(project):
+ try:
+ for visitor in self.list:
+ visitor._visit_project(project)
+ except:
+ (type, value, traceback) = sys.exc_info()
+ self.error_handler.handle(visitor, project, type, value, traceback)
+ mark_failure(project, project.exceptions[len(project.exceptions)-1])
+
+ # blame commands that went awry
+ for command in project.commands:
+ if getattr(command, "build_exit_status", False):
+ mark_failure(command, command)
+ mark_failure(project, command)
Modified: gump/branches/Gump3/pygump/python/gump/plugins/__init__.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/plugins/__init__.py?rev=165511&r1=165510&r2=165511&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/plugins/__init__.py (original)
+++ gump/branches/Gump3/pygump/python/gump/plugins/__init__.py Sun May 1 07:30:50 2005
@@ -28,45 +28,6 @@
from gump.model import ModelObject
-class BaseErrorHandler:
- """Base error handler for use with the MulticastPlugin.
-
- This handler just re-raises a caught error.
- """
- def handle(self, visitor, visited_model_object, type, value, traceback):
- """Override this method to be able to swallow exceptions."""
- # TODO this is not properly saving the traceback stack. Highly annoying. Fix it!
- raise type, value
-
-class LoggingErrorHandler:
- """Logging error handler for use with the MulticastPlugin.
-
- This handler logs then just re-raises a caught error.
- """
- def __init__(self, log):
- self.log = log
-
- def handle(self, visitor, visited_model_object, type, value, traceback):
- """Override this method to be able to swallow exceptions."""
- self.log.exception("%s threw an exception while visiting %s!" % (visitor, visited_model_object))
- raise type, value
-
-class OptimisticLoggingErrorHandler:
- """Logging error handler for use with the MulticastPlugin.
-
- This handler logs a caught error then stores it on the model.
- """
- def __init__(self, log):
- self.log = log
-
- def handle(self, visitor, visited_model_object, type, value, traceback):
- """Override this method to be able to swallow exceptions."""
- self.log.exception("%s threw an exception while visiting %s!" % (visitor, visited_model_object))
- if isinstance(visited_model_object, ModelObject):
- if not hasattr(visited_model_object, 'exceptions'):
- visited_model_object.exceptions = []
- visited_model_object.exceptions.append( (type, value, traceback) )
-
class AbstractPlugin:
"""Base class for all plugins.
@@ -157,54 +118,6 @@
def __str__(self):
return self.__class__.__name__
-class MulticastPlugin(AbstractPlugin):
- """Core plugin that redirects visit_XXX calls to other plugins."""
- def __init__(self, plugin_list, error_handler=BaseErrorHandler()):
- self.list = plugin_list
- self.error_handler = error_handler
-
- def initialize(self):
- for visitor in self.list:
- try: visitor._initialize()
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, "{{{initialization stage}}}", type, value, traceback)
-
- def visit_workspace(self, workspace):
- for visitor in self.list:
- try: visitor._visit_workspace(workspace)
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, workspace, type, value, traceback)
-
- def visit_repository(self, repository):
- for visitor in self.list:
- try: visitor._visit_repository(repository)
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, repository, type, value, traceback)
-
- def visit_module(self, module):
- for visitor in self.list:
- try: visitor._visit_module(module)
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, module, type, value, traceback)
-
- def visit_project(self, project):
- for visitor in self.list:
- try: visitor._visit_project(project)
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, project, type, value, traceback)
-
- def finalize(self):
- for visitor in self.list:
- try: visitor._finalize()
- except:
- (type, value, traceback) = sys.exc_info()
- self.error_handler.handle(visitor, "{{{finalization stage}}}", type, value, traceback)
-
class LoggingPlugin(AbstractPlugin):
"""Plugin that prints debug messages as it visits model objects."""
def __init__(self, log):