[jhbuild: 1/27] change building state machine for an inter-phases dependency system



commit 809bcee848e4837c666e5afed9d05b508de3450a
Author: Frederic Peters <fpeters 0d be>
Date:   Sun May 3 23:50:24 2009 +0200

    change building state machine for an inter-phases dependency system
    
    Use a simple dependency resolution system (no support for dependency
    cycles) to build a list of phases required to build a module. This
    allows more control over targets and puts a stop to the multiplication
    of flags that were necessary to reach non-standard steps (such as
    make distcheck).
    
    The makeclean, makecheck, nobuild, makedist and makedistcheck options
    can now all be implemented with a single build_targets option; support
    exists to fill this new option according to the older flags.
---
 jhbuild/commands/base.py         |   31 +++++----
 jhbuild/commands/bot.py          |    4 +-
 jhbuild/config.py                |   15 ++++
 jhbuild/defaults.jhbuildrc       |    2 +
 jhbuild/errors.py                |    9 +++
 jhbuild/frontends/autobuild.py   |   14 ++--
 jhbuild/frontends/buildscript.py |  133 +++++++++++++++++++++++++++-----------
 jhbuild/frontends/gtkui.py       |   20 +++---
 jhbuild/frontends/terminal.py    |   29 +++++----
 jhbuild/frontends/tinderbox.py   |   14 ++--
 jhbuild/modtypes/__init__.py     |   68 +++++--------------
 jhbuild/modtypes/ant.py          |   38 +++--------
 jhbuild/modtypes/autotools.py    |  127 +++++++++++++-----------------------
 jhbuild/modtypes/cmake.py        |   52 +++++----------
 jhbuild/modtypes/distutils.py    |   35 +++--------
 jhbuild/modtypes/linux.py        |   94 +++++++++------------------
 jhbuild/modtypes/perl.py         |   35 +++--------
 jhbuild/modtypes/testmodule.py   |   19 +----
 jhbuild/modtypes/waf.py          |   87 ++++++++-----------------
 19 files changed, 351 insertions(+), 475 deletions(-)

diff --git a/jhbuild/commands/base.py b/jhbuild/commands/base.py
index 50e53c0..f771f30 100644
--- a/jhbuild/commands/base.py
+++ b/jhbuild/commands/base.py
@@ -87,7 +87,7 @@ class cmd_update(Command):
                 raise FatalError(_('%s not in module list') % options.startat)
 
         # don't actually perform build ...
-        config.nobuild = True
+        config.build_targets = ['checkout']
         config.nonetwork = False
 
         build = jhbuild.frontends.get_buildscript(config, module_list)
@@ -123,7 +123,7 @@ class cmd_updateone(Command):
             self.parser.error(_('This command requires a module parameter.'))
 
         # don't actually perform build ...
-        config.nobuild = True
+        config.build_targets = ['checkout']
         config.nonetwork = False
 
         build = jhbuild.frontends.get_buildscript(config, module_list)
@@ -161,9 +161,10 @@ class cmd_cleanone(Command):
             logging.info(
                     _('clean command called while makeclean is set to False, skipped.'))
             return 0
+        config.build_targets = ['clean']
 
         build = jhbuild.frontends.get_buildscript(config, module_list)
-        return build.clean()
+        return build.build()
 
 register_command(cmd_cleanone)
 
@@ -277,14 +278,14 @@ class cmd_build(Command):
     def run(self, config, options, args):
         if options.autogen:
             config.alwaysautogen = True
-        if options.clean:
-            config.makeclean = True
-        if options.dist:
-            config.makedist = True
+        if options.clean and not 'clean' in config.build_targets:
+            config.build_targets.insert(0, 'clean')
+        if options.dist and not 'dist' in config.build_targets:
+            config.build_targets.append('dist')
+        if options.distcheck and not 'distcheck' in config.build_targets:
+            config.build_targets.append('distcheck')
         if options.ignore_suggests:
             config.ignore_suggests = True
-        if options.distcheck:
-            config.makedistcheck = True
         if options.nonetwork:
             config.nonetwork = True
         for item in options.skip:
@@ -379,12 +380,12 @@ class cmd_buildone(Command):
     def run(self, config, options, args):
         if options.autogen:
             config.alwaysautogen = True
-        if options.clean:
-            config.makeclean = True
-        if options.dist:
-            config.makedist = True
-        if options.distcheck:
-            config.makedistcheck = True
+        if options.clean and not 'clean' in config.build_targets:
+            config.build_targets.insert(0, 'clean')
+        if options.dist and not 'dist' in config.build_targets:
+            config.build_targets.append('dist')
+        if options.distcheck and not 'distcheck' in config.build_targets:
+            config.build_targets.append('distcheck')
         if options.nonetwork:
             config.nonetwork = True
         if options.sticky_date is not None:
diff --git a/jhbuild/commands/bot.py b/jhbuild/commands/bot.py
index 9fd9e4f..7440154 100644
--- a/jhbuild/commands/bot.py
+++ b/jhbuild/commands/bot.py
@@ -153,9 +153,7 @@ class cmd_bot(Command):
                 config.alwaysautogen = True
             elif args[0] == 'check':
                 command = 'buildone'
-                config.nobuild = True
-                config.makecheck = True
-                config.forcecheck = True
+                config.build_targets = ['check']
                 config.build_policy = 'all'
             elif args[0] == 'clean':
                 command = 'cleanone'
diff --git a/jhbuild/config.py b/jhbuild/config.py
index b699072..242e214 100644
--- a/jhbuild/config.py
+++ b/jhbuild/config.py
@@ -49,6 +49,7 @@ _known_keys = [ 'moduleset', 'modules', 'skip', 'tags', 'prefix',
                 'jhbuildbot_svn_commits_box',
                 'use_local_modulesets', 'ignore_suggests', 'modulesets_dir',
                 'mirror_policy', 'module_mirror_policy', 'dvcs_mirror_dir',
+                'build_targets',
                 ]
 
 env_prepends = {}
@@ -331,6 +332,20 @@ class Config:
                     valarr.remove(x)
             os.environ['LD_PRELOAD'] = ' '.join(valarr)
 
+        # update build targets according to old flags
+        if self.makeclean and not 'clean' in self.build_targets:
+            self.build_targets.insert(0, 'clean')
+        if self.makecheck and not 'check' in self.build_targets:
+            self.build_targets.insert(0, 'check')
+        if self.nobuild:
+            self.build_targets.remove('install')
+            if len(self.build_targets) == 0:
+                self.build_targets = ['checkout']
+        if self.makedist and not 'dist' in self.build_targets:
+            self.build_targets.append('dist')
+        if self.makedistcheck and not 'distcheck' in self.build_targets:
+            self.build_targets.append('distcheck')
+
     def __setattr__(self, k, v):
         '''Override __setattr__ for additional checks on some options.'''
         if k == 'quiet_mode' and v:
diff --git a/jhbuild/defaults.jhbuildrc b/jhbuild/defaults.jhbuildrc
index 0f6816e..ffc3cd9 100644
--- a/jhbuild/defaults.jhbuildrc
+++ b/jhbuild/defaults.jhbuildrc
@@ -78,6 +78,8 @@ trycheckout   = False  # try to force checkout and autogen on failure
 nopoison      = False  # don't poison modules on failure
 forcecheck    = False  # run make check even when not building
 
