Example #1
0
    def test_iter_nodes(self):
        self._git_init(data=False)
        self._git_fast_import(self._data_iter_nodes)
        self._add_repository('gitrepos')
        repos = self._repomgr.get_repository('gitrepos')
        repos.sync()
        mod = BrowserModule(self.env)

        root_node = repos.get_node('')
        nodes = list(mod._iter_nodes(root_node))
        self.assertEqual(['79dff4ccf842f8e2d2da2ee3e7a2149df63b099b'] * 7,
                         [node.rev for node in nodes])
        self.assertEqual([
            ('79dff4ccf842f8e2d2da2ee3e7a2149df63b099b', ''),
            ('64e12f96b6b3040cd9edc225734ab2b26a03758b', 'A'),
            ('64e12f96b6b3040cd9edc225734ab2b26a03758b', 'A/a1.txt'),
            ('67fdcf11e2d083b123b9a79be4fce0600f313f81', 'A/a2.txt'),
            ('42fbe758709b2a65aba33e56b2f53cd126c190e3', 'B'),
            ('998bf23843c8fd982bbc23f88ec33c4d08114557', 'B/b1.txt'),
            ('42fbe758709b2a65aba33e56b2f53cd126c190e3', 'B/b2.txt'),
            ], [(node.created_rev, node.path) for node in nodes])

        root_node = repos.get_node('',
                                   '86387120095e9e43573bce61b9da70a8c5d1c1b9')
        nodes = list(mod._iter_nodes(root_node))
        self.assertEqual(['86387120095e9e43573bce61b9da70a8c5d1c1b9'] * 7,
                         [node.rev for node in nodes])
        self.assertEqual([
            ('86387120095e9e43573bce61b9da70a8c5d1c1b9', ''),
            ('64e12f96b6b3040cd9edc225734ab2b26a03758b', 'A'),
            ('64e12f96b6b3040cd9edc225734ab2b26a03758b', 'A/a1.txt'),
            ('67fdcf11e2d083b123b9a79be4fce0600f313f81', 'A/a2.txt'),
            ('24d94dc08eb77438e4ead192b3f7d1c7bdf1a9e1', 'B'),
            ('998bf23843c8fd982bbc23f88ec33c4d08114557', 'B/b1.txt'),
            ('24d94dc08eb77438e4ead192b3f7d1c7bdf1a9e1', 'B/b2.txt'),
            ], [(node.created_rev, node.path) for node in nodes])

        root_commit = 'c5b01c74e125aa034a1d4ae31dc16f1897a73779'
        root_node = repos.get_node('', root_commit)
        nodes = list(mod._iter_nodes(root_node))
        self.assertEqual([root_commit] * 7, [node.rev for node in nodes])
        self.assertEqual([
            (root_commit, ''),
            (root_commit, 'A'),
            (root_commit, 'A/a1.txt'),
            (root_commit, 'A/a2.txt'),
            (root_commit, 'B'),
            (root_commit, 'B/b1.txt'),
            (root_commit, 'B/b2.txt'),
            ], [(node.created_rev, node.path) for node in nodes])
Example #2
0
    def _test_on_empty_repos(self, cached_repository):
        self.env.config.set('git', 'persistent_cache', 'false')
        self.env.config.set('git', 'cached_repository',
                            'true' if cached_repository else 'false')

        self._git_init(data=False, bare=True)
        self._add_repository(bare=True)
        repos = self._repomgr.get_repository('gitrepos')
        if cached_repository:
            # call sync() thrice with empty repository (#11851)
            for i in xrange(3):
                repos.sync()
                rows = self.env.db_query("SELECT value FROM repository "
                                         "WHERE id=%s AND name=%s",
                                         (repos.id, 'youngest_rev'))
                self.assertEqual('', rows[0][0])
        else:
            repos.sync()
        youngest_rev = repos.youngest_rev
        self.assertIsNone(youngest_rev)
        self.assertIsNone(repos.oldest_rev)
        self.assertIsNone(repos.normalize_rev(''))
        self.assertIsNone(repos.normalize_rev(None))
        self.assertIsNone(repos.display_rev(''))
        self.assertIsNone(repos.display_rev(None))
        self.assertIsNone(repos.short_rev(''))
        self.assertIsNone(repos.short_rev(None))

        node = repos.get_node('/', youngest_rev)
        self.assertEqual([], list(node.get_entries()))
        self.assertEqual([], list(node.get_history()))
        self.assertRaises(NoSuchNode, repos.get_node, '/path', youngest_rev)

        req = MockRequest(self.env, path_info='/browser/gitrepos')
        browser_mod = BrowserModule(self.env)
        self.assertTrue(browser_mod.match_request(req))
        rv = browser_mod.process_request(req)
        self.assertEqual('browser.html', rv[0])
        self.assertIsNone(rv[1]['rev'])

        req = MockRequest(self.env, path_info='/log/gitrepos')
        log_mod = LogModule(self.env)
        self.assertTrue(log_mod.match_request(req))
        rv = log_mod.process_request(req)
        self.assertEqual('revisionlog.html', rv[0])
        self.assertEqual([], rv[1]['items'])
