コード例 #1
0
ファイル: config.py プロジェクト: zxfly/trac
    def __get__(self, instance, owner):
        if instance is None:
            return self
        order = ListOption.__get__(self, instance, owner)
        components = []
        implementing_classes = []
        for impl in self.xtnpt.extensions(instance):
            implementing_classes.append(impl.__class__.__name__)
            if self.include_missing or impl.__class__.__name__ in order:
                components.append(impl)
        not_found = sorted(set(order) - set(implementing_classes))
        if not_found:
            raise ConfigurationError(
                tag_("Cannot find implementation(s) of the %(interface)s "
                     "interface named %(implementation)s. Please check "
                     "that the Component is enabled or update the option "
                     "%(option)s in trac.ini.",
                     interface=tag.code(self.xtnpt.interface.__name__),
                     implementation=tag(
                         (', ' if idx != 0 else None, tag.code(impl))
                         for idx, impl in enumerate(not_found)),
                     option=tag.code("[%s] %s" % (self.section, self.name))))

        def key(impl):
            name = impl.__class__.__name__
            if name in order:
                return 0, order.index(name)
            else:
                return 1, components.index(impl)
        return sorted(components, key=key)
コード例 #2
0
ファイル: macros.py プロジェクト: minimalistduck/trac
    def expand_macro(self, formatter, name, content):
        from trac.mimeview.api import Mimeview
        mime_map = Mimeview(self.env).mime_map
        mime_type_filter = ''
        args, kw = parse_args(content)
        if args:
            mime_type_filter = args.pop(0).strip().rstrip('*')

        mime_types = {}
        for key, mime_type in mime_map.iteritems():
            if (not mime_type_filter or mime_type.startswith(mime_type_filter)
                ) and key != mime_type:
                mime_types.setdefault(mime_type, []).append(key)

        return tag.div(class_='mimetypes')(
            tag.table(class_='wiki')(
                tag.thead(
                    tag.tr(
                        tag.th(_("MIME Types")),  # always use plural
                        tag.th(
                            tag.a("WikiProcessors",
                                  href=formatter.context.href.wiki(
                                      'WikiProcessors'))))),
                tag.tbody(
                    tag.tr(
                        tag.th(tag.code(mime_type), style="text-align: left"),
                        tag.td(
                            tag.code(' '.join(sorted(mime_types[mime_type])))))
                    for mime_type in sorted(mime_types))))
コード例 #3
0
def _arg_as_int(val, key=None, min=None, max=None):
    int_val = as_int(val, None, min=min, max=max)
    if int_val is None:
        raise MacroError(tag_("Invalid macro argument %(expr)s",
                              expr=tag.code("%s=%s" % (key, val))
                                   if key else tag.code(val)))
    return int_val
コード例 #4
0
ファイル: macros.py プロジェクト: minimalistduck/trac
    def expand_macro(self, formatter, name, content):
        from trac.wiki.formatter import system_message

        content = content.strip() if content else ''
        name_filter = content.strip('*')

        def get_macro_descr():
            for macro_provider in formatter.wiki.macro_providers:
                names = list(macro_provider.get_macros() or [])
                if name_filter and not any(
                        name.startswith(name_filter) for name in names):
                    continue
                try:
                    name_descriptions = [
                        (name, macro_provider.get_macro_description(name))
                        for name in names
                    ]
                except Exception as e:
                    yield system_message(
                        _("Error: Can't get description for macro %(name)s",
                          name=names[0]), e), names
                else:
                    for descr, pairs in groupby(name_descriptions,
                                                key=lambda p: p[1]):
                        if descr:
                            if isinstance(descr, (tuple, list)):
                                descr = dgettext(descr[0],
                                                 to_unicode(descr[1])) \
                                        if descr[1] else ''
                            else:
                                descr = to_unicode(descr) or ''
                            if content == '*':
                                descr = format_to_oneliner(self.env,
                                                           formatter.context,
                                                           descr,
                                                           shorten=True)
                            else:
                                descr = format_to_html(self.env,
                                                       formatter.context,
                                                       descr)
                        yield descr, [name for name, descr in pairs]

        return tag.div(class_='trac-macrolist')(
            (tag.h3(tag.code('[[', names[0], ']]'), id='%s-macro' % names[0]),
             len(names) > 1 and tag.p(
                 tag.strong(_("Aliases:")),
                 [tag.code(' [[', alias, ']]')
                  for alias in names[1:]]) or None,
             description or tag.em(_("Sorry, no documentation found")))
            for description, names in sorted(get_macro_descr(),
                                             key=lambda item: item[1][0]))