+build_targets = ['install']
+
 makecheck_advisory = False # whether to pass over 'make check' failures
 
 interact      = True   # whether to interact with the user.
diff --git a/jhbuild/errors.py b/jhbuild/errors.py
index 251e903..227a7e6 100644
--- a/jhbuild/errors.py
+++ b/jhbuild/errors.py
@@ -49,3 +49,12 @@ class BuildStateError(JhbuildException):
 class DependencyCycleError(JhbuildException):
     '''There is a dependency cycle in the module set'''
 
+
+class SkipToPhase(Exception):
+    def __init__(self, phase):
+        Exception.__init__(self)
+        self.phase = phase
+
+class SkipToEnd(SkipToPhase):
+    def __init__(self):
+        SkipToPhase.__init__(self, None)
diff --git a/jhbuild/frontends/autobuild.py b/jhbuild/frontends/autobuild.py
index 3e0c968..968a26f 100644
--- a/jhbuild/frontends/autobuild.py
+++ b/jhbuild/frontends/autobuild.py
@@ -238,27 +238,27 @@ class AutobuildBuildScript(buildscript.BuildScript, TerminalBuildScript):
         self.modulefp = None
         self.server.end_module(self.build_id, module, compress_data(log), failed)
 
-    def start_phase(self, module, state):
-        self.server.start_phase(self.build_id, module, state)
+    def start_phase(self, module, phase):
+        self.server.start_phase(self.build_id, module, phase)
         if self.verbose:
-            TerminalBuildScript.start_phase(self, module, state)
+            TerminalBuildScript.start_phase(self, module, phase)
         self.phasefp = StringIO()
 
 
-    def end_phase(self, module, state, error):
+    def end_phase(self, module, phase, error):
         log = fix_encoding(self.phasefp.getvalue())
         self.phasefp = None
 
-        if state == 'test':
+        if phase == 'test':
             if self.modules == {}:
                 self.modules = jhbuild.moduleset.load_tests(self.config)
 
             if module in self.modules.modules.keys() \
                    and self.modules.modules[module].test_type == 'ldtp':
                 self._upload_logfile(module)
-        self.server.end_phase(self.build_id, module, state, compress_data(log), error)
+        self.server.end_phase(self.build_id, module, phase, compress_data(log), error)
 
-    def handle_error(self, module, state, nextstate, error, altstates):
+    def handle_error(self, module, phase, nextphase, error, altphases):
         '''handle error during build'''
 	print 'FIXME: handle error! (failed build: %s: %s)' % (module, error)
         return 'fail'
diff --git a/jhbuild/frontends/buildscript.py b/jhbuild/frontends/buildscript.py
index 6c94da0..24c0904 100644
--- a/jhbuild/frontends/buildscript.py
+++ b/jhbuild/frontends/buildscript.py
@@ -21,7 +21,7 @@
 import os
 
 from jhbuild.utils import packagedb
-from jhbuild.errors import FatalError, CommandError
+from jhbuild.errors import FatalError, CommandError, SkipToPhase, SkipToEnd
 
 class BuildScript:
     def __init__(self, config, module_list):
