Beispiel #1
0
 def default(cls, env):
     """Return a prototype for the defaults on the new prototype screen."""
     from api import TracForgeAdminSystem
     steps = TracForgeAdminSystem(env).get_project_setup_participants()
     
     proto = cls(env, '')
     for action, info in steps.iteritems():
         default = info['provider'].get_setup_action_default(action, env)
         if default is not None:
             proto.append((action, default))
     env.log.debug('TracForge: %s', proto)
     proto.sort()
     return proto
Beispiel #2
0
 def sort(self):
     """Do an in-place topological sort of this prototype."""
     from api import TracForgeAdminSystem
     steps = TracForgeAdminSystem(self.env).get_project_setup_participants()
     
     all_provides = set()
     for action, args in self:
         all_provides |= set(steps[action].get('provides', ()))
     
     effective_depends = {}
     for action, args in self:
         # All real deps are always used
         effective_depends.setdefault(action, []).extend(steps[action].get('depends', ()))
         for tag in steps[action].get('optional_depends', ()):
             # Any optional dep that is provided by something else is used
             if tag in all_provides:
                 effective_depends[action].append(tag)
     
     old = set([action for action, args in self])
     new = []
     tags = set()
     for i in xrange(len(self)):
         for action in old:
             self.env.log.debug('TracForge: %s %s %s %s %s', i, action, old, new, tags)
             if all([tag in tags for tag in effective_depends[action]]):
                 new.append(action)
                 tags |= set(steps[action].get('provides', []))
                 old.remove(action)
                 break
         if not old:
             break
     if old:
         raise ValueError('Cant solve')
     action_map = dict(self)
     self[:] = [(action, action_map[action]) for action in new]
Beispiel #3
0
    def apply(self, req, proj):
        """Run this prototype on a new project.
        NOTE: If you pass in a project that isn't new, this could explode. Don't do that.
        """
        from api import TracForgeAdminSystem
        steps = TracForgeAdminSystem(self.env).get_project_setup_participants()

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s',
                       (proj.name, ))
        db.commit()

        for step in self:
            action = args = None
            if isinstance(step, dict):
                action = step['action']
                args = step['args']
            else:
                action, args = step

            pid = os.fork()
            if not pid:
                #o_fd, o_file = mkstemp('tracforge-step', text=True)
                #e_fd, e_file = mkstemp('tracforge-step', text=True)

                o_file = TemporaryFile(prefix='tracforge-step', bufsize=0)
                e_file = TemporaryFile(prefix='tracforge-step', bufsize=0)

                sys.stdout = o_file
                sys.stderr = e_file

                os.dup2(o_file.fileno(), 1)
                os.dup2(e_file.fileno(), 2)

                rv = steps[action]['provider'].execute_setup_action(
                    req, proj, action, args)
                self.env.log.debug('TracForge: %s() => %r', action, rv)

                o_file.seek(0, 0)
                o_data = o_file.read()
                o_file.close()
                e_file.seek(0, 0)
                e_data = e_file.read()
                e_file.close()

                db = self.env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute(
                    'INSERT INTO tracforge_project_log (project, action, args, return, stdout, stderr) VALUES (%s, %s, %s, %s, %s, %s)',
                    (proj.name, action, args, int(rv), o_data, e_data))
                db.commit()
                db.close()

                os._exit(0)
        os.waitpid(pid, 0)
    def _show_prototype(self, req, path_info, action):
        """Handler for creating a new prototype."""
        add_stylesheet(req, 'tracforge/css/prototypes_new.css')
        add_script(req, 'tracforge/js/interface/iutil.js')
        add_script(req, 'tracforge/js/jquery.animatedswap.js')
        req.hdf['tracforge.prototypes.name'] = path_info.strip('/')

        if req.method == 'POST':
            if req.args.get(
                    'save'
            ):  # Save either a new prototype or a changed existing ones
                name = req.args.get('name')
                if action == 'edit':
                    name = path_info.strip('/')
                if not name:
                    raise TracError(
                        'You must specify a name for the prototype')
                if name in ('new', 'configset'):
                    raise TracError('"new" and "configset" are reserved names')

                data = req.args.get('data')
                if data is None:
                    raise TracError(
                        "Warning: Peguins on fire. You might have JavaScript off, don't do that"
                    )
                data = data[4:]  # Strip off the 'data' literal at the start
                if not data:
                    raise TracError(
                        "You must have at least one step in a prototype")

                proto = Prototype(self.env, name)
                if action == 'new' and proto.exists:
                    raise TracError("Prototype %s already exists" % name)
                del proto[:]
                for x in data.split('|'):
                    proto.append(x.split(',', 1))
                proto.save()
            elif req.args.get('cancel'):
                pass  # This should just redirect back
            elif req.args.get(
                    'delete'
            ) and action == 'edit':  # Show the confirmation screen
                return 'admin_tracforge_prototypes_delete.cs', None
            elif req.args.get(
                    'reallydelete'
            ) and action == 'edit':  # Actually delete this prototype
                name = path_info.strip('/')
                proto = Prototype(self.env, name)
                if not proto.exists:
                    raise TracError('Prototype %s does not exist' % name)
                proto.delete()
            req.redirect(req.href.admin(req.cat, req.page))

        #steps = {}
        #for p in self.setup_participants:
        #    for a in p.get_setup_actions():
        #        steps[a] = {
        #            'provider': p,
        #            'description': p.get_setup_action_description(a),
        #        }
        steps = TracForgeAdminSystem(self.env).get_project_setup_participants()

        initial_steps = []
        if action == 'new':  # For a new one, use the specified defaults
            initial_steps = Prototype.default(
                self.env)  # XXX: This should really read from trac.ini somehow
        elif action == 'edit':
            proto = Prototype(self.env, path_info.strip('/'))
            if not proto.exists:
                raise TracError('Unknown prototype %s' % proto.tag)
            initial_steps = proto
        else:
            raise TracError('Invalid action %s' % action)

        req.hdf['tracforge.prototypes.action'] = action
        req.hdf['tracforge.prototypes.steps'] = steps
        req.hdf['tracforge.prototypes.initialsteps'] = initial_steps
        req.hdf['tracforge.prototypes.liststeps'] = [
            k for k in steps.iterkeys() if k not in initial_steps
        ]

        return 'admin_tracforge_prototypes_show.cs', None
