Changeset 3394

Show
Ignore:
Timestamp:
03/18/08 18:30:49 (9 months ago)
Author:
coderanger
Message:

Project creation from the web now works!!!

Files:

Legend:

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

    r3377 r3394  
    3939        ], 
    4040        'console_scripts': [ 
    41             'tracforge-helper = tracforge.admin.constructor:main', 
     41            'tracforge-helper = tracforge.admin.helper:main', 
    4242        ], 
    4343    }, 
  • tracforgeplugin/0.11/tracforge/admin/admin.py

    r3377 r3394  
    11# Created by Noah Kantrowitz on 2008-02-19. 
    22# Copyright (c) 2008 Noah Kantrowitz. All rights reserved. 
     3import os 
    34import os.path 
    45 
     
    67from trac.admin.api import IAdminPanelProvider 
    78from trac.web.chrome import add_script 
     9from trac.config import Option 
    810from trac.util.compat import sorted 
    911 
     
    1214class TracForgeAdminModule(Component): 
    1315    """A module to manage projects in TracForge.""" 
     16 
     17    helper_script = Option('tracforge', 'helper_script', default='tracforge-helper', 
     18                           doc='Path to the tracforge-helper script, possibly' 
     19                               'utilizing sudo or similar wrappers.') 
    1420 
    1521    implements(IAdminPanelProvider)     
     
    2127             
    2228    def render_admin_panel(self, req, cat, page, path_info): 
     29        if path_info: 
     30            return self._render_project_view(req, cat, page, path_info) 
     31         
    2332        data = {} 
    2433         
     
    2635            if 'create' in req.args.keys(): # Project creation 
    2736                name = req.args.get('shortname', '').strip() 
    28                 fullname = req.args.get('fullname', '').strip() 
     37                full_name = req.args.get('fullname', '').strip() 
    2938                env_path = req.args.get('env_path', '').strip() 
    3039                proto_name = req.args.get('prototype', '').strip() 
    31                 if not (name and fullname and env_path and proto_name): 
     40                if not (name and full_name and env_path and proto_name): 
    3241                    raise TracError('All arguments are required') 
    3342                 
    3443                # Make the models 
    35                 proj = Project(self.env, name) 
    3644                proto = Prototype(self.env, proto_name) 
    3745                if not proto.exists: 
    3846                    raise TracError('Penguins on fire') 
    3947                 
    40                 # Store the project 
    41                 proj.env_path = env_path 
    42                 proj.save() 
     48                # Use $PATH on non-Win32 
     49                if os.name == 'nt': 
     50                    spawn = os.spawnv 
     51                else: 
     52                    spawn = os.spawnvp 
    4353                 
    44                 # Apply the prototype 
    45                 proto.apply(req, proj) 
     54                # Spawn the helper script 
     55                helper = self.helper_script.split() 
     56                helper += [self.env.path, proto_name, name, full_name, env_path] 
     57                helper.insert(1, os.path.basename(helper[0])) 
     58                spawn(os.P_NOWAIT, helper.pop(0), helper) 
    4659                 
    47                 db = self.env.get_db_cnx() 
    48                 cursor = db.cursor() 
    49                 cursor.execute('SELECT action, args, return, stdout, stderr FROM tracforge_project_log WHERE project=%s ORDER BY id',(proj.name,)) 
    50                  
    51                 output = [] 
    52                 for action, args, rv, out, err in cursor: 
    53                     output.append({ 
    54                         'action': action, 
    55                         'args': args, 
    56                         'rv': rv, 
    57                         'out': out.splitlines(), 
    58                         'err': err.splitlines(), 
    59                     }) 
    60                          
    61                 req.hdf['tracforge.output'] = output 
    62                 req.hdf['tracforge.href.projects'] = req.href.admin(cat, page) 
    63                 #req.args['hdfdump'] = 1 
    64                 return 'admin_tracforge_project_new.cs', None 
    65                 req.redirect(req.href.admin(cat, page)) 
     60                # Redirect to the watcher page 
     61                req.redirect(req.href.admin(cat, page, name)) 
    6662            elif 'delete' in req.args.keys(): # Project deleteion 
    6763                raise TracError, 'Not implemented yet. Sorry.' 
     
    7369        add_script(req, 'tracforge/js/typewatch1.1.js') 
    7470        return 'admin_tracforge_projects.html', data 
    75               
     71 
     72    def _render_project_view(self, req, cat, page, path_info): 
     73        data = { 
     74            'project': path_info, 
     75            'actions': [], 
     76        } 
     77        action_map = {} 
     78         
     79        db = self.env.get_db_cnx() 
     80        cursor = db.cursor() 
     81         
     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: 
     84            d = { 
     85                'action': action, 
     86                'args': args, 
     87                'rv': rv == '1', 
     88                'output': [], 
     89            } 
     90            data['actions'].append(d) 
     91            action_map[action] = d 
     92         
     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)) 
     96         
     97        return 'admin_tracforge_project.html', data 
  • tracforgeplugin/0.11/tracforge/admin/api.py

    r2635 r3394  
    1313        """Return a string description of the given action.""" 
    1414         
    15     def execute_setup_action(self, req, proj, action, args): 
     15    def execute_setup_action(self, action, args, data, log_cb): 
    1616        """Perform the given setup action on an environment.""" 
    1717     
  • tracforgeplugin/0.11/tracforge/admin/db_default.py

    r3377 r3394  
    22 
    33name = 'tracforge.admin' 
    4 version = 8 
     4version = 10 
    55tables = [ 
    66    Table('tracforge_projects', key='name')[ 
     
    99    ], 
    1010    Table('tracforge_project_log', key=('project', 'action'))[ 
    11         Column('id', auto_increment=True), 
    1211        Column('project'), 
     12        Column('step', type='integer'), 
    1313        Column('action'), 
    1414        Column('args'), 
    1515        Column('return'), 
    16         Column('stdout'), 
    17         Column('stderr'), 
    1816    ], 
    19 #    Table('tracforge_project_output', key=('ts' 
     17    Table('tracforge_project_output', key=('ts', 'project', 'action', 'stream'))[ 
     18        Column('ts'), 
     19        Column('project'), 
     20        Column('action'), 
     21        Column('stream'), 
     22        Column('data'), 
     23    ], 
    2024    Table('tracforge_members', key=('project', 'username'))[ 
    2125        Column('project'), 
  • tracforgeplugin/0.11/tracforge/admin/helper.py

    r3378 r3394  
    44 
    55import pkg_resources 
    6 pkg_resource.require('Trac') 
     6pkg_resources.require('Trac') 
    77 
    88from trac.env import open_environment 
     
    1616    # Load initial parameters from the command-line 
    1717    master_path = argv[0] 
    18     prototype_name = argv[1], 
     18    prototype_name = argv[1] 
    1919    data = { 
    2020        'name': argv[2], 
  • tracforgeplugin/0.11/tracforge/admin/__init__.py

    r3377 r3394  
    1 #import api 
     1import api 
    22import admin 
    33#import membership 
    44#import perm 
    55#import perm_admin 
    6 #import prototypes 
     6import prototypes 
    77#import prototypes_admin 
    88#import dispatch 
  • tracforgeplugin/0.11/tracforge/admin/model.py

    r3377 r3394  
    33 
    44from UserDict import DictMixin 
    5 from tempfile import mkstemp, TemporaryFile 
    65import os 
    76import sys 
     7import time 
     8import traceback 
    89 
    910class BadEnv(object): 
     
    168169 
    169170 
     171class _CaptureOutput(object): 
     172    """A file-like object to replace sys.stdout/err.""" 
     173     
     174    def __init__(self, cursor, project, action, stream): 
     175        self.cursor = cursor 
     176        self.project = project 
     177        self.action = action 
     178        self.stream = stream 
     179 
     180    def write(self, msg): 
     181        self.cursor.execute('INSERT INTO tracforge_project_output ' \ 
     182            '(ts, project, action, stream, data) VALUES (%s, %s, %s, %s, %s)', 
     183            (time.time(), self.project, self.action, self.stream, msg)) 
     184 
     185 
    170186class Prototype(list): 
    171187    """A model object for a project prototype.""" 
     
    180196         
    181197        cursor.execute('SELECT action, args FROM tracforge_prototypes WHERE tag=%s ORDER BY step', (self.tag,)) 
    182         list.__init__(self,[{'action':action, 'args':args} for action,args in cursor.fetchall()]
     198        list.__init__(self, cursor
    183199 
    184200    exists = property(lambda self: len(self)>0) 
     
    222238        return False         
    223239 
    224     def apply(self, req, proj): 
     240    def execute(self, data): 
    225241        """Run this prototype on a new project. 
    226242        NOTE: If you pass in a project that isn't new, this could explode. Don't do that. 
     
    229245        steps = TracForgeAdminSystem(self.env).get_project_setup_participants() 
    230246         
     247        # Clear out the last attempt at making this project, if any 
    231248        db = self.env.get_db_cnx() 
    232249        cursor = db.cursor() 
    233         cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s', (proj.name,)) 
     250        cursor.execute('DELETE FROM tracforge_project_log WHERE project=%s', (data['name'],)) 
     251        cursor.execute('DELETE FROM tracforge_project_output WHERE project=%s', (data['name'],)) 
    234252        db.commit() 
    235  
    236         for step in self: 
    237             action = args = None 
    238             if isinstance(step, dict): 
    239                 action = step['action'] 
    240                 args = step['args'] 
    241             else: 
    242                 action, args = step 
    243                  
    244             pid = os.fork() 
    245             if not pid: 
    246                 #o_fd, o_file = mkstemp('tracforge-step', text=True) 
    247                 #e_fd, e_file = mkstemp('tracforge-step', text=True) 
    248                  
    249                 o_file = TemporaryFile(prefix='tracforge-step', bufsize=0) 
    250                 e_file = TemporaryFile(prefix='tracforge-step', bufsize=0) 
    251                  
    252                 sys.stdout = o_file 
    253                 sys.stderr = e_file 
    254                  
    255                 os.dup2(o_file.fileno(), 1) 
    256                 os.dup2(e_file.fileno(), 2) 
    257              
    258                 rv = steps[action]['provider'].execute_setup_action(req, proj, action, args) 
    259                 self.env.log.debug('TracForge: %s() => %r', action, rv) 
    260                  
    261                 o_file.seek(0,0) 
    262                 o_data = o_file.read() 
    263                 o_file.close() 
    264                 e_file.seek(0,0) 
    265                 e_data = e_file.read() 
    266                 e_file.close() 
    267                  
    268                 db = self.env.get_db_cnx() 
    269                 cursor = db.cursor() 
    270                 cursor.execute('INSERT INTO tracforge_project_log (project, action, args, return, stdout, stderr) VALUES (%s, %s, %s, %s, %s, %s)', 
    271                                (proj.name, action, args, int(rv), o_data, e_data)) 
    272                 db.commit() 
    273                 db.close() 
    274                  
    275                 os._exit(0) 
    276         os.waitpid(pid, 0) 
     253         
     254        # Grab the current stdout/err 
     255        old_stdout = sys.stdout 
     256        old_stderr = sys.stderr 
     257 
     258        for i, (action, args) in enumerate(self): 
     259            cursor.execute('INSERT INTO tracforge_project_log (project, step, action, args) VALUES (%s, %s, %s, %s)', 
     260                           (data['name'], i, action, args)) 
     261            db.commit() 
     262            def log_cb(stdout, stderr): 
     263                now = time.time() 
     264                #print '!', stdout, '!', stderr 
     265                values = [] 
     266                if stdout: 
     267                    values.append((now, data['name'], action, 'stdout', stdout)) 
     268                if stderr: 
     269                    values.append((now, data['name'], action, 'stderr', stderr)) 
     270                if values: 
     271                    cursor.executemany('INSERT INTO tracforge_project_output ' \ 
     272                                 '(ts, project, action, stream, data) VALUES ' \ 
     273                                 '(%s, %s, %s, %s, %s)', 
     274                     values) 
     275                    db.commit() 
     276            if getattr(steps[action]['provider'], 'capture_output', True): 
     277                sys.stdout = _CaptureOutput(cursor, data['name'], action, 'stdout') 
     278                sys.stderr = _CaptureOutput(cursor, data['name'], action, 'stderr') 
     279            try: 
     280                rv = steps[action]['provider'].execute_setup_action(action, args, data, log_cb) 
     281            except Exception, e: 
     282                log_cb('', traceback.format_exc()) 
     283                rv = False 
     284            cursor.execute('UPDATE tracforge_project_log SET return=%s WHERE project=%s AND action=%s', 
     285                            (rv, data['name'], action)) 
     286            db.commit() 
     287         
     288        sys.stdout = old_stdout 
     289        sys.stderr = old_stderr 
    277290 
    278291 
  • tracforgeplugin/0.11/tracforge/admin/prototypes.py

    r1615 r3394  
    11# Utility classes for the TracForge prototypes system 
    2 from trac.core import * 
    3 from api import IProjectSetupParticipant 
    4  
    52import inspect 
    63import sys 
    74import os 
     5import os.path 
    86import time 
     7 
     8from trac.core import * 
     9 
     10from tracforge.admin.api import IProjectSetupParticipant 
     11from tracforge.admin.util import CommandLine, locate 
    912 
    1013class ProjectSetupParticipantBase(Component): 
     
    2528        return inspect.getdoc(self.__class__) 
    2629         
    27     def execute_setup_action(self, req, proj, action, args): 
     30    def execute_setup_action(self, action, args, data, log_cb): 
    2831        raise NotImplementedError 
     32 
     33    def call_external(self, log_cb, executable, *args): 
     34        path = executable 
     35        if not os.path.isabs(path): 
     36            path = locate(path) 
     37        if path is None: 
     38            log_cb('', 'Unable to locate %s'%executable) 
     39            return False 
     40        cl = CommandLine(path, args) 
     41        for stdout, stderr in cl.execute(): 
     42            log_cb(stdout, stderr) 
     43        return cl.returncode == 0 
     44 
    2945 
    3046class MakeTracEnvironmentAction(ProjectSetupParticipantBase): 
    3147    """DO NOT USE. Make a new Trac environment using trac-admin initenv.""" 
    32      
    33     def execute_setup_action(self, req, proj, action, args): 
    34         repo_type = hasattr(proj, 'repo_type') and proj.repo_type or 'svn' 
    35         repo_path = hasattr(proj, 'repo_path') and proj.repo_path or '' 
    36      
    37         from trac.config import default_dir 
    38         from trac.scripts.admin import run 
    39         return run([proj.env_path,  
     48    #capture_output = False 
     49    def execute_setup_action(self, action, args, data, log_cb): 
     50        from trac.admin.console import run 
     51         
     52        return run([data['path'],  
    4053                    'initenv',  
    41                     req.args.get('fullname','').strip(),  
     54                    data['full_name'],  
    4255                    'sqlite:db/trac.db',  
    43                     repo_type.strip(),  
    44                     repo_path.strip(),  
    45                     default_dir('templates'), 
     56                    data.get('repo_type', ''), 
     57                    data.get('repo_dir', ''), 
    4658                   ]) == 0 
     59 
    4760 
    4861class MakeSubversionRepositoryAction(ProjectSetupParticipantBase): 
    4962    """DO NOT USE. Make a new Subversion repository using `svnadmin create`.""" 
    50      
    51     def execute_setup_action(self, req, proj, action, args): 
    52         print 'Failed output' 
    53         print >>sys.stderr, 'Failed error 1\nFailed error 2\nFailed error 3' 
    54         time.sleep(60) 
    55         return False 
     63    capture_output = False 
     64    def execute_setup_action(self, action, args, data, log_cb): 
     65        if '%s' not in args: 
     66            args = os.path.join(args, '%s') 
     67        repo_dir = args%data['name'] 
     68        data['repo_type'] = 'svn' 
     69        data['repo_dir'] = repo_dir 
     70        return self.call_external(log_cb, 'svnadmin', 'create', repo_dir) 
     71 
    5672 
    5773class ApplyConfigSetAction(ProjectSetupParticipantBase): 
    5874    """DO NOT USE. Apply a ConfigSet to a Trac environment.""" 
    5975     
    60     def execute_setup_action(self, req, proj, action, args): 
     76    def execute_setup_action(self, action, args, data, log_cb): 
    6177        print 'Output 1' 
    6278        print 'Output 2\nOutput 3' 
    6379        print >>sys.stderr,'Error 1' 
    6480        print 'Output 4' 
    65         os.system('echo "Output 5"') 
     81        #os.system('echo "Output 5"') 
    6682        return True 
     83 
    6784 
    6885class DoNothingAction(ProjectSetupParticipantBase): 
    6986    """Do nothing, just like it says..""" 
    7087     
    71     def execute_setup_action(self, req, proj, action, args): 
     88    def execute_setup_action(self, action, args, data, log_cb): 
    7289        return True 
  • tracforgeplugin/0.11/tracforge/htdocs/js/typewatch1.1.js

    r3378 r3394  
    1717    function typewatchCheck( thisWinSaved, override ) { 
    1818      var timer = typewatch_data[thisWinSaved]; 
    19       var elTxt = $(timer.el).val(); 
     19      var elTxt = jQuery(timer.el).val(); 
    2020 
    2121      if (elTxt.toUpperCase() != timer.text || override) { 
  • tracforgeplugin/0.11/tracforge/templates/admin_tracforge_projects.html

    r3378 r3394  
    1414    <title>Project Admin</title> 
    1515    <script type="text/javascript"> 
    16       $(function() { 
    17         $('#shortname').typeWatch({ 
    18           callback: function() { 
    19             $('#env_path').val('$env_base_path' + $('#shortname').val()); 
    20           }, 
    21           wait: 250 
     16      (function($) { 
     17        $(function() { 
     18          $('#shortname').typeWatch({ 
     19            callback: function() { 
     20              $('#env_path').val('$env_base_path' + $('#shortname').val()); 
     21            }, 
     22            wait: 250 
     23          }); 
    2224        }); 
    23       }); 
     25      }(jQuery)); 
    2426    </script> 
    2527  </head>