@@ -68,27 +68,6 @@ class BuildScript:
         '''
         raise NotImplementedError
 
-    def start_clean(self):
-        '''Hook to perform actions at start of clean.'''
-        pass
-
-    def end_clean(self):
-        '''Hook to perform actions at end of clean.'''
-        pass
-
-    def clean(self):
-        self.start_clean()
-
-        for module in self.modulelist:
-            try:
-                module.do_clean(self)
-            except CommandError:
-                self.message(_('Failed to clean %s') % module.name)
-
-        self.end_clean()
-        return 0
-
-
     def build(self):
         '''start the build of the current configuration'''
         self.start_build()
@@ -120,30 +99,110 @@ class BuildScript:
                 self.end_module(module.name, failed)
                 continue
 
-            state = module.STATE_START
-            while state != module.STATE_DONE:
-                self.start_phase(module.name, state)
-                nextstate, error, altstates = module.run_state(self, state)
-                self.end_phase(module.name, state, error)
+            phases = self.get_build_phases(module)
+            phase = None
+            num_phase = 0
+            while num_phase < len(phases):
+                print 'phases:', phases
+                print '  current phase:', num_phase
+                last_phase, phase = phase, phases[num_phase]
+                if module.skip_phase(phase, last_phase):
+                    num_phase += 1
+                    continue
+
+                self.start_phase(module.name, phase)
+                error = None
+                try:
+                    error, altphases = module.run_phase(self, phase)
+                except SkipToPhase, e:
+                    try:
+                        num_phase = phases.index(e.phase)
+                    except ValueError:
+                        break
+                    continue
+                except SkipToEnd:
+                    break
+                finally:
+                    self.end_phase(module.name, phase, error)
 
                 if error:
-                    newstate = self.handle_error(module, state,
-                                                 nextstate, error,
-                                                 altstates)
-                    if newstate == 'fail':
+                    try:
+                        nextphase = phases[num_phase+1]
+                    except IndexError:
+                        nextphase = None
+                    newphase = self.handle_error(module, phase,
+                                                 nextphase, error,
+                                                 altphases)
+                    if newphase == 'fail':
                         failures.append(module.name)
                         failed = True
-                        state = module.STATE_DONE
+                        break
+                    if newphase is None:
+                        break
+                    if newphase in phases:
+                        num_phase = phases.index(newphase)
                     else:
-                        state = newstate
+                        # requested phase is not part of the plan, we insert
+                        # it, then fill with necessary phases to get back to
+                        # the current one.
+                        filling_phases = self.get_build_phases(module, targets=[phase])
+                        canonical_new_phase = newphase
+                        if canonical_new_phase.startswith('force_'):
+                            # the force_ phases won't appear in normal build
+                            # phases, so get the non-forced phase
+                            canonical_new_phase = canonical_new_phase[6:]
+
+                        if canonical_new_phase in filling_phases:
+                            filling_phases = filling_phases[
+                                    filling_phases.index(canonical_new_phase)+1:-1]
+                        phases[num_phase:num_phase] = [newphase] + filling_phases
+
+                        if phases[num_phase+1] == canonical_new_phase:
+                            # remove next phase if it would just be a repeat of
+                            # the inserted one
+                            del phases[num_phase+1]
                 else:
-                    state = nextstate
+                    num_phase += 1
+
             self.end_module(module.name, failed)
         self.end_build(failures)
         if failures:
             return 1
         return 0
 
+    def get_build_phases(self, module, targets=None):
+        '''returns the list of required phases'''
+        if targets:
+            tmp_phases = targets[:]
+        else:
+            tmp_phases = self.config.build_targets[:]
+        i = 0
+        while i < len(tmp_phases):
+            phase = tmp_phases[i]
+            depadd = []
+            try:
+                phase_method = getattr(module, 'do_' + phase)
+            except AttributeError:
+                # unknown phase for this module type, simply skip
+                del tmp_phases[i]
+                continue
+            if hasattr(phase_method, 'depends'):
+                for subphase in phase_method.depends:
+                    if subphase not in tmp_phases[:i+1]:
+                        depadd.append(subphase)
+            if depadd:
+                tmp_phases[i:i] = depadd
+            else:
+                i += 1
+
+        # remove duplicates
+        phases = []
+        for phase in tmp_phases:
+            if not phase in phases:
+                phases.append(phase)
+
+        return phases
+
     def start_build(self):
         '''Hook to perform actions at start of build.'''
         pass
@@ -158,10 +217,10 @@ class BuildScript:
         '''Hook to perform actions after finishing a build of a module.
         The argument is true if the module failed to build.'''
         pass
-    def start_phase(self, module, state):
+    def start_phase(self, module, phase):
         '''Hook to perform actions before starting a particular build phase.'''
         pass
-    def end_phase(self, module, state, error):
+    def end_phase(self, module, phase, error):
         '''Hook to perform actions after finishing a particular build phase.
         The argument is a string containing the error text if something
         went wrong.'''
@@ -175,6 +234,6 @@ class BuildScript:
         '''inform the buildscript of a new stage of the build'''
         raise NotImplementedError
 
-    def handle_error(self, module, state, nextstate, error, altstates):
+    def handle_error(self, module, phase, nextphase, error, altphases):
         '''handle error during build'''
         raise NotImplementedError
diff --git a/jhbuild/frontends/gtkui.py b/jhbuild/frontends/gtkui.py
index dab76e3..672f500 100644
--- a/jhbuild/frontends/gtkui.py
+++ b/jhbuild/frontends/gtkui.py
@@ -383,7 +383,7 @@ class GtkBuildScript(buildscript.BuildScript):
             client = gconf.client_get_default()
             client.set_string("/apps/jhbuild/start_at_module", module)
 
-    def handle_error(self, module, state, nextstate, error, altstates):
+    def handle_error(self, module, phase, nextphase, error, altphases):
         '''Ask the user what to do about an error.
 
         Returns one of ERR_RERUN, ERR_CONT or ERR_GIVEUP.''' #"
@@ -391,15 +391,15 @@ class GtkBuildScript(buildscript.BuildScript):
         if not self.config.interact:
             return 'fail'
 
-        dialog = gtk.Dialog(_('Error during %(state)s for module %(module)s') 
-                            % {'state':state, 'module':module.name})
-        dialog.add_button(_('_Try %s Again') % state, 1)
+        dialog = gtk.Dialog(_('Error during %(phase)s for module %(module)s') 
+                            % {'phase':phase, 'module':module.name})
+        dialog.add_button(_('_Try %s Again') % phase, 1)
         dialog.add_button(_('_Ignore Error'), 2)
         dialog.add_button(_('_Skip Module'), 3)
         dialog.add_button(_('_Terminal'), 4)
 
-        for i, altstate in enumerate(altstates):
-            dialog.add_button(_('Go to %s') % altstate, i + 5)
+        for i, altphase in enumerate(altphases):
+            dialog.add_button(_('Go to %s') % altphase, i + 5)
 
         text_view = gtk.TextView()
         text_view.set_buffer(self.build_text)
@@ -416,7 +416,7 @@ class GtkBuildScript(buildscript.BuildScript):
         
         while True:
 
-            #self.message('error during %s for module %s' % (state, module.name))
+            #self.message('error during %s for module %s' % (phase, module.name))
 
             text_view.scroll_to_iter(self.build_text.get_end_iter(), 0.0, True, 0.5, 0.5)
             dialog.show_all()
@@ -427,9 +427,9 @@ class GtkBuildScript(buildscript.BuildScript):
                 dialog.hide()
             # If the dialog was destroyed, interpret that as try again.
             if val in (1, gtk.RESPONSE_NONE, gtk.RESPONSE_DELETE_EVENT):
-                return state
+                return phase
             elif val == 2:
-                return nextstate
+                return nextphase
             elif val == 3:
                 return 'fail'
             elif val == 4:
@@ -437,7 +437,7 @@ class GtkBuildScript(buildscript.BuildScript):
                                          self.terminal_command)
                 os.system(command)
             else:
-                return altstates[val - 5]
+                return altphases[val - 5]
 
     def _createWindow(self):
 	glade_filename = get_glade_filename()
diff --git a/jhbuild/frontends/terminal.py b/jhbuild/frontends/terminal.py
index cfd4a4b..433f6e0 100644
--- a/jhbuild/frontends/terminal.py
+++ b/jhbuild/frontends/terminal.py
@@ -232,9 +232,9 @@ class TerminalBuildScript(buildscript.BuildScript):
             # it could happen on a really badly-timed ctrl-c (see bug 551641)
             raise CommandError(_('########## Error running %s') % pretty_command)
 
-    def start_phase(self, module, state):
+    def start_phase(self, module, phase):
         self.trayicon.set_icon(os.path.join(icondir,
-                               phase_map.get(state, 'build.png')))
+                               phase_map.get(phase, 'build.png')))
 
     def end_build(self, failures):
         self.is_end_of_build = True
@@ -246,10 +246,10 @@ class TerminalBuildScript(buildscript.BuildScript):
                 print module,
             print
 
-    def handle_error(self, module, state, nextstate, error, altstates):
+    def handle_error(self, module, phase, nextphase, error, altphases):
         '''handle error during build'''
-        summary = _('error during stage %(stage)s of %(module)s') % {
-            'stage':state, 'module':module.name}
+        summary = _('error during phase %(phase)s of %(module)s') % {
+            'phase': phase, 'module':module.name}
         try:
             error_message = error.args[0]
             self.message('%s: %s' % (summary, error_message))
@@ -260,7 +260,7 @@ class TerminalBuildScript(buildscript.BuildScript):
         self.notify.notify(summary = summary, body = error_message,
                 icon = 'dialog-error', expire = 20)
 
-        if self.config.trycheckout and (not self.triedcheckout) and altstates.count('force_checkout'):
+        if self.config.trycheckout and (not self.triedcheckout) and altphases.count('force_checkout'):
             self.triedcheckout = True
             return 'force_checkout'
         self.triedcheckout = False
@@ -269,21 +269,24 @@ class TerminalBuildScript(buildscript.BuildScript):
             return 'fail'
         while True:
             print
-            uprint(_('  [1] rerun stage %s') % state)
-            uprint(_('  [2] ignore error and continue to %s') % nextstate)
+            uprint(_('  [1] rerun phase %s') % phase)
+            if nextphase:
+                uprint(_('  [2] ignore error and continue to %s') % nextphase)
+            else:
+                uprint(_('  [2] ignore error and continue to next module'))
             uprint(_('  [3] give up on module'))
             uprint(_('  [4] start shell'))
             uprint(_('  [5] reload configuration'))
             nb_options = i = 6
-            for altstate in altstates:
-                uprint(_('  [%d] go to stage %s') % (i, altstate))
+            for altphase in (altphases or []):
+                uprint(_('  [%d] go to phase %s') % (i, altphase))
                 i = i + 1
             val = raw_input(uencode(_('choice: ')))
             val = val.strip()
             if val == '1':
-                return state
+                return phase
             elif val == '2':
-                return nextstate
+                return nextphase
             elif val == '3':
                 return 'fail'
             elif val == '4':
@@ -300,7 +303,7 @@ class TerminalBuildScript(buildscript.BuildScript):
             else:
                 try:
                     val = int(val)
-                    return altstates[val - nb_options]
+                    return altphases[val - nb_options]
                 except:
                     uprint(_('invalid choice'))
         assert False, 'not reached'
diff --git a/jhbuild/frontends/tinderbox.py b/jhbuild/frontends/tinderbox.py
index 5e8d062..395e6c1 100644
--- a/jhbuild/frontends/tinderbox.py
+++ b/jhbuild/frontends/tinderbox.py
@@ -327,20 +327,20 @@ class TinderboxBuildScript(buildscript.BuildScript):
         self.indexfp.write('</tr>\n\n')
         self.indexfp.flush()
 
-    def start_phase(self, module, state):
-        self.modulefp.write('<a name="%s"></a>\n' % state)
-    def end_phase(self, module, state, error):
+    def start_phase(self, module, phase):
+        self.modulefp.write('<a name="%s"></a>\n' % phase)
+    def end_phase(self, module, phase, error):
         if error:
             self.indexfp.write('<a class="failure" title="%s" href="%s#%s">%s</a>\n'
-                               % (error, self.modulefilename, state, state))
+                               % (error, self.modulefilename, phase, phase))
         else:
             self.indexfp.write('<a class="success" href="%s#%s">%s</a>\n'
-                               % (self.modulefilename, state, state))
+                               % (self.modulefilename, phase, phase))
         self.indexfp.flush()
 
-    def handle_error(self, module, state, nextstate, error, altstates):
+    def handle_error(self, module, phase, nextphase, error, altphases):
         '''handle error during build'''
-        self.message('error during stage %s of %s: %s' % (state, module.name,
+        self.message('error during stage %s of %s: %s' % (phase, module.name,
                                                           error))
         if self.config.trycheckout and (not self.triedcheckout):
             self.triedcheckout = True
diff --git a/jhbuild/modtypes/__init__.py b/jhbuild/modtypes/__init__.py
index 664545d..91088e3 100644
--- a/jhbuild/modtypes/__init__.py
+++ b/jhbuild/modtypes/__init__.py
@@ -29,7 +29,7 @@ __all__ = [
 
 import os
 
-from jhbuild.errors import FatalError, CommandError, BuildStateError
+from jhbuild.errors import FatalError, CommandError, BuildStateError, SkipToEnd
 from jhbuild.utils.sxml import sxml
 
 _module_types = {}
@@ -117,12 +117,6 @@ def get_branch(node, repositories, default_repo, config):
     return repo.branch_from_xml(name, childnode, repositories, default_repo)
 
 
-class SkipToState(Exception):
-    def __init__(self, state):
-        Exception.__init__(self)
-        self.state = state
-
-
 class Package:
     type = 'base'
     STATE_START = 'start'
@@ -150,49 +144,29 @@ class Package:
     def get_revision(self):
         return None
 
-    def _next_state(self, buildscript, last_state):
-        """Work out what state to go to next, possibly skipping some states.
+    def skip_phase(self, phase, last_phase):
+        try:
+            skip_phase_method = getattr(self, 'skip_' + phase)
+        except AttributeError:
+            return False
+        return skip_phase_method(self, last_phase)
 
-        This function executes skip_$state() to decide whether to run that
-        state or not.  If it returns True, go to do_$state.next_state and
-        repeat.  If it returns False, return that state.
-        """
-        seen_states = []
-        state = getattr(self, 'do_' + last_state).next_state
-        while True:
-            seen_states.append(state)
-            if state == self.STATE_DONE:
-                return state
-            do_method = getattr(self, 'do_' + state)
-
-            skip_method = getattr(self, 'skip_' + state)
-            try:
-                if skip_method(buildscript, last_state):
-                    state = do_method.next_state
-                    assert state not in seen_states, (
-                        'state %s should not appear in list of '
-                        'skipped states: %r' % (state, seen_states))
-                else:
-                    return state
-            except SkipToState, e:
-                return e.state
-
-    def run_state(self, buildscript, state):
+    def run_phase(self, buildscript, phase):
         """run a particular part of the build for this package.
 
         Returns a tuple of the following form:
-          (next-state, error-flag, [other-states])
+          (error-flag, [other-phases])
         """
-        method = getattr(self, 'do_' + state)
+        method = getattr(self, 'do_' + phase)
         try:
             method(buildscript)
-        except SkipToState, e:
-            return (e.state, None, None)
         except (CommandError, BuildStateError), e:
-            return (self._next_state(buildscript, state),
-                    e, method.error_states)
+            error_phases = None
+            if hasattr(method, 'error_phases'):
+                error_phases = method.error_phases
+            return (e, error_phases)
         else:
-            return (self._next_state(buildscript, state), None, None)
+            return (None, None)
 
     def check_build_policy(self, buildscript):
         if not buildscript.config.build_policy in ('updated', 'updated-deps'):
@@ -227,13 +201,13 @@ class Package:
             raise BuildStateError(_('source directory %s was not created') % srcdir)
 
         if self.check_build_policy(buildscript) == self.STATE_DONE:
-            raise SkipToState(self.STATE_DONE)
+            raise SkipToEnd()
 
-    def skip_checkout(self, buildscript, last_state):
+    def skip_checkout(self, buildscript, last_phase):
         # skip the checkout stage if the nonetwork flag is set
         if buildscript.config.nonetwork:
             if self.check_build_policy(buildscript) == self.STATE_DONE:
-                raise SkipToState(self.STATE_DONE)
+                raise SkipToEnd()
             return True
         return False
 
@@ -285,12 +259,6 @@ class MetaModule(Package):
         return buildscript.config.buildroot or \
                self.get_srcdir(buildscript)
 
-    # nothing to actually build in a metamodule ...
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = Package.STATE_DONE
-    do_start.error_states = []
-
     def to_sxml(self):
         return [sxml.metamodule(id=self.name),
                 [sxml.dependencies]
diff --git a/jhbuild/modtypes/ant.py b/jhbuild/modtypes/ant.py
index d15895d..b662711 100644
--- a/jhbuild/modtypes/ant.py
+++ b/jhbuild/modtypes/ant.py
@@ -33,10 +33,10 @@ class AntModule(Package):
     """Base type for modules that are built with Ant."""
     type = 'ant'
 
-    STATE_CHECKOUT = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_BUILD = 'build'
-    STATE_INSTALL = 'install'
+    PHASE_CHECKOUT = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_BUILD = 'build'
+    PHASE_INSTALL = 'install'
 
     def __init__(self, name, branch,
                  dependencies=[], after=[],
@@ -59,31 +59,17 @@ class AntModule(Package):
     def get_revision(self):
         return self.branch.branchname
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
-    def skip_checkout(self, buildscript, last_state):
-        # skip the checkout stage if the nonetwork flag is set
-        return buildscript.config.nonetwork
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_BUILD
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
-    def skip_force_checkout(self, buildscript, last_state):
+    def skip_force_checkout(self, buildscript, last_phase):
         return False
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_BUILD
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
@@ -96,11 +82,8 @@ class AntModule(Package):
         #if srcdir != builddir:
         #    cmd.extend(['--build-base', builddir])
         buildscript.execute(cmd, cwd=srcdir)
-    do_build.next_state = STATE_INSTALL
-    do_build.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_build.depends = [PHASE_CHECKOUT]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_install(self, buildscript):
         # Quoting David Schleef:
@@ -109,8 +92,7 @@ class AntModule(Package):
         #    -- http://bugzilla.gnome.org/show_bug.cgi?id=537037
         buildscript.set_action(_('Installing'), self)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
+    do_install.depends = [PHASE_BUILD]
 
     def xml_tag_and_attrs(self):
         return 'ant', [('id', 'name', None),
diff --git a/jhbuild/modtypes/autotools.py b/jhbuild/modtypes/autotools.py
index aaeddc2..7722d36 100644
--- a/jhbuild/modtypes/autotools.py
+++ b/jhbuild/modtypes/autotools.py
@@ -36,16 +36,15 @@ class AutogenModule(Package):
     responsible for downloading/updating the working copy.'''
     type = 'autogen'
 