コード例 #5
0
ファイル: mail.py プロジェクト: zxfly/trac
    def send(self, from_addr, recipients, message):
        global local_hostname
        # Ensure the message complies with RFC2822: use CRLF line endings
        message = fix_eol(message, CRLF)

        self.log.info("Sending notification through SMTP at %s:%d to %s",
                      self.smtp_server, self.smtp_port, recipients)
        try:
            server = smtplib.SMTP(self.smtp_server, self.smtp_port,
                                  local_hostname)
            local_hostname = server.local_hostname
        except smtplib.socket.error as e:
            raise ConfigurationError(
                tag_(
                    "SMTP server connection error (%(error)s). Please "
                    "modify %(option1)s or %(option2)s in your "
                    "configuration.",
                    error=to_unicode(e),
                    option1=tag.code("[notification] smtp_server"),
                    option2=tag.code("[notification] smtp_port")))
        # server.set_debuglevel(True)
        if self.use_tls:
            server.ehlo()
            if 'starttls' not in server.esmtp_features:
                raise TracError(
                    _("TLS enabled but server does not support"
                      " TLS"))
            server.starttls()
            server.ehlo()
        if self.smtp_user:
            server.login(self.smtp_user.encode('utf-8'),
                         self.smtp_password.encode('utf-8'))
        start = time_now()
        server.sendmail(from_addr, recipients, message)
        t = time_now() - start
        if t > 5:
            self.log.warning(
                "Slow mail submission (%.2f s), "
                "check your mail setup", t)
        if self.use_tls:
            # avoid false failure detection when the server closes
            # the SMTP connection with TLS enabled
            import socket
            try:
                server.quit()
            except socket.sslerror:
                pass
        else:
            server.quit()
コード例 #6
0
ファイル: config.py プロジェクト: zxfly/trac
 def __get__(self, instance, owner):
     if instance is None:
         return self
     value = Option.__get__(self, instance, owner)
     for impl in self.xtnpt.extensions(instance):
         if impl.__class__.__name__ == value:
             return impl
     raise ConfigurationError(
         tag_("Cannot find an implementation of the %(interface)s "
              "interface named %(implementation)s. Please check "
              "that the Component is enabled or update the option "
              "%(option)s in trac.ini.",
              interface=tag.code(self.xtnpt.interface.__name__),
              implementation=tag.code(value),
              option=tag.code("[%s] %s" % (self.section, self.name))))
コード例 #7
0
ファイル: mail.py プロジェクト: zxfly/trac
    def send(self, from_addr, recipients, message):
        # Use native line endings in message
        message = fix_eol(message, os.linesep)

        self.log.info("Sending notification through sendmail at %s to %s",
                      self.sendmail_path, recipients)
        cmdline = [self.sendmail_path, '-i', '-f', from_addr] + recipients
        self.log.debug("Sendmail command line: %s", cmdline)
        try:
            child = Popen(cmdline,
                          bufsize=-1,
                          stdin=PIPE,
                          stdout=PIPE,
                          stderr=PIPE,
                          close_fds=close_fds)
        except OSError as e:
            raise ConfigurationError(
                tag_(
                    "Sendmail error (%(error)s). Please modify %(option)s "
                    "in your configuration.",
                    error=to_unicode(e),
                    option=tag.code("[notification] sendmail_path")))
        out, err = child.communicate(message)
        if child.returncode or err:
            raise Exception("Sendmail failed with (%s, %s), command: '%s'" %
                            (child.returncode, err.strip(), cmdline))
コード例 #8
0
ファイル: macros.py プロジェクト: minimalistduck/trac
 def default_cell(option):
     default = option.default
     if default is not None and default != '':
         return tag.td(tag.code(option.dumps(default)),
                       class_='default')
     else:
         return tag.td(_("(no default)"), class_='nodefault')
