def prepare_request(req, environ): href = Href(req.href.all()) anenv = get_allenv(environ, req) req.href = href req.abs_href = Href(req.abs_href.all()) chrome = Chrome(anenv) update_request(req, chrome) # auth must be checked before this method runs, we are not a component yet req.perm = PermissionCache(anenv, req.authname) req.session = Session(anenv, req) loadpaths = chrome.get_all_templates_dirs(); loadpaths.insert(0, os.path.dirname(__file__) + "/templates/") req.hdf = {} populate_hdf(req.hdf, anenv, req) # after populate, add styles and scripts path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if len(path_info) == 0 or (len(path_info) == 1 and path_info[0] == ''): add_stylesheet(req, "tram/css/project-list.css") elif path_info[0] == 'roadmap': add_stylesheet(req, 'common/css/roadmap.css') elif path_info[0] == 'timeline': add_stylesheet(req, 'common/css/timeline.css') elif path_info[0] == 'query': add_stylesheet(req, 'common/css/report.css') elif path_info[0] == 'browser': add_stylesheet(req, 'common/css/browser.css') elif path_info[0] == 'search': add_stylesheet(req, 'common/css/search.css') add_stylesheet(req, 'tram/css/whole-search.css') add_script(req, 'tram/js/jquery-1.1.2.pack.js') add_script(req, 'tram/js/jquery.compat-1.0.js') add_script(req, 'tram/js/trac_ws.js') chrome.populate_hdf(req) req.hdf['tram.version'] = "0.3" req.hdf["tram_htdocs_location"] = req.hdf["htdocs_location"].replace("common", "tram") # We want to display the guide whether we are using an "all" env or not # As the elements are already ordered we hijac the about element and reassign it below req.hdf['chrome.nav.metanav.about'] = Markup('<a href="' + href.wiki('TracGuide') + '">Help/Guide</a>') req.hdf['chrome.nav.metanav.help'] = Markup('<a href="' + href.about() + '">About Trac</a>') # Here we are adding some links to plugins as they seem not to be loading now... if (anenv.isall): req.hdf['chrome.nav.mainnav.wiki'] = Markup('<a href="' + href.wiki() + '">Wiki</a>') req.hdf['chrome.nav.mainnav.timeline'] = Markup('<a href="' + href.timeline() + '">' + _('Timeline') + '</a>') req.hdf['chrome.nav.mainnav.roadmap'] = Markup('<a href="' + href.roadmap() + '">' + _('Roadmap') + '</a>') req.hdf['chrome.nav.mainnav.browser'] = Markup('<a href="' + href.browser('/') + '">' + _('Browse Source') + '</a>') req.hdf['chrome.nav.mainnav.tickets'] = Markup('<a href="' + href.query() + '">' + _('View Tickets') + '</a>') req.hdf['chrome.nav.mainnav.search'] = Markup('<a href="' + href.search() + '">' + _('Search') + '</a>') return chrome
def build(self): self._position = self._parent.position() x = self._position[0]+(self._w-self._tw)/2 y = self._position[1] r = UNIT/2 rect = SVG.rect(x,y,self._tw,self._h, self._parent.fillcolor(), self._parent.strokecolor(), self._parent.strokewidth()) rect.attributes['rx'] = r rect.attributes['ry'] = r text = SVG.text(self._position[0]++self._w/2, self._position[1]+self._h/2+UNIT/6, "/%s" % self._title.encode('utf-8'), self._parent.fontsize(), self._parent.fontname()) text.attributes['style'] = 'text-anchor: middle' name = self._title.encode('utf-8').replace('/','') g = SVG.group('grp%s' % name, elements=[rect, text]) href = Href(self._parent.urlbase()) self._link = SVG.link(plink(href.browser(self._title)), elements=[g])
def href(self): """The application root path""" return Href(urlsplit(self.abs_href.base).path)
def send_project_index(environ, start_response, parent_dir=None, env_paths=None): req = Request(environ, start_response) loadpaths = [pkg_resources.resource_filename('trac', 'templates')] if req.environ.get('trac.env_index_template'): env_index_template = req.environ['trac.env_index_template'] tmpl_path, template = os.path.split(env_index_template) loadpaths.insert(0, tmpl_path) else: template = 'index.html' data = { 'trac': { 'version': TRAC_VERSION, 'time': user_time(req, format_datetime) }, 'req': req } if req.environ.get('trac.template_vars'): for pair in req.environ['trac.template_vars'].split(','): key, val = pair.split('=') data[key] = val try: href = Href(req.base_path) projects = [] for env_name, env_path in get_environments(environ).items(): try: env = open_environment(env_path, use_cache=not environ['wsgi.run_once']) proj = { 'env': env, 'name': env.project_name, 'description': env.project_description, 'href': href(env_name) } except Exception as e: proj = {'name': env_name, 'description': to_unicode(e)} projects.append(proj) projects.sort(lambda x, y: cmp(x['name'].lower(), y['name'].lower())) data['projects'] = projects loader = TemplateLoader(loadpaths, variable_lookup='lenient', default_encoding='utf-8') tmpl = loader.load(template) stream = tmpl.generate(**data) if template.endswith('.xml'): output = stream.render('xml') req.send(output, 'text/xml') else: output = stream.render('xhtml', doctype=DocType.XHTML_STRICT, encoding='utf-8') req.send(output, 'text/html') except RequestDone: pass
def setUp(self): self.env = EnvironmentStub() self.req = Mock(href=Href('/'), abs_href=Href('http://example.org/'), authname='anonymous', tz=utc, locale=locale_en, lc_time=locale_en, chrome={}, perm=MockPerm(), session={})
def process_request(self, req): req.perm.assert_permission('ROADMAP_VIEW') #If the page was posted, a filter was applied. Build and redirect using query strnig if req.args.has_key('update'): req.redirect(self._get_href(req)) req.hdf['title'] = 'Project List' #Process filtering arguments self.status = req.args.has_key('status') and req.args['status'] or None #Process sorting arguments self.desc = req.args.has_key( 'desc') and req.args['desc'] == '1' or None self.order = req.args.has_key( 'order') and req.args['order'] or DEFAULT_SORT_FIELD #Get search path and base_url search_path, this_project = os.path.split(self.env.path) base_url, _ = posixpath.split(req.abs_href()) href = Href(base_url) #Start with an empty project list projects = [] for project in os.listdir(search_path): #Open the project environment project_path = os.path.join(search_path, project) env = open_environment(project_path) #Check if DB needs upgrading check_upgrade(env) #Trim project description if too long if len(env.project_description) <= 60: description = env.project_description else: description = "%s..." % env.project_description[:60] #Get last_login timestamp, and convert to human readable last_login = int(get_property(env, 'last_login', 0)) if last_login == 0: last_login = '' else: last_login = datetime.fromtimestamp(last_login).strftime( TIME_FORMAT) #Filter by status project_status = get_property(env, 'status', 'unknown') if self.status and project_status != self.status: continue projects.append({ 'name': env.project_name, 'description': description, 'company': get_property(env, 'company'), 'created': get_property(env, 'date_created'), 'started': get_property(env, 'date_started'), 'scheduled': get_property(env, 'date_scheduled'), 'finished': get_property(env, 'date_finished'), 'percent_finished': get_property(env, 'percent', '0'), 'percent_remaining': 100 - int(get_property(env, 'percent', '0')), 'status': STATUS[project_status], 'client': get_property(env, 'client'), 'manager': get_property(env, 'manager'), 'last_login': last_login, 'href': href(project) }) #Status selection sorted_keys = STATUS.keys() sorted_keys.sort() statuses = [dict(name='', label='*', selected=self.status == None)] statuses += [ dict(name=x, label=STATUS[x], selected=self.status == x) for x in sorted_keys ] #################################### ## Functions for project sorting, depending on the field def cmp_datetime(x, y): try: return datetime.strptime(x, TIME_FORMAT) < datetime.strptime( y, TIME_FORMAT) and -1 or 1 except: return x.lower() < y.lower() and -1 or 1 def cmp_date(x, y): try: return datetime.strptime(x, DATE_FORMAT) < datetime.strptime( y, DATE_FORMAT) and -1 or 1 except: return x.lower() < y.lower() and -1 or 1 def cmp_int(x, y): try: return int(x) < int(y) and -1 or 1 except: return x < y and -1 or 1 def cmp_str_nocase(x, y): try: return x.lower() < y.lower() and -1 or 1 except: return x < y and -1 or 1 ################################# #For some fields, use a special comparison function if self.order in ('created', 'last_login'): cmp = lambda x, y: cmp_datetime(x[self.order], y[self.order]) if self.order in ('started', 'scheduled', 'finished'): cmp = lambda x, y: cmp_date(x[self.order], y[self.order]) if self.order in ('percent_finished'): cmp = lambda x, y: cmp_int(x[self.order], y[self.order]) else: cmp = lambda x, y: cmp_str_nocase(x[self.order], y[self.order]) projects.sort(cmp=cmp, reverse=self.desc and True or False) #Set template HDF req.hdf['projects'] = projects req.hdf['statuses'] = statuses req.hdf['status'] = self.status req.hdf['order'] = self.order req.hdf['desc'] = self.desc add_stylesheet(req, 'tracprojectmanager/css/projectlist.css') return 'projectlist.cs', None
def test_add_link_simple(self): req = Request(href=Href('/trac.cgi')) add_link(req, 'start', '/trac/wiki') self.assertEqual('/trac/wiki', req.chrome['links']['start'][0]['href'])
def test_process_build_step_failure_continue(self): recipe = """<build> <step id="foo" onerror="continue"> </step> </build>""" BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.slave_info[Build.TOKEN] = '123' build.insert() inbody = StringIO("""<result step="foo" status="failure" time="2007-04-01T15:30:00.0000" duration="3.45"> </result>""") outheaders = {} outbody = StringIO() req = Mock(method='POST', base_path='', path_info='/builds/%d/steps/' % build.id, href=Href('/trac'), abs_href=Href('http://example.org/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), read=inbody.read, send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=123')) module = BuildMaster(self.env) module._start_new_step(build, 'foo').insert() assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(201, outheaders['Status']) self.assertEqual('20', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Build step processed', outbody.getvalue()) build = Build.fetch(self.env, build.id) self.assertEqual(Build.FAILURE, build.status) assert build.stopped assert build.stopped > build.started steps = list(BuildStep.select(self.env, build.id)) self.assertEqual(1, len(steps)) self.assertEqual('foo', steps[0].name) self.assertEqual(BuildStep.FAILURE, steps[0].status)
def test_process_build_step_success_with_report(self): recipe = """<build> <step id="foo"> </step> </build>""" BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.slave_info[Build.TOKEN] = '123' build.insert() inbody = StringIO("""<result step="foo" status="success" time="2007-04-01T15:30:00.0000" duration="3.45"> <report category="test" generator="http://bitten.edgewall.org/tools/python#unittest"> <test fixture="my.Fixture" file="my/test/file.py"> <stdout>Doing my thing</stdout> </test> </report> </result>""") outheaders = {} outbody = StringIO() req = Mock(method='POST', base_path='', path_info='/builds/%d/steps/' % build.id, href=Href('/trac'), abs_href=Href('http://example.org/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), read=inbody.read, send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=123')) module = BuildMaster(self.env) module._start_new_step(build, 'foo').insert() assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(201, outheaders['Status']) self.assertEqual('20', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Build step processed', outbody.getvalue()) build = Build.fetch(self.env, build.id) self.assertEqual(Build.SUCCESS, build.status) assert build.stopped assert build.stopped > build.started steps = list(BuildStep.select(self.env, build.id)) self.assertEqual(1, len(steps)) self.assertEqual('foo', steps[0].name) self.assertEqual(BuildStep.SUCCESS, steps[0].status) reports = list(Report.select(self.env, build=build.id, step='foo')) self.assertEqual(1, len(reports)) self.assertEqual('test', reports[0].category) self.assertEqual('http://bitten.edgewall.org/tools/python#unittest', reports[0].generator) self.assertEqual(1, len(reports[0].items)) self.assertEqual( { 'fixture': 'my.Fixture', 'file': 'my/test/file.py', 'stdout': 'Doing my thing', 'type': 'test', }, reports[0].items[0])
def open_environment(self, environ, start_response): env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) raise RequestDone errmsg = None # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. script_name = environ.get('SCRIPT_NAME', '') try: script_name = unicode(script_name, 'utf-8') # (as Href expects unicode parameters) environ['SCRIPT_NAME'] = Href(script_name)(env_name) environ['PATH_INFO'] = '/' + '/'.join(path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): errmsg = 'Environment not found' except UnicodeDecodeError: errmsg = 'Invalid URL encoding (was %r)' % script_name if errmsg: write = start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(errmsg)))]) write(errmsg) raise RequestDone if not env_path: raise EnvironmentError('The environment options "TRAC_ENV" or ' '"TRAC_ENV_PARENT_DIR" or the mod_python ' 'options "TracEnv" or "TracEnvParentDir" are ' 'missing. Trac requires one of these options ' 'to locate the Trac environment(s).') run_once = environ['wsgi.run_once'] env = None self.global_env = global_env = None try: self.global_env = global_env = open_environment(env_path, use_cache=not run_once) factory = environment_factory(global_env) factory_env = factory().open_environment(environ, env_path, global_env, use_cache=not run_once) if factory \ else None env = factory_env if factory_env else global_env except Exception: raise return env
def post_process_request(self, req, template, data, content_type): msg = req.session.get('watchlist_message', []) if msg: add_notice(req, msg) del req.session['watchlist_message'] msg = req.session.get('watchlist_notify_message', []) if msg: add_notice(req, msg) del req.session['watchlist_notify_message'] # Extract realm and resid from path: parts = req.path_info[1:].split('/', 1) # Handle special case for '/' and '/wiki' if len(parts) == 0 or not parts[0]: parts = ["wiki", "WikiStart"] elif len(parts) == 1: parts.append("WikiStart") realm, resid = parts[:2] if realm not in ('wiki','ticket') \ or realm.upper() + '_VIEW' not in req.perm: return (template, data, content_type) href = Href(req.base_path) user = req.authname if user and user != "anonymous": if self.is_watching(realm, resid, user): add_ctxtnav(req, "Unwatch", href=href('watchlist', action='unwatch', resid=resid, realm=realm), title="Remove %s from watchlist" % realm) else: add_ctxtnav(req, "Watch", href=href('watchlist', action='watch', resid=resid, realm=realm), title="Add %s to watchlist" % realm) if self.gnotify and self.notifyctxtnav: if self.is_notify(req.session.sid, True, realm, resid): add_ctxtnav(req, "Do not Notify me", href=href('watchlist', action='notifyoff', resid=resid, realm=realm), title="No not notify me if %s changes" % realm) else: add_ctxtnav(req, "Notify me", href=href('watchlist', action='notifyon', resid=resid, realm=realm), title="Notify me if %s changes" % realm) return (template, data, content_type)
def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. @param environ: the WSGI environment dict @param start_response: the WSGI callback for starting the response """ if 'mod_python.options' in environ: options = environ['mod_python.options'] environ.setdefault('trac.env_path', options.get('TracEnv')) environ.setdefault('trac.env_parent_dir', options.get('TracEnvParentDir')) environ.setdefault('trac.env_index_template', options.get('TracEnvIndexTemplate')) environ.setdefault('trac.template_vars', options.get('TracTemplateVars')) environ.setdefault('trac.locale', options.get('TracLocale')) if 'TracUriRoot' in options: # Special handling of SCRIPT_NAME/PATH_INFO for mod_python, which # tends to get confused for whatever reason root_uri = options['TracUriRoot'].rstrip('/') request_uri = environ['REQUEST_URI'].split('?', 1)[0] if not request_uri.startswith(root_uri): raise ValueError(u'TracUriRoot défini pour %s mais la requète ' u'pointe sur %s' % (root_uri, request_uri)) environ['SCRIPT_NAME'] = root_uri environ['PATH_INFO'] = urllib.unquote(request_uri[len(root_uri):]) else: environ.setdefault('trac.env_path', os.getenv('TRAC_ENV')) environ.setdefault('trac.env_parent_dir', os.getenv('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac.env_index_template', os.getenv('TRAC_ENV_INDEX_TEMPLATE')) environ.setdefault('trac.template_vars', os.getenv('TRAC_TEMPLATE_VARS')) environ.setdefault('trac.locale', os.getenv('TRAC_LOCALE')) if environ['trac.locale']: locale.setlocale(locale.LC_ALL, environ['trac.locale']) else: if os.name == 'posix': locale.setlocale(locale.LC_ALL, 'fr_FR') elif os.name == 'nt': locale.setlocale(locale.LC_ALL, 'French_France') else: locale.setlocale(locale.LC_ALL, '') # Allow specifying the python eggs cache directory using SetEnv if 'mod_python.subprocess_env' in environ: egg_cache = environ['mod_python.subprocess_env'].get('PYTHON_EGG_CACHE') if egg_cache: os.environ['PYTHON_EGG_CACHE'] = egg_cache # Determine the environment env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) return [] # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. environ['SCRIPT_NAME'] = Href(environ['SCRIPT_NAME'])(env_name) environ['PATH_INFO'] = '/'.join([''] + path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): start_response(u'404 Non trouvé', []) return [u'Environment non trouvé'] if not env_path: raise EnvironmentError(u'Les options d\'environment "TRAC_ENV" ou ' u'"TRAC_ENV_PARENT_DIR", ou bien les options ' u'mod_python "TracEnv" ou "TracEnvParentDir" ne ' u'sont pas définies. Trac a besoin d\'une de ces ' u'options pour localiser le ou les environnments ' u'Trac.') run_once = environ['wsgi.run_once'] env = _open_environment(env_path, run_once=run_once) if env.base_url: environ['trac.base_url'] = env.base_url req = Request(environ, start_response) try: try: try: dispatcher = RequestDispatcher(env) dispatcher.dispatch(req) except RequestDone: pass return req._response or [] finally: if not run_once: env.shutdown(threading._get_ident()) except HTTPException, e: env.log.warn(e) if req.hdf: req.hdf['title'] = e.reason or u'Erreur' req.hdf['error'] = { 'title': e.reason or u'Erreur', 'type': 'TracError', 'message': e.message } try: req.send_error(sys.exc_info(), status=e.code) except RequestDone: return []
def test_empty_content(self): context = Mock(env=self.env, href=Href('/'), req=self.req) formatter = Mock(context=context, req=self.req) self.assertTrue('No resources found' in str( self.tag_twm.expand_macro(formatter, 'ListTagged', '')))
class TracTicket(object): """A Trac ticket implementation see http://trac.edgewall.org/ """ def __init__(self, env, parameters): self.env = env self.db = None def searchTickets(self, nbsec): """search tickets updated since nbsec, if nbsec is -1, it checks all jobs else check is performed since now - nbsec. """ db = self.env.get_db_cnx() cursor = db.cursor() tickets = {} if nbsec == -1: sql = 'SELECT id, changetime, owner, summary, status FROM ticket' else: sql = 'SELECT id, changetime, owner, summary, status FROM ticket WHERE strftime(\'%s\', \'now\') - changetime < ' + str( nbsec) cursor.execute(sql) while True: row = cursor.fetchone() if row == None: break r = { 'Date': row[1], 'Status': row[4], 'Description': row[3], 'User': row[2], 'From': u'trac' } tickets[row[0]] = r return tickets def searchFixes(self, id, jobs): """try to retrieve comment input string into ticket's changes stored in sqlite db. """ db = self.env.get_db_cnx() cursor = db.cursor() begin_ticket_re = re.compile(r'see changelist') ticket_re = re.compile(r'\d+') tickets = {} sql = 'SELECT newvalue FROM ticket_change where field="comment" and ticket=%d' % ( id) cursor.execute(sql) while True: row = cursor.fetchone() if row == None: break row = str(row) if begin_ticket_re.search(row): trac = set([]) for x in ticket_re.findall(row): trac.add(int(x)) jobs.difference_update(trac) return jobs def updateTicket(self, id, ticket, notification): """ """ try: tkt = Ticket(self.env, id, self.db) except TracError, detail: print "Cannot create Trac ticket : %s" % (detail) return tkt['status'] = settings['p4_to_trac'][ticket['Status']] if tkt['status'] == u'closed': tkt['resolution'] = u'fixed' else: tkt['resolution'] = u'' tkt['owner'] = ticket['User'] tkt['summary'] = ticket['Description'] jobs = set([]) comment = '' if 'Fixes' in ticket: for f in ticket['Fixes']: jobs.add(int(f)) jobs = self.searchFixes(id, jobs) if len(jobs) > 0: comment = 'see changelist :' for j in jobs: comment += ' [%d]' % j if settings.get('debug', 0) > 1: print "Trac ticket comment %s" % (comment) when = datetime.fromtimestamp(ticket['Date'], utc) if settings.get('debug', 0): print "update Trac %d %s" % (id, ticket) if settings.get('dry_run', 0) == 0: saved = tkt.save_changes(ticket['User'], comment, when) try: if saved: self.env._abs_href = Href( self.env.config.get('project', 'url')) #self.env._href = Href(self.env.config.get('project', 'url')) tn = TicketNotifyEmail(self.env) tn.notify(tkt, False, when) except Exception, e: print 'TD: Failure sending notification on creation of ticket #%s: %s' % ( id, e)
def test_testcase_errors_and_failures(self): config = Mock(name='trunk', path='/somewhere', min_rev_time=lambda env: 0, max_rev_time=lambda env: 1000) step = Mock(name='foo') build = Build(self.env, config=config.name, platform=1, rev=123, rev_time=42) build.insert() report = Report(self.env, build=build.id, step=step.name, category='test') report.items += [{ 'fixture': 'test_foo', 'name': 'foo', 'file': 'foo.c', 'type': 'test', 'status': 'success' }, { 'fixture': 'test_bar', 'name': 'bar', 'file': 'bar.c', 'type': 'test', 'status': 'error', 'traceback': 'Error traceback' }, { 'fixture': 'test_baz', 'name': 'baz', 'file': 'baz.c', 'type': 'test', 'status': 'failure', 'traceback': 'Failure reason' }] report.insert() req = Mock(href=Href('trac')) generator = TestResultsSummarizer(self.env) template, data = generator.render_summary(req, config, build, step, 'test') self.assertEquals('bitten_summary_tests.html', template) self.assertEquals(data['totals'], { 'ignore': 0, 'failure': 1, 'success': 1, 'error': 1 }) for fixture in data['fixtures']: if fixture.has_key('failures'): if fixture['failures'][0]['status'] == 'error': self.assertEquals('test_bar', fixture['name']) self.assertEquals('Error traceback', fixture['failures'][0]['traceback']) if fixture['failures'][0]['status'] == 'failure': self.assertEquals('test_baz', fixture['name']) self.assertEquals('Failure reason', fixture['failures'][0]['traceback'])
def populate_hdf(self, req, handler): """Add chrome-related data to the HDF.""" # Provided for template customization req.hdf['HTTP.PathInfo'] = req.path_info href = Href(req.base_path) req.hdf['chrome.href'] = href.chrome() htdocs_location = self.htdocs_location or href.chrome('common') req.hdf['htdocs_location'] = htdocs_location.rstrip('/') + '/' # HTML <head> links add_link(req, 'start', req.href.wiki()) add_link(req, 'search', req.href.search()) add_link(req, 'help', req.href.wiki('TracGuide')) add_stylesheet(req, 'common/css/trac.css') add_script(req, 'common/js/trac.js') icon = self.env.project_icon if icon: if not icon.startswith('/') and icon.find('://') == -1: if '/' in icon: icon = href.chrome(icon) else: icon = href.chrome('common', icon) mimetype = mimeview.get_mimetype(icon) add_link(req, 'icon', icon, mimetype=mimetype) add_link(req, 'shortcut icon', icon, mimetype=mimetype) # Logo image logo_src = self.logo_src if logo_src: logo_src_abs = logo_src.startswith('http://') or \ logo_src.startswith('https://') if not logo_src.startswith('/') and not logo_src_abs: if '/' in logo_src: logo_src = href.chrome(logo_src) else: logo_src = href.chrome('common', logo_src) width = self.logo_width > -1 and self.logo_width height = self.logo_height > -1 and self.logo_height req.hdf['chrome.logo'] = { 'link': self.logo_link, 'src': logo_src, 'src_abs': logo_src_abs, 'alt': self.logo_alt, 'width': width, 'height': height } else: req.hdf['chrome.logo.link'] = self.logo_link # Navigation links navigation = {} active = None for contributor in self.navigation_contributors: for category, name, text in contributor.get_navigation_items(req): navigation.setdefault(category, {})[name] = text if contributor is handler: active = contributor.get_active_navigation_item(req) for category, items in [(k, v.items()) for k, v in navigation.items()]: category_order = category + '_order' if hasattr(self, category_order): order = getattr(self, category_order) def navcmp(x, y): if x[0] not in order: return int(y[0] in order) if y[0] not in order: return -int(x[0] in order) return cmp(order.index(x[0]), order.index(y[0])) items.sort(navcmp) for name, text in items: req.hdf['chrome.nav.%s.%s' % (category, name)] = text if name == active: req.hdf['chrome.nav.%s.%s.active' % (category, name)] = 1
def expand_macro(self, formatter, name, content, args=None): content = content.replace('\n', ',') args, kwargs = parse_args(content, multi=['markers', 'path', 'visible']) # HTML arguments used in Google Maps URL hargs = { 'center': "50.805935,10.349121", #'zoom' : "6", 'key': self.key, 'size': self.size, 'hl': self.hl, 'sensor': 'false', } # Set API version api = kwargs.get('api', self.api) if api not in self.google_url: api = self.api # Delete default zoom if user provides 'span' argument: if 'span' in kwargs: del hargs['zoom'] # Copy given macro arguments to the HTML arguments for k, v in kwargs.iteritems(): if k in self.allowed_args and v: hargs[k] = v # Check if API key exists if not 'key' in hargs and api == '1': # TODO: check if old API still needs the key raise TracError("No Google Maps API key given!\n") # Get height and width try: if 'x' not in hargs['size']: hargs['size'] = hargs['size'] + 'x' + hargs['size'] (width, height) = hargs['size'].split('x') if int(height) < 1: height = "1" elif int(height) > 640: height = "640" if int(width) < 1: width = "1" elif int(width) > 640: width = "640" hargs['size'] = "%sx%s" % (width, height) except: raise TracError( "Invalid `size` argument. Should be `<width>x<height>`.") if api == '1': # Correct separator for 'center' argument because comma isn't allowed in # macro arguments hargs['center'] = hargs['center'].replace(':', ',') if 'markers' in hargs: hargs['markers'] = [ marker.replace(':', ',') for marker in hargs['markers'] ] # Build URL src = Href(self.google_url.get(api, ''))(**hargs) title = alt = "Google Static Map at %s" % hargs['center'] # TODO: provide sane alternative text and image title if 'title' in kwargs: title = kwargs['title'] return tag.img( class_="googlestaticmap", src=src, title=title, alt=alt, height=height, width=width, )
def post_process_request(self, req, template, data, content_type): user = to_unicode(req.authname) settings = self.get_settings( user) # FIXME: suboptimal to reload settings here # TODO: Move to request handler? msg = req.session.get('watchlist_message', []) if msg: add_notice(req, msg) del req.session['watchlist_message'] msg = req.session.get('watchlist_notify_message', []) if msg: add_notice(req, msg) del req.session['watchlist_notify_message'] # Extract realm and resid from path: parts = req.path_info[1:].split('/', 1) # Handle special case for '/' and '/wiki' if len(parts) == 0 or not parts[0]: parts = ["wiki", "WikiStart"] elif len(parts) == 1: parts.append("WikiStart") realm, resid = parts[:2] if realm not in self.realms or not \ self.realm_handler[realm].has_perm(realm, req.perm): return (template, data, content_type) href = Href(req.base_path) user = req.authname if user and user != "anonymous": if self.is_watching(realm, resid, user): add_ctxtnav(req, _("Unwatch"), href=req.href('watchlist', action='unwatch', resid=resid, realm=realm), title=_("Remove %s from watchlist") % realm) else: add_ctxtnav(req, _("Watch"), href=req.href('watchlist', action='watch', resid=resid, realm=realm), title=_("Add %s to watchlist") % realm) if settings['notifications'] and settings[ 'display_notify_navitems']: if self.is_notify(req, realm, resid): add_ctxtnav(req, _("Do not Notify me"), href=req.href('watchlist', action='notifyoff', resid=resid, realm=realm), title=_("Do not notify me if %s changes") % realm) else: add_ctxtnav(req, _("Notify me"), href=req.href('watchlist', action='notifyon', resid=resid, realm=realm), title=_("Notify me if %s changes") % realm) return (template, data, content_type)
def test_process_build_step_invalidated_build(self): recipe = """<build> <step id="foo"> </step> <step id="foo2"> </step> </build>""" BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.slave_info[Build.TOKEN] = '123' build.insert() inbody = StringIO("""<result step="foo" status="success" time="2007-04-01T15:30:00.0000" duration="3.45"> <log generator="http://bitten.edgewall.org/tools/python#unittest"> <message level="info">Doing stuff</message> <message level="error">Ouch that hurt</message> </log> </result>""") outheaders = {} outbody = StringIO() req = Mock(method='POST', base_path='', path_info='/builds/%d/steps/' % build.id, href=Href('/trac'), abs_href=Href('http://example.org/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), read=inbody.read, send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=123')) module = BuildMaster(self.env) module._start_new_step(build, 'foo').insert() assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) build = Build.fetch(self.env, build.id) self.assertEqual(Build.IN_PROGRESS, build.status) assert not build.stopped steps = list(BuildStep.select(self.env, build.id)) self.assertEqual(2, len(steps)) # invalidate the build. build = Build.fetch(self.env, build.id) build.slave = None build.status = Build.PENDING build.slave_info = {} for step in list(BuildStep.select(self.env, build=build.id)): step.delete() build.update() # have this slave submit more data. inbody = StringIO("""<result step="foo2" status="success" time="2007-04-01T15:45:00.0000" duration="4"> <log generator="http://bitten.edgewall.org/tools/python#unittest"> <message level="info">This is a step after invalidation</message> </log> </result>""") outheaders = {} outbody = StringIO() req = Mock(method='POST', base_path='', path_info='/builds/%d/steps/' % build.id, href=Href('/trac'), abs_href=Href('http://example.org/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), read=inbody.read, send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=123')) module = BuildMaster(self.env) module._start_new_step(build, 'foo').insert() assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEquals(409, outheaders['Status']) self.assertEquals('Token mismatch (wrong slave): slave=123, build=', outbody.getvalue()) build = Build.fetch(self.env, build.id) self.assertEqual(Build.PENDING, build.status)
def test_login_no_username(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertRaises(TracError, self.module._do_login, req)
class LinkAdmin(Component): implements(IAdminPageProvider, ITemplateProvider) # IAdminPageProvider methods # required permission to access this page _perm = 'TRAC_ADMIN' def get_admin_pages(self, req): # FIXME: more suitable permission should be used if req.perm.has_permission(self._perm): # (category, category_label, page, page_label) yield ('general', 'General', 'link', 'Links') def _set_message(self, req, cls, text): req.session['message_text'] = text req.session['message_class'] = cls def _get_message(self, req): return req.session.get('message_text', ''), \ req.session.get('message_class', 'none') def _clear_message(self, req): dic = req.session if dic.has_key('message_text'): dic.pop('message_text') if dic.has_key('message_class'): dic.pop('message_class') def _notify(self, req, text): self._set_message(req, 'notify', text) def _error(self, req, text): self._set_message(req, 'error', 'ERROR: ' + text) def process_admin_request(self, req, category, page, name): req.perm.assert_permission(self._perm) # this page may called like # /proj/admin/general # /proj/admin/general/link # /proj/admin/general/link/name base_href = self.env.href.admin('general', 'link') # post back actions: # add ... add and redirect to top # modify ... modify and redirect self or renamed self # remove ... redirect to top prov = GeneralLinkSyntaxProvider(self.env) prov.load() try: if name: link = prov.get_link(name) if not link: raise TracError('No such link name: ' + name) # prepare to modify req.hdf['admin.link'] = link.get_hash() req.hdf['admin.link.mode'] = 'modify' if req.method == 'POST': # change value if req.args.get('save'): # set values prov.modify(name, req.args.get('expose') != None, req.args.get('disp'), req.args.get('url')) self._notify(req, "link '%s' is modified'" % name) # redirect to base req.redirect(base_href) else: if req.method == 'POST': if req.args.get('add'): # add new entry name = req.args.get('name') expose = req.args.get('expose') != None url = req.args.get('url') disp = req.args.get('disp') req.hdf['admin.link'] = { 'mode': 'add', 'name': name, 'exposed': expose, 'disp': disp, 'url': url } prov.add(name, expose, disp, url) self._notify(req, "link '%s' is added'" % name) elif req.args.get('remove') and req.args.get('sel'): # Remove components sel = req.args.get('sel') sel = isinstance(sel, list) and sel or [sel] if not sel: raise TracError, 'No item selected' for name in sel: prov.delete(name) self._notify(req, 'deleted %d liks' % len(sel)) req.redirect(base_href) except Exception, e: self._error(req, str(e)) # render current links links = [] href = Href(base_href) for link in prov.get_links(): h = link.get_hash() h['href'] = href(link.get_name()) links.append(h) req.hdf['admin.links'] = links # prepare notify message message_text, message_class = self._get_message(req) req.hdf['admin.message.text'] = message_text req.hdf['admin.message.class'] = message_class self._clear_message(req) add_stylesheet(req, 'admin/css/admin_link.css') return 'admin_link.cs', None
def test_logout_not_logged_in(self): req = Mock(cgi_location='/trac', href=Href('/trac.cgi'), incookie=Cookie(), outcookie=Cookie(), remote_addr='127.0.0.1', remote_user=None, authname='anonymous', method='POST', base_path='/trac.cgi') self.module._do_logout(req) # this shouldn't raise an error
def test_add_stylesheet_media(self): req = Request(base_path='/trac.cgi', href=Href('/trac.cgi')) add_stylesheet(req, 'foo.css', media='print') links = req.chrome['links']['stylesheet'] self.assertEqual(1, len(links)) self.assertEqual('print', links[0]['media'])
def test_anonymous_access(self): req = Mock(incookie=Cookie(), href=Href('/trac.cgi'), remote_addr='127.0.0.1', remote_user=None, base_path='/trac.cgi') self.assertIsNone(self.module.authenticate(req))
def setUp(self): self.env = EnvironmentStub(default_data=True) self.req = Mock(perm=MockPerm(), href=Href('/trac.cgi')) self.context = web_context(self.req)
def setUp(self): self.ghref = Href('/gbase') self.phref = ProductizedHref(self.ghref, '/gbase/product')
def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. :param environ: the WSGI environment dict :param start_response: the WSGI callback for starting the response """ # SCRIPT_URL is an Apache var containing the URL before URL rewriting # has been applied, so we can use it to reconstruct logical SCRIPT_NAME script_url = environ.get('SCRIPT_URL') if script_url is not None: path_info = environ.get('PATH_INFO') if not path_info: environ['SCRIPT_NAME'] = script_url else: # mod_wsgi squashes slashes in PATH_INFO (!) script_url = _slashes_re.sub('/', script_url) path_info = _slashes_re.sub('/', path_info) if script_url.endswith(path_info): environ['SCRIPT_NAME'] = script_url[:-len(path_info)] # If the expected configuration keys aren't found in the WSGI environment, # try looking them up in the process environment variables environ.setdefault('trac.env_path', os.getenv('TRAC_ENV')) environ.setdefault('trac.env_parent_dir', os.getenv('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac.env_index_template', os.getenv('TRAC_ENV_INDEX_TEMPLATE')) environ.setdefault('trac.template_vars', os.getenv('TRAC_TEMPLATE_VARS')) environ.setdefault('trac.locale', '') environ.setdefault('trac.base_url', os.getenv('TRAC_BASE_URL')) locale.setlocale(locale.LC_ALL, environ['trac.locale']) # Determine the environment env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) return [] errmsg = None # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. script_name = environ.get('SCRIPT_NAME', '') try: script_name = unicode(script_name, 'utf-8') # (as Href expects unicode parameters) environ['SCRIPT_NAME'] = Href(script_name)(env_name) environ['PATH_INFO'] = '/' + '/'.join(path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): errmsg = 'Environment not found' except UnicodeDecodeError: errmsg = 'Invalid URL encoding (was %r)' % script_name if errmsg: start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(errmsg)))]) return [errmsg] if not env_path: raise EnvironmentError('The environment options "TRAC_ENV" or ' '"TRAC_ENV_PARENT_DIR" or the mod_python ' 'options "TracEnv" or "TracEnvParentDir" are ' 'missing. Trac requires one of these options ' 'to locate the Trac environment(s).') run_once = environ['wsgi.run_once'] env = env_error = None try: env = open_environment(env_path, use_cache=not run_once) if env.base_url_for_redirect: environ['trac.base_url'] = env.base_url # Web front-end type and version information if not hasattr(env, 'webfrontend'): mod_wsgi_version = environ.get('mod_wsgi.version') if mod_wsgi_version: mod_wsgi_version = ( "%s (WSGIProcessGroup %s WSGIApplicationGroup %s)" % ('.'.join([str(x) for x in mod_wsgi_version ]), environ.get('mod_wsgi.process_group'), environ.get('mod_wsgi.application_group') or '%{GLOBAL}')) environ.update({ 'trac.web.frontend': 'mod_wsgi', 'trac.web.version': mod_wsgi_version }) env.webfrontend = environ.get('trac.web.frontend') if env.webfrontend: env.webfrontend_version = environ['trac.web.version'] except Exception as e: env_error = e req = RequestWithSession(environ, start_response) translation.make_activable(lambda: req.locale, env.path if env else None) try: return _dispatch_request(req, env, env_error) finally: translation.deactivate() if env and not run_once: env.shutdown(threading._get_ident()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect()
def __init__(self, default_data=False, enable=None, disable=None, path=None, destroying=False): """Construct a new Environment stub object. :param default_data: If True, populate the database with some defaults. :param enable: A list of component classes or name globs to activate in the stub environment. """ ComponentManager.__init__(self) Component.__init__(self) self.systeminfo = [] import trac self.path = path if self.path is None: self.path = os.path.dirname(trac.__file__) if not os.path.isabs(self.path): self.path = os.path.join(os.getcwd(), self.path) # -- configuration self.config = Configuration(None) # We have to have a ticket-workflow config for ''lots'' of things to # work. So insert the basic-workflow config here. There may be a # better solution than this. load_workflow_config_snippet(self.config, 'basic-workflow.ini') self.config.set('logging', 'log_level', 'DEBUG') self.config.set('logging', 'log_type', 'stderr') if enable is not None: self.config.set('components', 'trac.*', 'disabled') else: self.config.set('components', 'tracopt.versioncontrol.svn.*', 'enabled') for name_or_class in enable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'enabled') for name_or_class in disable or (): config_key = self._component_name(name_or_class) self.config.set('components', config_key, 'disabled') # -- logging from trac.log import logger_handler_factory self.log, self._log_handler = logger_handler_factory('test') # -- database self.config.set('components', 'trac.db.*', 'enabled') self.dburi = get_dburi() init_global = False if self.global_databasemanager: self.components[DatabaseManager] = self.global_databasemanager else: self.config.set('trac', 'database', self.dburi) self.global_databasemanager = DatabaseManager(self) self.config.set('trac', 'debug_sql', True) self.config.set('logging', 'log_type', 'stderr') self.config.set('logging', 'log_level', 'DEBUG') init_global = not destroying if default_data or init_global: self.reset_db(default_data) from trac.web.href import Href self.href = Href('/trac.cgi') self.abs_href = Href('http://example.org/trac.cgi') self.known_users = [] translation.activate(locale_en)
def setUp(self): self.env = EnvironmentStub(default_data=True) self.req = Mock(base_path='', chrome={}, args={}, session={}, abs_href=Href('/'), href=Href('/'), locale='', perm=MockPerm(), authname=None, tz=None) self.report_module = ReportModule(self.env)
def _get_jquery_ui_script_data(self, lc_time): req = Request(href=Href('/trac.cgi'), tz=utc, lc_time=lc_time) Chrome(self.env).add_jquery_ui(req) return req.chrome['script_data']['jquery_ui']
def abs_href(self): """The application URL""" if not self.base_url: self.log.warning("base_url option not set in configuration, " "generated links may be incorrect") return Href(self.base_url)
def setUp(self): self.env = EnvironmentStub(default_data=True) self.query_module = QueryModule(self.env) req = Mock(perm=MockPerm(), args={}, href=Href('/')) self.formatter = LinkFormatter(self.env, web_context(req))
def test_process_build_step_success_with_log(self): recipe = """<build> <step id="foo"> </step> </build>""" BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.slave_info[Build.TOKEN] = '123' build.insert() inbody = StringIO("""<result step="foo" status="success" time="2007-04-01T15:30:00.0000" duration="3.45"> <log generator="http://bitten.edgewall.org/tools/python#unittest"> <message level="info">Doing stuff</message> <message level="error">Ouch that hurt</message> </log> </result>""") outheaders = {} outbody = StringIO() req = Mock(method='POST', base_path='', path_info='/builds/%d/steps/' % build.id, href=Href('/trac'), abs_href=Href('http://example.org/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), read=inbody.read, send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=123')) module = BuildMaster(self.env) module._start_new_step(build, 'foo').insert() assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(201, outheaders['Status']) self.assertEqual('20', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Build step processed', outbody.getvalue()) build = Build.fetch(self.env, build.id) self.assertEqual(Build.SUCCESS, build.status) assert build.stopped assert build.stopped > build.started steps = list(BuildStep.select(self.env, build.id)) self.assertEqual(1, len(steps)) self.assertEqual('foo', steps[0].name) self.assertEqual(BuildStep.SUCCESS, steps[0].status) logs = list(BuildLog.select(self.env, build=build.id, step='foo')) self.assertEqual(1, len(logs)) self.assertEqual('http://bitten.edgewall.org/tools/python#unittest', logs[0].generator) self.assertEqual(2, len(logs[0].messages)) self.assertEqual((u'info', u'Doing stuff'), logs[0].messages[0]) self.assertEqual((u'error', u'Ouch that hurt'), logs[0].messages[1])
def get_href(self, href, *args, **kwargs): href = Href(href.tracforge()) return super(MultiQuery, self).get_href(href, *args, **kwargs)