-    STATE_CHECKOUT       = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_CLEAN          = 'clean'
-    STATE_FORCE_CLEAN    = 'force_clean'
-    STATE_FORCE_DISTCLEAN= 'force_distclean'
-    STATE_CONFIGURE      = 'configure'
-    STATE_BUILD          = 'build'
-    STATE_CHECK          = 'check'
-    STATE_DIST           = 'dist'
-    STATE_INSTALL        = 'install'
+    PHASE_CHECKOUT       = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_CLEAN          = 'clean'
+    PHASE_DISTCLEAN      = 'distclean'
+    PHASE_CONFIGURE      = 'configure'
+    PHASE_BUILD          = 'build'
+    PHASE_CHECK          = 'check'
+    PHASE_DIST           = 'dist'
+    PHASE_INSTALL        = 'install'
 
     def __init__(self, name, branch, autogenargs='', makeargs='',
                  makeinstallargs='',
@@ -82,40 +81,26 @@ class AutogenModule(Package):
     def get_revision(self):
         return self.branch.tree_id()
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_CONFIGURE
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_CONFIGURE
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_configure(self, buildscript, last_state):
-        # skip if nobuild is set.
-        if buildscript.config.nobuild:
-            return True
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
+    def skip_configure(self, buildscript, last_phase):
         # skip if manually instructed to do so
         if self.skip_autogen is True:
             return True
 
         # don't skip this stage if we got here from one of the
-        # following states:
-        if last_state in [self.STATE_FORCE_CHECKOUT,
-                          self.STATE_CLEAN,
-                          self.STATE_BUILD,
-                          self.STATE_INSTALL]:
+        # following phases:
+        if last_phase in [self.PHASE_FORCE_CHECKOUT,
+                          self.PHASE_CLEAN,
+                          self.PHASE_BUILD,
+                          self.PHASE_INSTALL]:
             return False
 
         if self.skip_autogen == 'never':
@@ -203,13 +188,17 @@ class AutogenModule(Package):
             cmd = cmd.replace('${exec_prefix}', buildscript.config.prefix)
 
         buildscript.execute(cmd, cwd = builddir, extra_env = self.extra_env)
-    do_configure.next_state = STATE_CLEAN
-    do_configure.error_states = [STATE_FORCE_CHECKOUT,
-            STATE_FORCE_CLEAN, STATE_FORCE_DISTCLEAN]
+    do_configure.depends = [PHASE_CHECKOUT]
+    do_configure.error_phases = [PHASE_FORCE_CHECKOUT,
+            PHASE_CLEAN, PHASE_DISTCLEAN]
 
-    def skip_clean(self, buildscript, last_state):
-        return (not buildscript.config.makeclean or
-                buildscript.config.nobuild)
+    def skip_clean(self, buildscript, last_phase):
+        srcdir = self.get_srcdir(buildscript)
+        if not os.path.exists(srcdir):
+            return True
+        if not os.path.exists(os.path.join(srcdir, self.makefile)):
+            return True
+        return False
 
     def do_clean(self, buildscript):
         buildscript.set_action(_('Cleaning'), self)
@@ -218,30 +207,22 @@ class AutogenModule(Package):
         cmd = '%s %s clean' % (os.environ.get('MAKE', 'make'), makeargs)
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                 extra_env = self.extra_env)
-    do_clean.next_state = STATE_BUILD
-    do_clean.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_clean.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
         cmd = '%s %s' % (os.environ.get('MAKE', 'make'), self.makeargs)
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                 extra_env = self.extra_env)
-    do_build.next_state = STATE_CHECK
-    do_build.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE,
-            STATE_FORCE_CLEAN, STATE_FORCE_DISTCLEAN]
+    do_build.depends = [PHASE_CONFIGURE]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE,
+            PHASE_CLEAN, PHASE_DISTCLEAN]
 