Example #3
0
    def _test_on_empty_repos(self, cached_repository):
        self.env.config.set('git', 'persistent_cache', 'false')
        self.env.config.set('git', 'cached_repository',
                            'true' if cached_repository else 'false')

        self._git_init(data=False, bare=True)
        self._add_repository(bare=True)
        repos = self._repomgr.get_repository('gitrepos')
        if cached_repository:
            # call sync() thrice with empty repository (#11851)
            for i in xrange(3):
                repos.sync()
                rows = self.env.db_query("SELECT value FROM repository "
                                         "WHERE id=%s AND name=%s",
                                         (repos.id, 'youngest_rev'))
                self.assertEqual('', rows[0][0])
        else:
            repos.sync()
        youngest_rev = repos.youngest_rev
        self.assertEqual(None, youngest_rev)
        self.assertEqual(None, repos.oldest_rev)
        self.assertEqual(None, repos.normalize_rev(''))
        self.assertEqual(None, repos.normalize_rev(None))

        node = repos.get_node('/', youngest_rev)
        self.assertEqual([], list(node.get_entries()))
        self.assertEqual([], list(node.get_history()))
        self.assertRaises(NoSuchNode, repos.get_node, '/path', youngest_rev)

        req = self._create_req(path_info='/browser/gitrepos')
        browser_mod = BrowserModule(self.env)
        self.assertTrue(browser_mod.match_request(req))
        rv = browser_mod.process_request(req)
        self.assertEqual('browser.html', rv[0])
        self.assertEqual(None, rv[1]['rev'])

        req = self._create_req(path_info='/log/gitrepos')
        log_mod = LogModule(self.env)
        self.assertTrue(log_mod.match_request(req))
        rv = log_mod.process_request(req)
        self.assertEqual('revisionlog.html', rv[0])
        self.assertEqual([], rv[1]['items'])