Beispiel #5
0
    def _show_prototype(self, req, path_info, action):
        """Handler for creating a new prototype."""
        add_stylesheet(req, 'tracforge/css/prototypes_new.css')
        add_script(req, 'tracforge/js/interface/iutil.js')
        add_script(req, 'tracforge/js/jquery.animatedswap.js')
        req.hdf['tracforge.prototypes.name'] = path_info.strip('/')
        
        if req.method == 'POST':
            if req.args.get('save'): # Save either a new prototype or a changed existing ones
                name = req.args.get('name')
                if action == 'edit':
                    name = path_info.strip('/')
                if not name:
                    raise TracError('You must specify a name for the prototype')
                if name in ('new', 'configset'):
                    raise TracError('"new" and "configset" are reserved names')
            
                data = req.args.get('data')
                if data is None:
                    raise TracError("Warning: Peguins on fire. You might have JavaScript off, don't do that")
                data = data[4:] # Strip off the 'data' literal at the start
                if not data:
                    raise TracError("You must have at least one step in a prototype")
                
                proto = Prototype(self.env, name)
                if action == 'new' and proto.exists:
                    raise TracError("Prototype %s already exists"%name)
                del proto[:]
                for x in data.split('|'):
                    proto.append(x.split(',',1))
                proto.save()
            elif req.args.get('cancel'): 
                pass # This should just redirect back
            elif req.args.get('delete') and action == 'edit': # Show the confirmation screen
                return 'admin_tracforge_prototypes_delete.cs', None
            elif req.args.get('reallydelete') and action == 'edit': # Actually delete this prototype
                name = path_info.strip('/')
                proto = Prototype(self.env, name)
                if not proto.exists:
                    raise TracError('Prototype %s does not exist'%name)
                proto.delete()
            req.redirect(req.href.admin(req.cat, req.page))

        #steps = {}
        #for p in self.setup_participants:
        #    for a in p.get_setup_actions():
        #        steps[a] = {
        #            'provider': p,
        #            'description': p.get_setup_action_description(a),
        #        }
        steps = TracForgeAdminSystem(self.env).get_project_setup_participants()
        
        initial_steps = []        
        if action == 'new': # For a new one, use the specified defaults 
            initial_steps = Prototype.default(self.env) # XXX: This should really read from trac.ini somehow
        elif action == 'edit': 
            proto = Prototype(self.env, path_info.strip('/'))
            if not proto.exists:
                raise TracError('Unknown prototype %s'%proto.tag)
            initial_steps = proto
        else:
            raise TracError('Invalid action %s'%action)

        req.hdf['tracforge.prototypes.action'] = action
        req.hdf['tracforge.prototypes.steps'] = steps
        req.hdf['tracforge.prototypes.initialsteps'] = initial_steps
        req.hdf['tracforge.prototypes.liststeps'] = [k for k in steps.iterkeys() if k not in initial_steps]
        
        return 'admin_tracforge_prototypes_show.cs', None