-    def skip_check(self, buildscript, last_state):
+    def skip_check(self, buildscript, last_phase):
         if not self.check_target:
             return True
         if not buildscript.config.module_makecheck.get(self.name, buildscript.config.makecheck):
             return True
-        if buildscript.config.forcecheck:
-            return False
-        if buildscript.config.nobuild:
-            return True
         return False
 
     def do_check(self, buildscript):
@@ -253,25 +234,24 @@ class AutogenModule(Package):
         except CommandError:
             if not buildscript.config.makecheck_advisory:
                 raise
-    do_check.next_state = STATE_DIST
-    do_check.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_dist(self, buildscript, last_state):
-        return not (buildscript.config.makedist or buildscript.config.makedistcheck)
+    do_check.depends = [PHASE_BUILD]
+    do_check.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_dist(self, buildscript):
         buildscript.set_action(_('Creating tarball for'), self)
-        if buildscript.config.makedistcheck:
-            cmd = '%s %s distcheck' % (os.environ.get('MAKE', 'make'), self.makeargs)
-        else:
-            cmd = '%s %s dist' % (os.environ.get('MAKE', 'make'), self.makeargs)
+        cmd = '%s %s dist' % (os.environ.get('MAKE', 'make'), self.makeargs)
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                     extra_env = self.extra_env)
-    do_dist.next_state = STATE_INSTALL
-    do_dist.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
+    do_dist.depends = [PHASE_CONFIGURE]
+    do_dist.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    def do_distcheck(self, buildscript):
+        buildscript.set_action(_('Creating tarball for'), self)
+        cmd = '%s %s distcheck' % (os.environ.get('MAKE', 'make'), self.makeargs)
+        buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
+                    extra_env = self.extra_env)
+    do_dist.depends = [PHASE_CONFIGURE]
+    do_dist.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_install(self, buildscript):
         buildscript.set_action(_('Installing'), self)