コード例 #9
0
ファイル: api.py プロジェクト: wataash/trac
def _invalid_db_str(db_str):
    return ConfigurationError(
        tag_(
            "Invalid format %(db_str)s for the database connection string. "
            "Please refer to the %(doc)s for help.",
            db_str=tag.code(db_str),
            doc=_doc_db_str()))
コード例 #10
0
    def process_request(self, req):
        parent_realm = req.args.get('realm')
        path = req.args.get('path')

        if not parent_realm or not path:
            raise HTTPBadRequest(_("Bad request"))
        if parent_realm == 'attachment':
            raise TracError(
                tag_("%(realm)s is not a valid parent realm",
                     realm=tag.code(parent_realm)))

        parent_realm = Resource(parent_realm)
        action = req.args.get('action', 'view')
        if action == 'new':
            parent_id, filename = path.rstrip('/'), None
        else:
            last_slash = path.rfind('/')
            if last_slash == -1:
                parent_id, filename = path, ''
            else:
                parent_id, filename = path[:last_slash], path[last_slash + 1:]

        parent = parent_realm(id=parent_id)
        if not resource_exists(self.env, parent):
            raise ResourceNotFound(
                _("Parent resource %(parent)s doesn't exist",
                  parent=get_resource_name(self.env, parent)))

        # Link the attachment page to parent resource
        parent_name = get_resource_name(self.env, parent)
        parent_url = get_resource_url(self.env, parent, req.href)
        add_link(req, 'up', parent_url, parent_name)
        add_ctxtnav(req, _("Back to %(parent)s", parent=parent_name),
                    parent_url)

        if not filename:  # there's a trailing '/'
            if req.args.get('format') == 'zip':
                self._download_as_zip(req, parent)
            elif action != 'new':
                return self._render_list(req, parent)

        attachment = Attachment(self.env, parent.child(self.realm, filename))

        if req.method == 'POST':
            if action == 'new':
                data = self._do_save(req, attachment)
            elif action == 'delete':
                self._do_delete(req, attachment)
            else:
                raise HTTPBadRequest(_("Invalid request arguments."))
        elif action == 'delete':
            data = self._render_confirm_delete(req, attachment)
        elif action == 'new':
            data = self._render_form(req, attachment)
        else:
            data = self._render_view(req, attachment)

        add_stylesheet(req, 'common/css/code.css')
        return 'attachment.html', data
コード例 #11
0
    def __init__(self, path, log=None, params={}):
        self.cnx = None
        if path != ':memory:':
            if not os.access(path, os.F_OK):
                raise ConfigurationError(
                    _('Database "%(path)s" not found.', path=path))

            dbdir = os.path.dirname(path)
            if not os.access(path, os.R_OK + os.W_OK) or \
                    not os.access(dbdir, os.R_OK + os.W_OK):
                raise ConfigurationError(
                    tag_(
                        "The user %(user)s requires read _and_ write permissions "
                        "to the database file %(path)s and the directory it is "
                        "located in.",
                        user=tag.code(getuser()),
                        path=tag.code(path)))

        self._active_cursors = weakref.WeakKeyDictionary()
        timeout = int(params.get('timeout', 10.0))
        self._eager = params.get('cursor', 'eager') == 'eager'
        # eager is default, can be turned off by specifying ?cursor=
        if isinstance(path, unicode):  # needed with 2.4.0
            path = path.encode('utf-8')
        cnx = sqlite.connect(path,
                             detect_types=sqlite.PARSE_DECLTYPES,
                             isolation_level=None,
                             check_same_thread=sqlite_version < (3, 3, 1),
                             timeout=timeout)
        # load extensions
        extensions = params.get('extensions', [])
        if len(extensions) > 0:
            cnx.enable_load_extension(True)
            for ext in extensions:
                cnx.load_extension(ext)
            cnx.enable_load_extension(False)

        with closing(cnx.cursor()) as cursor:
            _set_journal_mode(cursor, params.get('journal_mode'))
            set_synchronous(cursor, params.get('synchronous'))
        cnx.isolation_level = 'DEFERRED'
        ConnectionWrapper.__init__(self, cnx, log)
