Changeset 3549

Show
Ignore:
Timestamp:
04/24/08 19:57:45 (7 months ago)
Author:
coderanger
Message:

Initial work on step undo support.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • tracforgeplugin/0.11/tracforge/admin/admin.py

    r3401 r3549  
    8080        cursor = db.cursor() 
    8181         
    82         cursor.execute('SELECT action, args, return FROM tracforge_project_log WHERE project=%s ORDER BY step', (data['project'],)) 
    83         for action, args, rv in cursor: 
     82        cursor.execute('SELECT action, step_direction, args, return FROM tracforge_project_log WHERE project=%s ORDER BY step', (data['project'],)) 
     83        for action, step_direction, args, rv in cursor: 
    8484            d = { 
    8585                'action': action, 
     86                'direction': step_direction, 
    8687                'args': args, 
    8788                'rv': rv == '1', 
     
    8990            } 
    9091            data['actions'].append(d) 
    91             action_map[action] = d 
     92            action_map[action,step_direction] = d 
    9293         
    93         cursor.execute('SELECT ts, action, stream, data FROM tracforge_project_output WHERE project=%s ORDER BY ts, stream DESC', (data['project'],)) 
    94         for ts, action, stream, msg in cursor: 
    95             action_map[action]['output'].append((float(ts), stream, msg)) 
     94        cursor.execute('SELECT ts, action, step_direction, stream, data FROM tracforge_project_output WHERE project=%s ORDER BY ts, stream DESC', (data['project'],)) 
     95        for ts, action, step_direction, stream, msg in cursor: 
     96            action_map[action, step_direction]['output'].append((float(ts), stream, msg)) 
    9697         
    9798        return 'admin_tracforge_project.html', data 
  • tracforgeplugin/0.11/tracforge/admin/api.py

    r3476 r3549  
    3333    def execute_setup_action(action, args, data, log_cb): 
    3434        """Perform the given setup action on an environment.""" 
     35     
     36    def undo_setup_action(action, args, data, log_cb): 
     37        """Reverse the given setup action.""" 
    3538     
    3639class IProjectChangeListener(Interface): 
  • tracforgeplugin/0.11/tracforge/admin/db_default.py

    r3394 r3549  
    22 
    33name = 'tracforge.admin' 
    4 version = 10 
     4version = 13 
    55tables = [ 
    66    Table('tracforge_projects', key='name')[ 
    77        Column('name'), 
    88        Column('env_path'), 
     9        Column('status'), 
    910    ], 
    10     Table('tracforge_project_log', key=('project', 'action'))[ 
     11    Table('tracforge_project_log', key=('project', 'direction', 'action', 'step_direction'))[ 
    1112        Column('project'), 
    1213        Column('step', type='integer'), 
     14        Column('direction'), 
    1315        Column('action'), 
     16        Column('step_direction'), 
    1417        Column('args'), 
    1518        Column('return'), 
     19        Column('undone', type='integer'), 
    1620    ], 
    17     Table('tracforge_project_output', key=('ts', 'project', 'action', 'stream'))[ 
     21    Table('tracforge_project_output', key=('ts', 'project', 'direction', 
     22                                           'action', 'step_direction', 'stream'))[ 
    1823        Column('ts'), 
    1924        Column('project'), 
     25        Column('direction'), 
    2026        Column('action'), 
    2127        Column('stream'), 
     28        Column('step_direction'), 
    2229        Column('data'), 
    2330    ], 
  • tracforgeplugin/0.11/tracforge/admin/model.py

    r3421 r3549  
    11from trac.env import open_environment 
    22from trac.config import Configuration, Section 
    3 from trac.util.compat import set, all 
     3from trac.util.compat import set, all, reversed 
    44 
    55from UserDict import DictMixin 
     
    174174    """A file-like object to replace sys.stdout/err.""" 
    175175     
    176     def __init__(self, cursor, project, action, stream): 
     176    def __init__(self, cursor, project, direction, action, stream, step_direction): 
    177177        self.cursor = cursor 
    178178        self.project = project 
     179        self.direction = direction 
    179180        self.action = action 
    180181        self.stream = stream 
     182        self.step_direction = step_direction 
    181183 
    182184    def write(self, msg): 
    183185        self.cursor.execute('INSERT INTO tracforge_project_output ' \ 
    184             '(ts, project, action, stream, data) VALUES (%s, %s, %s, %s, %s)', 
    185             (time.time(), self.project, self.action, self.stream, msg)) 
     186            '(ts, project, direction, action, stream, step_direction, data) VALUES (%s, %s, %s, %s, %s, %s, %s)', 
     187            (time.time(), self.project, self.direction, self.action, self.stream, self.step_direction, msg)) 
    186188 
    187189 
     
    240242        return False         
    241243 
    242     def execute(self, data): 
     244    def execute(self, data, direction='execute', project=None): 
    243245        """Run this prototype on a new project. 
    244246        NOTE: If you pass in a project that isn't new, this could explode. Don't do that. 
     
    247249        steps = TracForgeAdminSystem(self.env).get_project_setup_participants() 
    248250         
     251        # Store this for later 
     252        orig_direction = direction 
     253         
    249254        # Clear out the last attempt at making this project, if any 
    250255        db = self.env.get_db_cnx() 
    251256        cursor = db.cursor() 
    252         cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s', (data['name'],)) 
    253         cursor.execute('DELETE FROM tracforge_project_output WHERE project=%s', (data['name'],)) 
     257        cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s AND direction=%s', (data['name'], direction)) 
     258        cursor.execute('DELETE FROM tracforge_project_output WHERE project=%s AND direction=%s', (data['name'], direction)) 
    254259        db.commit() 
    255260         
     
    257262        old_stdout = sys.stdout 
    258263        old_stderr = sys.stderr 
    259  
    260         for i, (action, args) in enumerate(self): 
    261             cursor.execute('INSERT INTO tracforge_project_log (project, step, action, args) VALUES (%s, %s, %s, %s)', 
    262                            (data['name'], i, action, args)) 
     264         
     265        if direction == 'execute': 
     266            run_buffer = [(action, args, 'execute') for action, args in self] 
     267        else: 
     268            cursor.execute('SELECT action, args WHERE project=%s AND direction=%s AND undone=%s ORDER BY step DESC', 
     269                           (project, direction, 0)) 
     270            run_buffer = [(action, args, 'undo') for action, args in cursor] 
     271 
     272        for i, (action, args, step_direction) in enumerate(run_buffer): 
     273            #print data['name'], orig_direction, action, step_direction 
     274            cursor.execute('INSERT INTO tracforge_project_log (project, step, direction, action, step_direction, args, undone) VALUES (%s, %s, %s, %s, %s, %s, %s)', 
     275                           (data['name'], i, orig_direction, action, step_direction, args, 0)) 
    263276            db.commit() 
    264277            def log_cb(stdout, stderr): 
    265278                now = time.time() 
    266                 #print '!', stdout, '!', stderr 
     279                #print '!'1, stdout, '!', stderr 
    267280                values = [] 
    268281                if stdout: 
    269                     values.append((now, data['name'], action, 'stdout', stdout)) 
     282                    values.append((now, data['name'], orig_direction, action, 'stdout', step_direction, stdout)) 
    270283                if stderr: 
    271                     values.append((now, data['name'], action, 'stderr', stderr)) 
     284                    values.append((now, data['name'], orig_direction, action, 'stderr', step_direction, stderr)) 
    272285                if values: 
    273286                    cursor.executemany('INSERT INTO tracforge_project_output ' \ 
    274                                  '(ts, project, action, stream, data) VALUES ' \ 
    275                                  '(%s, %s, %s, %s, %s)', 
     287                                 '(ts, project, direction, action, stream, step_direction, data) VALUES ' \ 
     288                                 '(%s, %s, %s, %s, %s, %s, %s)', 
    276289                     values) 
    277290                    db.commit() 
    278291            if getattr(steps[action]['provider'], 'capture_output', True): 
    279                 sys.stdout = _CaptureOutput(cursor, data['name'], action, 'stdout'
    280                 sys.stderr = _CaptureOutput(cursor, data['name'], action, 'stderr'
     292                sys.stdout = _CaptureOutput(cursor, data['name'], orig_direction, action, 'stdout', step_direction
     293                sys.stderr = _CaptureOutput(cursor, data['name'], orig_direction, action, 'stderr', step_direction
    281294            try: 
    282                 rv = steps[action]['provider'].execute_setup_action(action, args, data, log_cb) 
     295                rv = getattr(steps[action]['provider'], step_direction+'_setup_action')(action, args, data, log_cb) 
    283296            except Exception, e: 
    284297                log_cb('', traceback.format_exc()) 
    285298                rv = False 
    286             cursor.execute('UPDATE tracforge_project_log SET return=%s WHERE project=%s AND action=%s', 
    287                             (rv, data['name'], action)) 
    288             db.commit() 
     299            cursor.execute('UPDATE tracforge_project_log SET return=%s WHERE project=%s AND direction=%s AND action=%s AND step_direction=%s', 
     300                            (int(rv), data['name'], orig_direction, action, step_direction)) 
     301            db.commit() 
     302             
     303            if not rv and direction == 'execute': 
     304                # Failure, initiate rollback 
     305                direction = 'undo' 
     306                del run_buffer[i+1:] 
     307                run_buffer.extend([(action, args, 'undo') for action, args, _ in reversed(run_buffer)]) 
    289308         
    290309        sys.stdout = old_stdout 
  • tracforgeplugin/0.11/tracforge/admin/prototypes_admin.py

    r3425 r3549  
    116116                proto.append((req.args['type'], '')) 
    117117            elif 'save' in req.args: 
    118                 proto.tag = data['name'] 
     118                proto.tag = (action == 'new' and req.args['name'] or data['name']).strip() 
     119                if not proto.tag or proto.tag == 'new': 
     120                    raise TracError('Invalid prototype name "%s"', proto.tag) 
    119121                proto.save() 
    120122                req.redirect(req.href.admin('tracforge/prototypes', proto.tag)) 
     
    122124                req.redirect(req.href.admin('tracforge/prototypes')) 
    123125            elif 'delete' in req.args: 
    124                 proto.tag = data['name'] 
     126                proto.tag = data['name'] 
    125127                proto.delete() 
    126128                req.redirect(req.href.admin('tracforge/prototypes')) 
  • tracforgeplugin/0.11/tracforge/admin/prototypes.py

    r3426 r3549  
    44import os 
    55import os.path 
     6import shutil 
    67import time 
    78import stat 
     
    4849        raise NotImplementedError 
    4950     
     51    def undo_setup_action(self, action, args, data, log_cb): 
     52        pass 
     53     
    5054    def call_external(self, log_cb, executable, *args): 
    5155        path = executable 
     
    8892        data['env'] = open_environment(path, use_cache=True) 
    8993        return rv == 0 
     94     
     95    def undo_setup_action(self, action, args, data, log_cb): 
     96        if '%s' not in args: 
     97            args = os.path.join(args, '%s') 
     98        path = args%data['name'] 
     99         
     100        print 'Removing %s'%path 
     101        try: 
     102            shutil.rmtree(path) 
     103            print 'Successful' 
     104            return True 
     105        except os.error, e: 
     106            print >>sys.stderr,'Error:' 
     107            print >>sys.stderr, e 
     108            return False 
    90109 
    91110 
     
    128147class DoNothingAction(ProjectSetupParticipantBase): 
    129148    """Do nothing, just like it says..""" 
    130      
    131     provides = ['foo'] 
    132      
    133     depends = ['foo'] 
    134149     
    135150    def execute_setup_action(self, action, args, data, log_cb): 
     
    227242            os.chmod(hook_file, os.stat(hook_file).st_mode|stat.S_IXUSR) 
    228243        return hookf, trachook_file 
     244 
     245 
     246class TestOneAction(ProjectSetupParticipantBase): 
     247    """For testing.""" 
     248     
     249    execute_text = 'Running execute' 
     250    execute_rv = True 
     251    undo_text = 'Running undo' 
     252    undo_rv = True 
     253     
     254    def execute_setup_action(self, action, args, data, log_cb): 
     255        from trac.env import open_environment 
     256        data['env'] = open_environment('/Users/coderanger/trac/install/trunk/tracs/tf_master', use_cache=True) 
     257        print self.execute_text 
     258        return self.execute_rv 
     259     
     260    def undo_setup_action(self, action, args, data, log_cb): 
     261        print self.undo_text 
     262        return self.undo_rv 
     263 
     264class TestTwoAction(TestOneAction): 
     265    execute_text = 'Running execute in two' 
     266    undo_rv = False 
     267 
     268class TestThreeAction(TestOneAction): 
     269    execute_rv = False 
     270     
     271class TestFourAction(TestOneAction): 
     272    execute_rv = False 
  • tracforgeplugin/0.11/tracforge/templates/admin_tracforge_project.html

    r3394 r3549  
    2121    <h2>Project View: $project</h2> 
    2222    <div py:for="step in actions"> 
    23       <h3>$step.action($step.args) = ${step.rv and 'Pass' or 'Fail'}</h3> 
     23      <h3>${step.direction.title()} $step.action($step.args) = ${step.rv and 'Pass' or 'Fail'}</h3> 
    2424      <table id="project-output"> 
    2525        <tr py:for="ts, stream, data in step.output" class="$stream">