@@ -283,27 +263,14 @@ class AutogenModule(Package):
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                     extra_env = self.extra_env)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
-
-    def skip_force_clean(self, buildscript, last_state):
-        return False
-
-    def do_force_clean(self, buildscript):
-        self.do_clean(buildscript)
-    do_force_clean.next_state = STATE_CONFIGURE
-    do_force_clean.error_states = []
-
-    def skip_force_distclean(self, buildscript, last_state):
-        return False
+    do_install.depends = [PHASE_BUILD]
 
-    def do_force_distclean(self, buildscript):
+    def do_distclean(self, buildscript):
         buildscript.set_action(_('Distcleaning'), self)
         cmd = '%s %s distclean' % (os.environ.get('MAKE', 'make'), self.makeargs)
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                     extra_env = self.extra_env)
-    do_force_distclean.next_state = STATE_CONFIGURE
-    do_force_distclean.error_states = []
+    do_distclean.depends = [PHASE_CONFIGURE]
 
     def xml_tag_and_attrs(self):
         return ('autotools',
diff --git a/jhbuild/modtypes/cmake.py b/jhbuild/modtypes/cmake.py
index 0a9f547..421be2d 100644
--- a/jhbuild/modtypes/cmake.py
+++ b/jhbuild/modtypes/cmake.py
@@ -31,12 +31,12 @@ class CMakeModule(Package):
     """Base type for modules that use CMake build system."""
     type = 'cmake'
 
-    STATE_CHECKOUT = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_CONFIGURE = 'configure'
-    STATE_BUILD = 'build'
-    STATE_DIST = 'dist'
-    STATE_INSTALL = 'install'
+    PHASE_CHECKOUT = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_CONFIGURE = 'configure'
+    PHASE_BUILD = 'build'
+    PHASE_DIST = 'dist'
+    PHASE_INSTALL = 'install'
 
     def __init__(self, name, branch, dependencies=[], after=[], suggests=[]):
         Package.__init__(self, name, dependencies, after, suggests)
@@ -56,26 +56,16 @@ class CMakeModule(Package):
     def get_revision(self):
         return self.branch.tree_id()
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_CONFIGURE
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_CONFIGURE
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
-    def skip_configure(self, buildscript, last_state):
+    def skip_configure(self, buildscript, last_phase):
         return buildscript.config.nobuild
     
     def do_configure(self, buildscript):
@@ -87,33 +77,24 @@ class CMakeModule(Package):
         prefix = os.path.expanduser(buildscript.config.prefix)
         cmd = ['cmake', '-DCMAKE_INSTALL_PREFIX=%s' % prefix, srcdir]
         buildscript.execute(cmd, cwd = builddir, extra_env = self.extra_env)
-    do_configure.next_state = STATE_BUILD
-    do_configure.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_configure.depends = [PHASE_CHECKOUT]
+    do_configure.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
         builddir = self.get_builddir(buildscript)
         buildscript.execute(os.environ.get('MAKE', 'make'), cwd = builddir,
                 extra_env = self.extra_env)
-    do_build.next_state = STATE_DIST
-    do_build.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_dist(self, buildscript, last_state):
-        return not buildscript.config.makedist
+    do_build.depends = [PHASE_CONFIGURE]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_dist(self, buildscript):
         buildscript.set_action(_('Creating tarball for'), self)
         cmd = '%s package_source' % os.environ.get('MAKE', 'make')
         buildscript.execute(cmd, cwd = self.get_builddir(buildscript),
                 extra_env = self.extra_env)
-    do_dist.next_state = STATE_INSTALL
-    do_dist.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_dist.depends = [PHASE_CONFIGURE]
+    do_dist.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_install(self, buildscript):
         buildscript.set_action(_('Installing'), self)
@@ -122,8 +103,7 @@ class CMakeModule(Package):
                 cwd = builddir,
                 extra_env = self.extra_env)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
+    do_install.depends = [PHASE_BUILD]
 
     def xml_tag_and_attrs(self):
         return 'cmake', [('id', 'name', None)]