コード例 #12
0
ファイル: main.py プロジェクト: wataash/trac
    def _get_valid_default_handler(self, req):
        # Use default_handler from the Session if it is a valid value.
        name = req.session.get('default_handler')
        handler = self._request_handlers.get(name)
        if handler and not is_valid_default_handler(handler):
            handler = None

        if not handler:
            # Use default_handler from project configuration.
            handler = self.default_handler
            if not is_valid_default_handler(handler):
                raise ConfigurationError(
                    tag_("%(handler)s is not a valid default handler. Please "
                         "update %(option)s through the %(page)s page or by "
                         "directly editing trac.ini.",
                         handler=tag.code(handler.__class__.__name__),
                         option=tag.code("[trac] default_handler"),
                         page=tag.a(_("Basic Settings"),
                                    href=req.href.admin('general/basics'))))
        return handler
コード例 #13
0
ファイル: macros.py プロジェクト: minimalistduck/trac
 def options_table(section, options):
     if options:
         return tag.table(class_='wiki')(tag.tbody(
             tag.tr(tag.td(
                 tag.a(tag.code(option.name),
                       class_='tracini-option',
                       href='#%s-%s-option' % (section, option.name))),
                    tag.td(
                        format_to_html(self.env, formatter.context,
                                       option.doc)),
                    default_cell(option),
                    id='%s-%s-option' % (section, option.name),
                    class_='odd' if idx % 2 else 'even')
             for idx, option in enumerate(options)))
コード例 #14
0
ファイル: prefs.py プロジェクト: rwbaumg/trac
    def expand_macro(self, formatter, name, content):
        content = content.strip() if content else ''
        name_filter = content.strip('*')
        items = {}
        for subscriber in NotificationSystem(self.env).subscribers:
            name = subscriber.__class__.__name__
            if not name_filter or name.startswith(name_filter):
                items[name] = subscriber.description()

        return tag.div(class_='trac-subscriberlist')(tag.table(class_='wiki')(
            tag.thead(tag.tr(tag.th(_("Subscriber")),
                             tag.th(_("Description")))),
            tag.tbody(
                tag.tr(tag.td(tag.code(name)),
                       tag.td(items[name]),
                       class_='odd' if idx % 2 else 'even')
                for idx, name in enumerate(sorted(items)))))
コード例 #15
0
    def _provider_failure(self, exc, req, ep, current_filters, all_filters):
        """Raise a TracError exception explaining the failure of a provider.

        At the same time, the message will contain a link to the timeline
        without the filters corresponding to the guilty event provider `ep`.
        """
        self.log.error("Timeline event provider failed: %s",
                       exception_to_unicode(exc, traceback=True))

        ep_kinds = {f[0]: f[1] for f in ep.get_timeline_filters(req) or []}
        ep_filters = set(ep_kinds.keys())
        current_filters = set(current_filters)
        other_filters = set(current_filters) - ep_filters
        if not other_filters:
            other_filters = set(all_filters) - ep_filters
        args = [(a, req.args.get(a))
                for a in ('from', 'format', 'max', 'daysback')]
        href = req.href.timeline(args + [(f, 'on') for f in other_filters])
        # TRANSLATOR: ...want to see the 'other kinds of events' from... (link)
        other_events = tag.a(_('other kinds of events'), href=href)
        raise TracError(
            tag(
                tag.p(tag_(
                    "Event provider %(name)s failed for filters "
                    "%(kinds)s: ",
                    name=tag.code(ep.__class__.__name__),
                    kinds=', '.join('"%s"' % ep_kinds[f]
                                    for f in current_filters & ep_filters)),
                      tag.strong(exception_to_unicode(exc)),
                      class_='message'),
                tag.p(
                    tag_(
                        "You may want to see the %(other_events)s from the "
                        "Timeline or notify your Trac administrator about the "
                        "error (detailed information was written to the log).",
                        other_events=other_events))))
