Changeset 3394
- Timestamp:
- 03/18/08 18:30:49 (9 months ago)
- Files:
-
- tracforgeplugin/0.11/setup.py (modified) (1 diff)
- tracforgeplugin/0.11/tracforge/admin/admin.py (modified) (6 diffs)
- tracforgeplugin/0.11/tracforge/admin/api.py (modified) (1 diff)
- tracforgeplugin/0.11/tracforge/admin/db_default.py (modified) (2 diffs)
- tracforgeplugin/0.11/tracforge/admin/helper.py (modified) (2 diffs)
- tracforgeplugin/0.11/tracforge/admin/__init__.py (modified) (1 diff)
- tracforgeplugin/0.11/tracforge/admin/model.py (modified) (5 diffs)
- tracforgeplugin/0.11/tracforge/admin/prototypes.py (modified) (2 diffs)
- tracforgeplugin/0.11/tracforge/admin/util.py (added)
- tracforgeplugin/0.11/tracforge/htdocs/js/typewatch1.1.js (modified) (1 diff)
- tracforgeplugin/0.11/tracforge/templates/admin_tracforge_project.html (added)
- tracforgeplugin/0.11/tracforge/templates/admin_tracforge_projects.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
tracforgeplugin/0.11/setup.py
r3377 r3394 39 39 ], 40 40 'console_scripts': [ 41 'tracforge-helper = tracforge.admin. constructor:main',41 'tracforge-helper = tracforge.admin.helper:main', 42 42 ], 43 43 }, tracforgeplugin/0.11/tracforge/admin/admin.py
r3377 r3394 1 1 # Created by Noah Kantrowitz on 2008-02-19. 2 2 # Copyright (c) 2008 Noah Kantrowitz. All rights reserved. 3 import os 3 4 import os.path 4 5 … … 6 7 from trac.admin.api import IAdminPanelProvider 7 8 from trac.web.chrome import add_script 9 from trac.config import Option 8 10 from trac.util.compat import sorted 9 11 … … 12 14 class TracForgeAdminModule(Component): 13 15 """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.') 14 20 15 21 implements(IAdminPanelProvider) … … 21 27 22 28 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 23 32 data = {} 24 33 … … 26 35 if 'create' in req.args.keys(): # Project creation 27 36 name = req.args.get('shortname', '').strip() 28 full name = req.args.get('fullname', '').strip()37 full_name = req.args.get('fullname', '').strip() 29 38 env_path = req.args.get('env_path', '').strip() 30 39 proto_name = req.args.get('prototype', '').strip() 31 if not (name and full name and env_path and proto_name):40 if not (name and full_name and env_path and proto_name): 32 41 raise TracError('All arguments are required') 33 42 34 43 # Make the models 35 proj = Project(self.env, name)36 44 proto = Prototype(self.env, proto_name) 37 45 if not proto.exists: 38 46 raise TracError('Penguins on fire') 39 47 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 43 53 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) 46 59 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)) 66 62 elif 'delete' in req.args.keys(): # Project deleteion 67 63 raise TracError, 'Not implemented yet. Sorry.' … … 73 69 add_script(req, 'tracforge/js/typewatch1.1.js') 74 70 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 13 13 """Return a string description of the given action.""" 14 14 15 def execute_setup_action(self, req, proj, action, args):15 def execute_setup_action(self, action, args, data, log_cb): 16 16 """Perform the given setup action on an environment.""" 17 17 tracforgeplugin/0.11/tracforge/admin/db_default.py
r3377 r3394 2 2 3 3 name = 'tracforge.admin' 4 version = 84 version = 10 5 5 tables = [ 6 6 Table('tracforge_projects', key='name')[ … … 9 9 ], 10 10 Table('tracforge_project_log', key=('project', 'action'))[ 11 Column('id', auto_increment=True),12 11 Column('project'), 12 Column('step', type='integer'), 13 13 Column('action'), 14 14 Column('args'), 15 15 Column('return'), 16 Column('stdout'),17 Column('stderr'),18 16 ], 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 ], 20 24 Table('tracforge_members', key=('project', 'username'))[ 21 25 Column('project'), tracforgeplugin/0.11/tracforge/admin/helper.py
r3378 r3394 4 4 5 5 import pkg_resources 6 pkg_resource .require('Trac')6 pkg_resources.require('Trac') 7 7 8 8 from trac.env import open_environment … … 16 16 # Load initial parameters from the command-line 17 17 master_path = argv[0] 18 prototype_name = argv[1] ,18 prototype_name = argv[1] 19 19 data = { 20 20 'name': argv[2], tracforgeplugin/0.11/tracforge/admin/__init__.py
r3377 r3394 1 #import api1 import api 2 2 import admin 3 3 #import membership 4 4 #import perm 5 5 #import perm_admin 6 #import prototypes6 import prototypes 7 7 #import prototypes_admin 8 8 #import dispatch tracforgeplugin/0.11/tracforge/admin/model.py
r3377 r3394 3 3 4 4 from UserDict import DictMixin 5 from tempfile import mkstemp, TemporaryFile6 5 import os 7 6 import sys 7 import time 8 import traceback 8 9 9 10 class BadEnv(object): … … 168 169 169 170 171 class _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 170 186 class Prototype(list): 171 187 """A model object for a project prototype.""" … … 180 196 181 197 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) 183 199 184 200 exists = property(lambda self: len(self)>0) … … 222 238 return False 223 239 224 def apply(self, req, proj):240 def execute(self, data): 225 241 """Run this prototype on a new project. 226 242 NOTE: If you pass in a project that isn't new, this could explode. Don't do that. … … 229 245 steps = TracForgeAdminSystem(self.env).get_project_setup_participants() 230 246 247 # Clear out the last attempt at making this project, if any 231 248 db = self.env.get_db_cnx() 232 249 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'],)) 234 252 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 277 290 278 291 tracforgeplugin/0.11/tracforge/admin/prototypes.py
r1615 r3394 1 1 # Utility classes for the TracForge prototypes system 2 from trac.core import *3 from api import IProjectSetupParticipant4 5 2 import inspect 6 3 import sys 7 4 import os 5 import os.path 8 6 import time 7 8 from trac.core import * 9 10 from tracforge.admin.api import IProjectSetupParticipant 11 from tracforge.admin.util import CommandLine, locate 9 12 10 13 class ProjectSetupParticipantBase(Component): … … 25 28 return inspect.getdoc(self.__class__) 26 29 27 def execute_setup_action(self, req, proj, action, args):30 def execute_setup_action(self, action, args, data, log_cb): 28 31 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 29 45 30 46 class MakeTracEnvironmentAction(ProjectSetupParticipantBase): 31 47 """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'], 40 53 'initenv', 41 req.args.get('fullname','').strip(),54 data['full_name'], 42 55 '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', ''), 46 58 ]) == 0 59 47 60 48 61 class MakeSubversionRepositoryAction(ProjectSetupParticipantBase): 49 62 """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 56 72 57 73 class ApplyConfigSetAction(ProjectSetupParticipantBase): 58 74 """DO NOT USE. Apply a ConfigSet to a Trac environment.""" 59 75 60 def execute_setup_action(self, req, proj, action, args):76 def execute_setup_action(self, action, args, data, log_cb): 61 77 print 'Output 1' 62 78 print 'Output 2\nOutput 3' 63 79 print >>sys.stderr,'Error 1' 64 80 print 'Output 4' 65 os.system('echo "Output 5"')81 #os.system('echo "Output 5"') 66 82 return True 83 67 84 68 85 class DoNothingAction(ProjectSetupParticipantBase): 69 86 """Do nothing, just like it says..""" 70 87 71 def execute_setup_action(self, req, proj, action, args):88 def execute_setup_action(self, action, args, data, log_cb): 72 89 return True tracforgeplugin/0.11/tracforge/htdocs/js/typewatch1.1.js
r3378 r3394 17 17 function typewatchCheck( thisWinSaved, override ) { 18 18 var timer = typewatch_data[thisWinSaved]; 19 var elTxt = $(timer.el).val();19 var elTxt = jQuery(timer.el).val(); 20 20 21 21 if (elTxt.toUpperCase() != timer.text || override) { tracforgeplugin/0.11/tracforge/templates/admin_tracforge_projects.html
r3378 r3394 14 14 <title>Project Admin</title> 15 15 <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 }); 22 24 }); 23 } );25 }(jQuery)); 24 26 </script> 25 27 </head>