diff --git a/jhbuild/modtypes/distutils.py b/jhbuild/modtypes/distutils.py
index 6df85a4..b39f151 100644
--- a/jhbuild/modtypes/distutils.py
+++ b/jhbuild/modtypes/distutils.py
@@ -32,10 +32,10 @@ class DistutilsModule(Package):
     Distutils style setup.py."""
     type = 'distutils'
 
-    STATE_CHECKOUT = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_BUILD = 'build'
-    STATE_INSTALL = 'install'
+    PHASE_CHECKOUT = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_BUILD = 'build'
+    PHASE_INSTALL = 'install'
 
     def __init__(self, name, branch,
                  dependencies = [], after = [], suggests = [],
@@ -58,27 +58,14 @@ class DistutilsModule(Package):
     def get_revision(self):
         return self.branch.tree_id()
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_BUILD
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_BUILD
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_force_checkout.error_phase = [PHASE_FORCE_CHECKOUT]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
@@ -89,11 +76,8 @@ class DistutilsModule(Package):
         if srcdir != builddir:
             cmd.extend(['--build-base', builddir])
         buildscript.execute(cmd, cwd = srcdir, extra_env = self.extra_env)
-    do_build.next_state = STATE_INSTALL
-    do_build.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_build.depends = [PHASE_CHECKOUT]
+    do_build.error_phase = [PHASE_FORCE_CHECKOUT]
 
     def do_install(self, buildscript):
         buildscript.set_action(_('Installing'), self)
@@ -106,8 +90,7 @@ class DistutilsModule(Package):
         cmd.extend(['install', '--prefix', buildscript.config.prefix])
         buildscript.execute(cmd, cwd = srcdir, extra_env = self.extra_env)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
+    do_install.depends = [PHASE_BUILD]
 
     def xml_tag_and_attrs(self):
         return 'distutils', [('id', 'name', None),
diff --git a/jhbuild/modtypes/linux.py b/jhbuild/modtypes/linux.py
index e70e2d7..3186717 100644
--- a/jhbuild/modtypes/linux.py
+++ b/jhbuild/modtypes/linux.py
@@ -51,15 +51,16 @@ class LinuxModule(Package):
     make config, make, make install and make modules_install.'''
     type = 'linux'
 
-    STATE_CHECKOUT        = 'checkout'
-    STATE_FORCE_CHECKOUT  = 'force_checkout'
-    STATE_CLEAN           = 'clean'
-    STATE_MRPROPER        = 'mrproper'
-    STATE_CONFIGURE       = 'configure'
-    STATE_BUILD           = 'build'
-    STATE_INSTALL         = 'install'
-    STATE_MODULES_INSTALL = 'modules_install'
-    STATE_HEADERS_INSTALL = 'headers_install'
+    PHASE_CHECKOUT        = 'checkout'
+    PHASE_FORCE_CHECKOUT  = 'force_checkout'
+    PHASE_CLEAN           = 'clean'
+    PHASE_MRPROPER        = 'mrproper'
+    PHASE_CONFIGURE       = 'configure'
+    PHASE_BUILD           = 'build'
+    PHASE_KERNEL_INSTALL  = 'kernel_install'
+    PHASE_MODULES_INSTALL = 'modules_install'
+    PHASE_HEADERS_INSTALL = 'headers_install'
+    PHASE_INSTALL         = 'install'
 
     def __init__(self, name, branch, kconfigs, makeargs,
             dependencies, after, suggests):
@@ -77,12 +78,7 @@ class LinuxModule(Package):
     def get_revision(self):
         return self.branch.branchname
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
-    def skip_checkout(self, buildscript, last_state):
+    def skip_checkout(self, buildscript, last_phase):
         # skip the checkout stage if the nonetwork flag is set
         # (can't just call Package.skip_checkout() as build policy won't work
         # with kconfigs)
@@ -93,20 +89,12 @@ class LinuxModule(Package):
         self.checkout(buildscript)
         for kconfig in self.kconfigs:
             kconfig.checkout(buildscript)
-    do_checkout.next_state = STATE_CONFIGURE
-    do_checkout.error_states = [STATE_MRPROPER]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_MRPROPER]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_CONFIGURE
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT, STATE_MRPROPER]
-
-    def skip_mrproper(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_MRPROPER]
 
     def get_makeargs(self):
         return self.makeargs + ' ' + self.config.module_makeargs.get(self.name, self.config.makeargs)
@@ -125,12 +113,7 @@ class LinuxModule(Package):
         cmd = '%s mrproper' % os.environ.get('MAKE', 'make')
         buildscript.execute(cmd, cwd = self.branch.srcdir,
                     extra_env = self.extra_env)
-
-    do_mrproper.next_state = STATE_CONFIGURE
-    do_mrproper.error_states = []
-
-    def skip_configure(self, buildscript, last_state):
-        return False
+    do_mrproper.depends = [PHASE_CHECKOUT]
 
     def do_configure(self, buildscript):
         buildscript.set_action(_('Configuring'), self)
@@ -161,12 +144,8 @@ class LinuxModule(Package):
             if kconfig.path:
                 os.remove(os.path.join(self.branch.srcdir, ".config"))
 
-    do_configure.next_state = STATE_CLEAN
-    do_configure.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_clean(self, buildscript, last_state):
-        return (not buildscript.config.makeclean or
-                buildscript.config.nobuild)
+    do_configure.depends = [PHASE_MRPROPER]
+    do_configure.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_clean(self, buildscript):
         buildscript.set_action(_('Cleaning'), self)
@@ -179,11 +158,7 @@ class LinuxModule(Package):
             buildscript.execute(cmd, cwd = self.branch.srcdir,
                     extra_env = self.extra_env)
 
-    do_clean.next_state = STATE_BUILD
-    do_clean.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_clean.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
@@ -195,14 +170,11 @@ class LinuxModule(Package):
             buildscript.execute(cmd, cwd = self.branch.srcdir,
                     extra_env = self.extra_env)
 
-    do_build.next_state = STATE_INSTALL
-    do_build.error_states = [STATE_FORCE_CHECKOUT, STATE_MRPROPER, STATE_CONFIGURE]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_build.depends = [PHASE_CONFIGURE]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_MRPROPER, PHASE_CONFIGURE]
 
-    def do_install(self, buildscript):
-        buildscript.set_action(_('Installing'), self)
+    def do_kernel_install(self, buildscript):
+        buildscript.set_action(_('Installing kernel'), self)
         bootdir = os.path.join(buildscript.config.prefix, 'boot')
         if not os.path.isdir(bootdir):
             os.makedirs(bootdir)
@@ -216,11 +188,8 @@ class LinuxModule(Package):
                 buildscript.execute(cmd, cwd = self.branch.srcdir,
                     extra_env = self.extra_env)
 
-    do_install.next_state = STATE_MODULES_INSTALL
-    do_install.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_modules_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_kernel_install.depends = [PHASE_BUILD]
+    do_kernel_install.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_modules_install(self, buildscript):
         buildscript.set_action(_('Installing modules'), self)
@@ -234,14 +203,11 @@ class LinuxModule(Package):
             buildscript.execute(cmd, cwd = self.branch.srcdir,
                     extra_env = self.extra_env)
 
-    do_modules_install.next_state = STATE_HEADERS_INSTALL
-    do_modules_install.error_states = []
-
-    def skip_headers_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_modules_install.depends = [PHASE_BUILD]
+    do_modules_install.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_headers_install(self, buildscript):
-        buildscript.set_action(_('Installing kernel'), self)
+        buildscript.set_action(_('Installing kernel headers'), self)
         for kconfig in self.kconfigs:
             cmd = '%s %s headers_install EXTRAVERSION=%s O=%s INSTALL_HDR_PATH=%s' % (
                     os.environ.get('MAKE', 'make'),
@@ -253,8 +219,12 @@ class LinuxModule(Package):
                     extra_env = self.extra_env)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
 
-    do_headers_install.next_state = Package.STATE_DONE
-    do_headers_install.error_states = []
+    do_headers_install.depends = [PHASE_BUILD]
+    do_headers_install.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
+
+    def do_install(self, buildscript):
+        pass
+    do_install.depends = [PHASE_KERNEL_INSTALL, PHASE_MODULES_INSTALL, PHASE_HEADERS_INSTALL]
 
     def xml_tag_and_attrs(self):
         return 'linux', [('id', 'name', None),
diff --git a/jhbuild/modtypes/perl.py b/jhbuild/modtypes/perl.py
index 391a68d..6f18056 100644
--- a/jhbuild/modtypes/perl.py
+++ b/jhbuild/modtypes/perl.py
@@ -33,10 +33,10 @@ class PerlModule(Package):
     "Makefile.PL" Makefile."""
     type = 'perl'
 
-    STATE_CHECKOUT = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_BUILD = 'build'
-    STATE_INSTALL = 'install'
+    PHASE_CHECKOUT = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_BUILD = 'build'
+    PHASE_INSTALL = 'install'
 
     def __init__(self, name, branch, makeargs='',
                  dependencies=[], after=[], suggests=[]):
@@ -54,27 +54,14 @@ class PerlModule(Package):
     def get_revision(self):
         return self.branch.branchname
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_BUILD
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_BUILD
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
@@ -87,11 +74,8 @@ class PerlModule(Package):
         buildscript.execute(cmd, cwd=builddir, extra_env = self.extra_env)
         buildscript.execute([make, 'LD_RUN_PATH='], cwd=builddir,
                 extra_env = self.extra_env)
-    do_build.next_state = STATE_INSTALL
-    do_build.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_build.depends = [PHASE_CHECKOUT]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_install(self, buildscript):
         buildscript.set_action(_('Installing'), self)