コード例 #16
0
ファイル: admin.py プロジェクト: skshel123/trac
    def render_admin_panel(self, req, category, page, path_info):
        # Retrieve info for all repositories
        rm = RepositoryManager(self.env)
        all_repos = rm.get_all_repositories()
        db_provider = self.env[DbRepositoryProvider]

        if path_info:
            # Detail view
            reponame = path_info if not is_default(path_info) else ''
            info = all_repos.get(reponame)
            if info is None:
                raise TracError(
                    _("Repository '%(repo)s' not found", repo=path_info))
            if req.method == 'POST':
                if req.args.get('cancel'):
                    req.redirect(req.href.admin(category, page))

                elif db_provider and req.args.get('save'):
                    # Modify repository
                    changes = {}
                    valid = True
                    for field in db_provider.repository_attrs:
                        value = normalize_whitespace(req.args.get(field))
                        if (value is not None
                            or field in ('hidden', 'sync_per_request')) \
                                and value != info.get(field):
                            changes[field] = value
                    if 'dir' in changes and not \
                            self._check_dir(req, changes['dir']):
                        valid = False
                    if valid and changes:
                        db_provider.modify_repository(reponame, changes)
                        add_notice(req, _('Your changes have been saved.'))
                        name = req.args.get('name')
                        pretty_name = name or '(default)'
                        resync = tag.code('trac-admin "%s" repository resync '
                                          '"%s"' %
                                          (self.env.path, pretty_name))
                        if 'dir' in changes:
                            msg = tag_(
                                'You should now run %(resync)s to '
                                'synchronize Trac with the repository.',
                                resync=resync)
                            add_notice(req, msg)
                        elif 'type' in changes:
                            msg = tag_(
                                'You may have to run %(resync)s to '
                                'synchronize Trac with the repository.',
                                resync=resync)
                            add_notice(req, msg)
                        if name and name != path_info and 'alias' not in info:
                            cset_added = tag.code('trac-admin "%s" changeset '
                                                  'added "%s" $REV' %
                                                  (self.env.path, pretty_name))
                            msg = tag_(
                                'You will need to update your '
                                'post-commit hook to call '
                                '%(cset_added)s with the new '
                                'repository name.',
                                cset_added=cset_added)
                            add_notice(req, msg)
                    if valid:
                        req.redirect(req.href.admin(category, page))

            chrome = Chrome(self.env)
            chrome.add_wiki_toolbars(req)
            chrome.add_auto_preview(req)
            data = {'view': 'detail', 'reponame': reponame}

        else:
            # List view
            if req.method == 'POST':
                # Add a repository
                if db_provider and req.args.get('add_repos'):
                    name = req.args.get('name')
                    pretty_name = name or '(default)'
                    if name in all_repos:
                        raise TracError(
                            _('The repository "%(name)s" already '
                              'exists.',
                              name=pretty_name))
                    type_ = req.args.get('type')
                    # Avoid errors when copy/pasting paths
                    dir = normalize_whitespace(req.args.get('dir', ''))
                    if name is None or type_ is None or not dir:
                        add_warning(
                            req, _('Missing arguments to add a '
                                   'repository.'))
                    elif self._check_dir(req, dir):
                        db_provider.add_repository(name, dir, type_)
                        add_notice(
                            req,
                            _('The repository "%(name)s" has been '
                              'added.',
                              name=pretty_name))
                        resync = tag.code('trac-admin "%s" repository resync '
                                          '"%s"' %
                                          (self.env.path, pretty_name))
                        msg = tag_(
                            'You should now run %(resync)s to '
                            'synchronize Trac with the repository.',
                            resync=resync)
                        add_notice(req, msg)
                        cset_added = tag.code('trac-admin "%s" changeset '
                                              'added "%s" $REV' %
                                              (self.env.path, pretty_name))
                        doc = tag.a(_("documentation"),
                                    href=req.href.wiki('TracRepositoryAdmin') +
                                    '#Synchronization')
                        msg = tag_(
                            'You should also set up a post-commit hook '
                            'on the repository to call %(cset_added)s '
                            'for each committed changeset. See the '
                            '%(doc)s for more information.',
                            cset_added=cset_added,
                            doc=doc)
                        add_notice(req, msg)

                # Add a repository alias
                elif db_provider and req.args.get('add_alias'):
                    name = req.args.get('name')
                    pretty_name = name or '(default)'
                    alias = req.args.get('alias')
                    if name is not None and alias is not None:
                        try:
                            db_provider.add_alias(name, alias)
                        except self.env.db_exc.IntegrityError:
                            raise TracError(
                                _('The alias "%(name)s" already '
                                  'exists.',
                                  name=pretty_name))
                        add_notice(
                            req,
                            _('The alias "%(name)s" has been '
                              'added.',
                              name=pretty_name))
                    else:
                        add_warning(req,
                                    _('Missing arguments to add an '
                                      'alias.'))

                # Refresh the list of repositories
                elif req.args.get('refresh'):
                    pass

                # Remove repositories
                elif db_provider and req.args.get('remove'):
                    sel = req.args.getlist('sel')
                    if sel:
                        for name in sel:
                            db_provider.remove_repository(name)
                        add_notice(
                            req,
                            _('The selected repositories have '
                              'been removed.'))
                    else:
                        add_warning(req, _('No repositories were selected.'))

                req.redirect(req.href.admin(category, page))

            data = {'view': 'list'}

        # Find repositories that are editable
        db_repos = {}
        if db_provider is not None:
            db_repos = dict(db_provider.get_repositories())

        # Prepare common rendering data
        repositories = {
            reponame: self._extend_info(reponame, info.copy(), reponame
                                        in db_repos)
            for (reponame, info) in all_repos.iteritems()
        }
        types = sorted([''] + rm.get_supported_types())
        data.update({
            'types':
            types,
            'default_type':
            rm.default_repository_type,
            'repositories':
            repositories,
            'can_add_alias':
            any('alias' not in info for info in repositories.itervalues())
        })

        return 'admin_repositories.html', data