Example #4
0
    def _render_html(self, req, repos, chgset, restricted, xhr, data):
        """HTML version"""
        data['restricted'] = restricted
        browser = BrowserModule(self.env)

        if chgset: # Changeset Mode (possibly restricted on a path)
            path, rev = data['new_path'], data['new_rev']

            # -- getting the change summary from the Changeset.get_changes
            def get_changes():
                for npath, kind, change, opath, orev in chgset.get_changes():
                    old_node = new_node = None
                    if (restricted and
                        not (npath == path or                # same path
                             npath.startswith(path + '/') or # npath is below
                             path.startswith(npath + '/'))): # npath is above
                        continue
                    if change != Changeset.ADD:
                        old_node = repos.get_node(opath, orev)
                    if change != Changeset.DELETE:
                        new_node = repos.get_node(npath, rev)
                    yield old_node, new_node, kind, change

            def _changeset_title(rev):
                if restricted:
                    return _('Changeset %(id)s for %(path)s', id=rev,
                             path=path)
                else:
                    return _('Changeset %(id)s', id=rev)

            data['changeset'] = chgset
            title = _changeset_title(rev)

            # Support for revision properties (#2545)
            context = Context.from_request(req, 'changeset', chgset.rev)
            revprops = chgset.get_properties()
            data['properties'] = browser.render_properties('revprop', context,
                                                           revprops)
            oldest_rev = repos.oldest_rev
            if chgset.rev != oldest_rev:
                if restricted:
                    prev = repos.get_node(path, rev).get_previous()
                    if prev:
                        prev_path, prev_rev = prev[:2]
                        if prev_rev:
                            prev_href = req.href.changeset(prev_rev, prev_path)
                    else:
                        prev_path = prev_rev = None
                else:
                    add_link(req, 'first', req.href.changeset(oldest_rev),
                             _('Changeset %(id)s', id=oldest_rev))
                    prev_path = data['old_path']
                    prev_rev = repos.previous_rev(chgset.rev)
                    if prev_rev:
                        prev_href = req.href.changeset(prev_rev)
                if prev_rev:
                    add_link(req, 'prev', prev_href, _changeset_title(prev_rev))
            youngest_rev = repos.youngest_rev
            if str(chgset.rev) != str(youngest_rev):
                if restricted:
                    next_rev = repos.next_rev(chgset.rev, path)
                    if next_rev:
                        if repos.has_node(path, next_rev):
                            next_href = req.href.changeset(next_rev, path)
                        else: # must be a 'D'elete or 'R'ename, show full cset
                            next_href = req.href.changeset(next_rev)
                else:
                    add_link(req, 'last', req.href.changeset(youngest_rev),
                             _('Changeset %(id)s', id=youngest_rev))
                    next_rev = repos.next_rev(chgset.rev)
                    if next_rev:
                        next_href = req.href.changeset(next_rev)
                if next_rev:
                    add_link(req, 'next', next_href, _changeset_title(next_rev))

        else: # Diff Mode
            # -- getting the change summary from the Repository.get_changes
            def get_changes():
                for d in repos.get_changes(
                    new_path=data['new_path'], new_rev=data['new_rev'],
                    old_path=data['old_path'], old_rev=data['old_rev']):
                    yield d
            title = self.title_for_diff(data)
            data['changeset'] = False

        data['title'] = title

        if 'BROWSER_VIEW' not in req.perm:
            return

        def node_info(node, annotated):
            return {'path': node.path,
                    'rev': node.rev,
                    'shortrev': repos.short_rev(node.rev),
                    'href': req.href.browser(node.created_path,
                                             rev=node.created_rev,
                                             annotate=annotated and 'blame' or \
                                                      None),
                    'title': (_('Show revision %(rev)s of this file in browser',
                                rev=node.rev))}
        # Reminder: node.path may not exist at node.rev
        #           as long as node.rev==node.created_rev
        #           ... and data['old_rev'] may have nothing to do
        #           with _that_ node specific history...

        options = data['diff']['options']

        def _prop_changes(old_node, new_node):
            old_source = Resource('source', old_node.created_path,
                                  version=old_node.created_rev)
            new_source = Resource('source', new_node.created_path,
                                  version=new_node.created_rev)
            old_props = new_props = []
            if 'FILE_VIEW' in req.perm(old_source):
                old_props = old_node.get_properties()
            if 'FILE_VIEW' in req.perm(new_source):
                new_props = new_node.get_properties()
            old_ctx = Context.from_request(req, old_source)
            new_ctx = Context.from_request(req, new_source)
            changed_properties = []
            if old_props != new_props:
                for k, v in sorted(old_props.items()):
                    new = old = diff = None
                    if not k in new_props:
                        old = v # won't be displayed, no need to render it
                    elif v != new_props[k]:
                        diff = self.render_property_diff(
                            k, old_ctx, old_props, new_ctx, new_props, options)
                        if not diff:
                            old = browser.render_property(k, 'changeset',
                                                          old_ctx, old_props)
                            new = browser.render_property(k, 'changeset',
                                                          new_ctx, new_props)
                    if new or old or diff:
                        changed_properties.append({'name': k, 'old': old,
                                                   'new': new, 'diff': diff})
                for k, v in sorted(new_props.items()):
                    if not k in old_props:
                        new = browser.render_property(k, 'changeset',
                                                      new_ctx, new_props)
                        if new is not None:
                            changed_properties.append({'name': k, 'new': new,
                                                       'old': None})
            return changed_properties

        def _estimate_changes(old_node, new_node):
            old_size = old_node.get_content_length()
            new_size = new_node.get_content_length()
            return old_size + new_size

        def _content_changes(old_node, new_node):
            """Returns the list of differences.

            The list is empty when no differences between comparable files
            are detected, but the return value is None for non-comparable files.
            """
            mview = Mimeview(self.env)
            if mview.is_binary(old_node.content_type, old_node.path):
                return None
            if mview.is_binary(new_node.content_type, new_node.path):
                return None
            old_content = old_node.get_content().read()
            if mview.is_binary(content=old_content):
                return None
            new_content = new_node.get_content().read()
            if mview.is_binary(content=new_content):
                return None

            old_content = mview.to_unicode(old_content, old_node.content_type)
            new_content = mview.to_unicode(new_content, new_node.content_type)

            if old_content != new_content:
                context = options.get('contextlines', 3)
                if context < 0:
                    context = None
                tabwidth = self.config['diff'].getint('tab_width') or \
                           self.config['mimeviewer'].getint('tab_width', 8)
                ignore_blank_lines = options.get('ignoreblanklines')
                ignore_case = options.get('ignorecase')
                ignore_space = options.get('ignorewhitespace')
                return diff_blocks(old_content.splitlines(),
                                   new_content.splitlines(),
                                   context, tabwidth,
                                   ignore_blank_lines=ignore_blank_lines,
                                   ignore_case=ignore_case,
                                   ignore_space_changes=ignore_space)
            else:
                return []

        if 'FILE_VIEW' in req.perm:
            diff_bytes = diff_files = 0
            if self.max_diff_bytes or self.max_diff_files:
                for old_node, new_node, kind, change in get_changes():
                    if change in Changeset.DIFF_CHANGES and kind == Node.FILE:
                        diff_files += 1
                        diff_bytes += _estimate_changes(old_node, new_node)
            show_diffs = (not self.max_diff_files or \
                          diff_files <= self.max_diff_files) and \
                         (not self.max_diff_bytes or \
                          diff_bytes <= self.max_diff_bytes or \
                          diff_files == 1)
        else:
            show_diffs = False

        # XHR is used for blame support: display the changeset view without
        # the navigation and with the changes concerning the annotated file
        annotated = False
        if xhr:
            show_diffs = False
            annotated = repos.normalize_path(req.args.get('annotate'))

        has_diffs = False
        filestats = self._prepare_filestats()
        changes = []
        files = []
        for old_node, new_node, kind, change in get_changes():
            props = []
            diffs = []
            show_entry = change != Changeset.EDIT
            show_diff = show_diffs or (new_node and new_node.path == annotated)

            if change in Changeset.DIFF_CHANGES and 'FILE_VIEW' in req.perm:
                assert old_node and new_node
                props = _prop_changes(old_node, new_node)
                if props:
                    show_entry = True
                if kind == Node.FILE and show_diff:
                    diffs = _content_changes(old_node, new_node)
                    if diffs != []:
                        if diffs:
                            has_diffs = True
                        # elif None (means: manually compare to (previous))
                        show_entry = True
            if show_entry or not show_diff:
                info = {'change': change,
                        'old': old_node and node_info(old_node, annotated),
                        'new': new_node and node_info(new_node, annotated),
                        'props': props,
                        'diffs': diffs}
                files.append(new_node and new_node.path or \
                             old_node and old_node.path or '')
                filestats[change] += 1
                if change in Changeset.DIFF_CHANGES:
                    if chgset:
                        href = req.href.changeset(new_node.rev, new_node.path)
                        title = _('Show the changeset %(id)s restricted to '
                                  '%(path)s', id=new_node.rev,
                                  path=new_node.path)
                    else:
                        href = req.href.changeset(
                            new_node.created_rev, new_node.created_path,
                            old=old_node.created_rev,
                            old_path=old_node.created_path)
                        title = _('Show the %(range)s differences restricted '
                                  'to %(path)s',
                                  range='r%s:%s' % (old_node.rev, new_node.rev),
                                  path=new_node.path)
                    info['href'] = href
                    info['title'] = old_node and title
                if change in Changeset.DIFF_CHANGES and not show_diff:
                    info['hide_diff'] = True
            else:
                info = None
            changes.append(info) # the sequence should be immutable

        data.update({'has_diffs': has_diffs, 'changes': changes, 'xhr': xhr,
                     'filestats': filestats, 'annotated': annotated,
                     'files': files, 
                     'location': self._get_parent_location(files),
                     'longcol': 'Revision', 'shortcol': 'r'})

        if xhr: # render and return the content only
            stream = Chrome(self.env).render_template(req, 'changeset.html',
                                                      data, fragment=True)
            content = stream.select('//div[@id="content"]')
            str_content = content.render('xhtml')
            req.send_header('Content-Length', len(str_content))
            req.end_headers()
            req.write(str_content)
            raise RequestDone

        return data
Example #5
0
 def get_navigation_items(self, req):
     for category, name, text in \
                     BrowserModule.get_navigation_items(self, req):
         if str(text) == str(tag.a(_('Browse Source'), href=req.href.browser())):
             yield (category, name, tag.a('Source', href=req.href.browser()))
Example #6
0
 def __init__(self):
     BrowserModule.__init__(self, self.compmgr)