@@ -101,8 +85,7 @@ class PerlModule(Package):
                 [make, 'install', 'PREFIX=%s' % buildscript.config.prefix],
                 cwd = builddir, extra_env = self.extra_env)
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
+    do_install.depends = [PHASE_CHECKOUT]
 
     def xml_tag_and_attrs(self):
         return 'perl', [('id', 'name', None),
diff --git a/jhbuild/modtypes/testmodule.py b/jhbuild/modtypes/testmodule.py
index 7f28d61..598586d 100644
--- a/jhbuild/modtypes/testmodule.py
+++ b/jhbuild/modtypes/testmodule.py
@@ -58,21 +58,14 @@ class TestModule(Package):
     def get_revision(self):
         return self.branch.branchname
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_TEST
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
+    do_checkout.error_phases = [STATE_FORCE_CHECKOUT]
         
     def do_force_checkout(self, buildscript):
         buildscript.set_action('Checking out', self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_TEST
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
+    do_force_checkout.error_phases = [STATE_FORCE_CHECKOUT]
 
     def _get_display(self):
         # get free display
@@ -106,9 +99,6 @@ class TestModule(Package):
             return ''
         return new_xauth
     
-    def skip_test(self, buildscript, last_state):
-        return False
-
     def do_test(self, buildscript):
         buildscript.set_action('Testing', self)
         if not buildscript.config.noxvfb:
@@ -135,9 +125,8 @@ class TestModule(Package):
                     os.environ['XAUTHORITY'] = old_xauth
                 else:
                     os.unsetenv('XAUTHORITY')
-    do_test.next_state = Package.STATE_DONE
-    do_test.error_states = []
-                
+    do_test.depends = [STATE_CHECKOUT]
+
     def get_ldtp_log_file(self, filename):
         # <ldtp>
         # |
diff --git a/jhbuild/modtypes/waf.py b/jhbuild/modtypes/waf.py
index 55f79b0..4270af4 100644
--- a/jhbuild/modtypes/waf.py
+++ b/jhbuild/modtypes/waf.py
@@ -35,14 +35,14 @@ class WafModule(Package):
     '''Base type for modules that are distributed with a WAF script.'''
     type = 'waf'
 
-    STATE_CHECKOUT       = 'checkout'
-    STATE_FORCE_CHECKOUT = 'force_checkout'
-    STATE_CLEAN          = 'clean'
-    STATE_CONFIGURE      = 'configure'
-    STATE_BUILD          = 'build'
-    STATE_CHECK          = 'check'
-    STATE_DIST           = 'dist'
-    STATE_INSTALL        = 'install'
+    PHASE_CHECKOUT       = 'checkout'
+    PHASE_FORCE_CHECKOUT = 'force_checkout'
+    PHASE_CLEAN          = 'clean'
+    PHASE_CONFIGURE      = 'configure'
+    PHASE_BUILD          = 'build'
+    PHASE_CHECK          = 'check'
+    PHASE_DIST           = 'dist'
+    PHASE_INSTALL        = 'install'
 
     def __init__(self, name, branch, dependencies=[], after=[], suggests=[],
                  waf_cmd='waf'):
@@ -59,36 +59,22 @@ class WafModule(Package):
     def get_revision(self):
         return self.branch.tree_id()
 
-    def do_start(self, buildscript):
-        pass
-    do_start.next_state = STATE_CHECKOUT
-    do_start.error_states = []
-
     def do_checkout(self, buildscript):
         self.checkout(buildscript)
-    do_checkout.next_state = STATE_CONFIGURE
-    do_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_force_checkout(self, buildscript, last_state):
-        return False
+    do_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_force_checkout(self, buildscript):
         buildscript.set_action(_('Checking out'), self)
         self.branch.force_checkout(buildscript)
-    do_force_checkout.next_state = STATE_CONFIGURE
-    do_force_checkout.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_configure(self, buildscript, last_state):
-        # skip if nobuild is set.
-        if buildscript.config.nobuild:
-            return True
+    do_force_checkout.error_phases = [PHASE_FORCE_CHECKOUT]
 
+    def skip_configure(self, buildscript, last_phase):
         # don't skip this stage if we got here from one of the
-        # following states:
-        if last_state in [self.STATE_FORCE_CHECKOUT,
-                          self.STATE_CLEAN,
-                          self.STATE_BUILD,
-                          self.STATE_INSTALL]:
+        # following phases:
+        if last_phase in [self.PHASE_FORCE_CHECKOUT,
+                          self.PHASE_CLEAN,
+                          self.PHASE_BUILD,
+                          self.PHASE_INSTALL]:
             return False
 
         # skip if the .lock-wscript file exists and we don't have the
@@ -108,37 +94,25 @@ class WafModule(Package):
         if buildscript.config.use_lib64:
             cmd += ["--libdir", os.path.join(buildscript.config.prefix, "lib64")]
         buildscript.execute(cmd, cwd=builddir)
-    do_configure.next_state = STATE_CLEAN
-    do_configure.error_states = [STATE_FORCE_CHECKOUT]
-
-    def skip_clean(self, buildscript, last_state):
-        return (not buildscript.config.makeclean or
-                buildscript.config.nobuild)
+    do_configure.depends = [PHASE_CHECKOUT]
+    do_configure.error_phases = [PHASE_FORCE_CHECKOUT]
 
     def do_clean(self, buildscript):
         buildscript.set_action(_('Cleaning'), self)
         cmd = [self.waf_cmd, 'clean']
         buildscript.execute(cmd, cwd=self.get_builddir(buildscript))
-    do_clean.next_state = STATE_BUILD
-    do_clean.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_build(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_clean.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_build(self, buildscript):
         buildscript.set_action(_('Building'), self)
         cmd = [self.waf_cmd, 'build']
         buildscript.execute(cmd, cwd=self.get_builddir(buildscript))
-    do_build.next_state = STATE_CHECK
-    do_build.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
+    do_build.depends = [PHASE_CHECKOUT]
+    do_build.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
-    def skip_check(self, buildscript, last_state):
+    def skip_check(self, buildscript, last_phase):
         if not buildscript.config.module_makecheck.get(self.name, buildscript.config.makecheck):
             return True
-        if buildscript.config.forcecheck:
-            return False
-        if buildscript.config.nobuild:
-            return True
         return False
 
     def do_check(self, buildscript):
@@ -149,11 +123,8 @@ class WafModule(Package):
         except CommandError:
             if not buildscript.config.makecheck_advisory:
                 raise
-    do_check.next_state = STATE_DIST
-    do_check.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_dist(self, buildscript, last_state):
-        return not (buildscript.config.makedist or buildscript.config.makedistcheck)
+    do_check.depends = [PHASE_BUILD]
+    do_check.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_dist(self, buildscript):
         buildscript.set_action(_('Creating tarball for'), self)
@@ -162,19 +133,15 @@ class WafModule(Package):
         else:
             cmd = [self.waf_cmd, 'dist']
         buildscript.execute(cmd, cwd=self.get_builddir(buildscript))
-    do_dist.next_state = STATE_INSTALL
-    do_dist.error_states = [STATE_FORCE_CHECKOUT, STATE_CONFIGURE]
-
-    def skip_install(self, buildscript, last_state):
-        return buildscript.config.nobuild
+    do_dist.depends = [PHASE_BUILD]
+    do_dist.error_phases = [PHASE_FORCE_CHECKOUT, PHASE_CONFIGURE]
 
     def do_install(self, buildscript):
         buildscript.set_action(_('Installing'), self)
         cmd = [self.waf_cmd, 'install']
         buildscript.execute(cmd, cwd=self.get_builddir(buildscript))
         buildscript.packagedb.add(self.name, self.get_revision() or '')
-    do_install.next_state = Package.STATE_DONE
-    do_install.error_states = []
+    do_install.depends = [PHASE_BUILD]
 
     def xml_tag_and_attrs(self):
         return 'waf', [('id', 'name', None),



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]