コード例 #17
0
    def render_admin_panel(self, req, cat, page, path_info):
        log_type = self.env.log_type
        log_level = self.env.log_level
        log_file = self.env.log_file
        log_dir = self.env.log_dir

        log_types = [
            dict(name='none',
                 label=_("None"),
                 selected=log_type == 'none',
                 disabled=False),
            dict(name='stderr',
                 label=_("Console"),
                 selected=log_type == 'stderr',
                 disabled=False),
            dict(name='file',
                 label=_("File"),
                 selected=log_type == 'file',
                 disabled=False),
            dict(name='syslog',
                 label=_("Syslog"),
                 selected=log_type in ('unix', 'syslog'),
                 disabled=os.name != 'posix'),
            dict(name='eventlog',
                 label=_("Windows event log"),
                 selected=log_type in ('winlog', 'eventlog', 'nteventlog'),
                 disabled=os.name != 'nt'),
        ]

        if req.method == 'POST':
            changed = False

            new_type = req.args.get('log_type')
            if new_type not in [t['name'] for t in log_types]:
                raise TracError(_("Unknown log type %(type)s", type=new_type),
                                _("Invalid log type"))
            new_file = req.args.get('log_file', 'trac.log')
            if not new_file:
                raise TracError(_("You must specify a log file"),
                                _("Missing field"))
            new_level = req.args.get('log_level')
            if new_level not in LOG_LEVELS:
                raise TracError(
                    _("Unknown log level %(level)s", level=new_level),
                    _("Invalid log level"))

            # Create logger to be sure the configuration is valid.
            new_file_path = new_file
            if not os.path.isabs(new_file_path):
                new_file_path = os.path.join(self.env.log_dir, new_file)
            try:
                logger, handler = \
                    self.env.create_logger(new_type, new_file_path, new_level,
                                           self.env.log_format)
            except Exception as e:
                add_warning(
                    req,
                    tag_(
                        "Changes not saved. Logger configuration "
                        "error: %(error)s. Inspect the log for more "
                        "information.",
                        error=tag.code(exception_to_unicode(e))))
                self.log.error("Logger configuration error: %s",
                               exception_to_unicode(e, traceback=True))
            else:
                handler.close()
                if new_type != log_type:
                    self.config.set('logging', 'log_type', new_type)
                    changed = True
                    log_type = new_type

                if log_type == 'none':
                    self.config.remove('logging', 'log_level')
                    changed = True
                else:
                    if new_level != log_level:
                        self.config.set('logging', 'log_level', new_level)
                        changed = True
                        log_level = new_level

                if log_type == 'file':
                    if new_file != log_file:
                        self.config.set('logging', 'log_file', new_file)
                        changed = True
                        log_file = new_file
                else:
                    self.config.remove('logging', 'log_file')
                    changed = True

            if changed:
                _save_config(self.config, req, self.log),
            req.redirect(req.href.admin(cat, page))

        data = {
            'type': log_type,
            'types': log_types,
            'level': log_level,
            'levels': LOG_LEVELS,
            'file': log_file,
            'dir': log_dir
        }
        return 'admin_logging.html', {'log': data}