Beispiel #6
0
    def execute(self, data, direction='execute', project=None):
        """Run this prototype on a new project.
        NOTE: If you pass in a project that isn't new, this could explode. Don't do that.
        """
        from api import TracForgeAdminSystem
        steps = TracForgeAdminSystem(self.env).get_project_setup_participants()
        
        # Store this for later
        orig_direction = direction
        
        # Clear out the last attempt at making this project, if any
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s AND direction=%s', (data['name'], direction))
        cursor.execute('DELETE FROM tracforge_project_output WHERE project=%s AND direction=%s', (data['name'], direction))
        db.commit()
        
        # Grab the current stdout/err
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        
        if direction == 'execute':
            run_buffer = [(action, args, 'execute') for action, args in self]
        else:
            cursor.execute('SELECT action, args WHERE project=%s AND direction=%s AND undone=%s ORDER BY step DESC',
                           (project, direction, 0))
            run_buffer = [(action, args, 'undo') for action, args in cursor]

        for i, (action, args, step_direction) in enumerate(run_buffer):
            #print data['name'], orig_direction, action, step_direction
            cursor.execute('INSERT INTO tracforge_project_log (project, step, direction, action, step_direction, args, undone) VALUES (%s, %s, %s, %s, %s, %s, %s)',
                           (data['name'], i, orig_direction, action, step_direction, args, 0))
            db.commit()
            def log_cb(stdout, stderr):
                now = time.time()
                #print '!'1, stdout, '!', stderr
                values = []
                if stdout:
                    values.append((now, data['name'], orig_direction, action, 'stdout', step_direction, stdout))
                if stderr:
                    values.append((now, data['name'], orig_direction, action, 'stderr', step_direction, stderr))
                if values:
                    cursor.executemany('INSERT INTO tracforge_project_output ' \
                                 '(ts, project, direction, action, stream, step_direction, data) VALUES ' \
                                 '(%s, %s, %s, %s, %s, %s, %s)',
                     values)
                    db.commit()
            if getattr(steps[action]['provider'], 'capture_output', True):
                sys.stdout = _CaptureOutput(cursor, data['name'], orig_direction, action, 'stdout', step_direction)
                sys.stderr = _CaptureOutput(cursor, data['name'], orig_direction, action, 'stderr', step_direction)
            try:
                rv = getattr(steps[action]['provider'], step_direction+'_setup_action')(action, args, data, log_cb)
            except Exception, e:
                log_cb('', traceback.format_exc())
                rv = False
            cursor.execute('UPDATE tracforge_project_log SET return=%s WHERE project=%s AND direction=%s AND action=%s AND step_direction=%s',
                            (int(rv), data['name'], orig_direction, action, step_direction))
            db.commit()
            
            if not rv and direction == 'execute':
                # Failure, initiate rollback
                direction = 'undo'
                del run_buffer[i+1:]
                run_buffer.extend([(action, args, 'undo') for action, args, _ in reversed(run_buffer)])