コード例 #18
0
ファイル: api.py プロジェクト: wataash/trac
def parse_connection_uri(db_str):
    """Parse the database connection string.

    The database connection string for an environment is specified through
    the `database` option in the `[trac]` section of trac.ini.

    :return: a tuple containing the scheme and a dictionary of attributes:
             `user`, `password`, `host`, `port`, `path`, `params`.
    :since: 1.1.3
    """
    if not db_str:
        section = tag.a("[trac]",
                        title=_("TracIni documentation"),
                        class_='trac-target-new',
                        href='https://trac.edgewall.org/wiki/TracIni'
                        '#trac-section')
        raise ConfigurationError(
            tag_(
                "Database connection string is empty. Set the %(option)s "
                "configuration option in the %(section)s section of "
                "trac.ini. Please refer to the %(doc)s for help.",
                option=tag.code("database"),
                section=section,
                doc=_doc_db_str()))

    try:
        scheme, rest = db_str.split(':', 1)
    except ValueError:
        raise _invalid_db_str(db_str)

    if not rest.startswith('/'):
        if scheme == 'sqlite' and rest:
            # Support for relative and in-memory SQLite connection strings
            host = None
            path = rest
        else:
            raise _invalid_db_str(db_str)
    else:
        if not rest.startswith('//'):
            host = None
            rest = rest[1:]
        elif rest.startswith('///'):
            host = None
            rest = rest[3:]
        else:
            rest = rest[2:]
            if '/' in rest:
                host, rest = rest.split('/', 1)
            else:
                host = rest
                rest = ''
        path = None

    if host and '@' in host:
        user, host = host.split('@', 1)
        if ':' in user:
            user, password = user.split(':', 1)
        else:
            password = None
        if user:
            user = urllib.unquote(user)
        if password:
            password = unicode_passwd(urllib.unquote(password))
    else:
        user = password = None

    if host and ':' in host:
        host, port = host.split(':', 1)
        try:
            port = int(port)
        except ValueError:
            raise _invalid_db_str(db_str)
    else:
        port = None

    if not path:
        path = '/' + rest
    if os.name == 'nt':
        # Support local paths containing drive letters on Win32
        if len(rest) > 1 and rest[1] == '|':
            path = "%s:%s" % (rest[0], rest[2:])

    params = {}
    if '?' in path:
        path, qs = path.split('?', 1)
        qs = qs.split('&')
        for param in qs:
            try:
                name, value = param.split('=', 1)
            except ValueError:
                raise _invalid_db_str(db_str)
            value = urllib.unquote(value)
            params[name] = value

    args = zip(('user', 'password', 'host', 'port', 'path', 'params'),
               (user, password, host, port, path, params))
    return scheme, {key: value for key, value in args if value}
コード例 #19
0
ファイル: macros.py プロジェクト: minimalistduck/trac
    def expand_macro(self, formatter, name, content):
        from trac.config import ConfigSection, Option

        args, kw = parse_args(content)
        filters = {}
        for name, index in (('section', 0), ('option', 1)):
            pattern = kw.get(name, '').strip()
            if pattern:
                filters[name] = fnmatch.translate(pattern)
                continue
            prefix = args[index].strip() if index < len(args) else ''
            if prefix:
                filters[name] = re.escape(prefix)
        has_option_filter = 'option' in filters
        for name in ('section', 'option'):
            filters[name] = re.compile(filters[name], re.IGNORECASE).match \
                            if name in filters \
                            else lambda v: True
        section_filter = filters['section']
        option_filter = filters['option']

        section_registry = ConfigSection.get_registry(self.compmgr)
        option_registry = Option.get_registry(self.compmgr)
        options = {}
        for (section, key), option in option_registry.iteritems():
            if section_filter(section) and option_filter(key):
                options.setdefault(section, {})[key] = option
        if not has_option_filter:
            for section in section_registry:
                if section_filter(section):
                    options.setdefault(section, {})
        for section in options:
            options[section] = sorted(options[section].itervalues(),
                                      key=lambda option: option.name)
        sections = [(section, section_registry[section].doc
                     if section in section_registry else '')
                    for section in sorted(options)]

        def default_cell(option):
            default = option.default
            if default is not None and default != '':
                return tag.td(tag.code(option.dumps(default)),
                              class_='default')
            else:
                return tag.td(_("(no default)"), class_='nodefault')

        def options_table(section, options):
            if options:
                return tag.table(class_='wiki')(tag.tbody(
                    tag.tr(tag.td(
                        tag.a(tag.code(option.name),
                              class_='tracini-option',
                              href='#%s-%s-option' % (section, option.name))),
                           tag.td(
                               format_to_html(self.env, formatter.context,
                                              option.doc)),
                           default_cell(option),
                           id='%s-%s-option' % (section, option.name),
                           class_='odd' if idx % 2 else 'even')
                    for idx, option in enumerate(options)))

        return tag.div(class_='tracini')(
            (tag.h3(tag.code('[%s]' % section), id='%s-section' % section),
             format_to_html(self.env, formatter.context, section_doc),
             options_table(section, options.get(section)))
            for section, section_doc in sections)
コード例 #20
0
ファイル: default_workflow.py プロジェクト: hanotch/trac
    def expand_macro(self, formatter, name, content, args=None):
        if content is not None:
            content = content.strip()
        if not args and not content:
            raw_actions = self.config.options('ticket-workflow')
        else:
            is_macro = args is None
            if is_macro:
                kwargs = parse_args(content)[1]
                file = kwargs.get('file')
            else:
                file = args.get('file')
                if not file and not content:
                    raise ProcessorError("Invalid argument(s).")

            if file:
                print(file)
                text = RepositoryManager(self.env).read_file_by_path(file)
                if text is None:
                    raise ProcessorError(
                        tag_("The file %(file)s does not exist.",
                             file=tag.code(file)))
            elif is_macro:
                text = '\n'.join(line.lstrip() for line in content.split(';'))
            else:
                text = content

            if '[ticket-workflow]' not in text:
                text = '[ticket-workflow]\n' + text
            parser = RawConfigParser()
            try:
                parser.readfp(io.StringIO(text))
            except ParsingError as e:
                if is_macro:
                    raise MacroError(exception_to_unicode(e))
                else:
                    raise ProcessorError(exception_to_unicode(e))
            raw_actions = list(parser.items('ticket-workflow'))
        actions = parse_workflow_config(raw_actions)
        states = list(
            {state for action in actions.itervalues()
                   for state in action['oldstates']} |
            {action['newstate'] for action in actions.itervalues()})
        action_labels = [attrs['label'] for attrs in actions.values()]
        action_names = list(actions)
        edges = []
        for name, action in actions.items():
            new_index = states.index(action['newstate'])
            name_index = action_names.index(name)
            for old_state in action['oldstates']:
                old_index = states.index(old_state)
                edges.append((old_index, new_index, name_index))

        args = args or {}
        width = args.get('width', 800)
        height = args.get('height', 600)
        graph = {'nodes': states, 'actions': action_labels, 'edges': edges,
                 'width': width, 'height': height}
        graph_id = '%012x' % id(graph)
        req = formatter.req
        add_script(req, 'common/js/excanvas.js', ie_if='IE')
        add_script(req, 'common/js/workflow_graph.js')
        add_script_data(req, {'graph_%s' % graph_id: graph})
        return tag(
            tag.div('', class_='trac-workflow-graph trac-noscript',
                    id='trac-workflow-graph-%s' % graph_id,
                    style="display:inline-block;width:%spx;height:%spx" %
                          (width, height)),
            tag.noscript(
                tag.div(_("Enable JavaScript to display the workflow graph."),
                        class_='system-message')))