Ejemplo n.º 1
0
    def _render_diff(self, req, filename, repos, diff, diff_options):
        """Raw Unified Diff version"""
        req.send_response(200)
        req.send_header('Content-Type', 'text/plain;charset=utf-8')
        req.send_header('Content-Disposition', 'inline;'
                        'filename=%s.diff' % filename)
        req.end_headers()

        mimeview = Mimeview(self.env)
        for old_node, new_node, kind, change in repos.get_changes(**diff):
            # TODO: Property changes

            # Content changes
            if kind == Node.DIRECTORY:
                continue

            new_content = old_content = ''
            new_node_info = old_node_info = ('','')
            mimeview = Mimeview(self.env)

            if old_node:
                old_content = old_node.get_content().read()
                if is_binary(old_content):
                    continue
                old_node_info = (old_node.path, old_node.rev)
                old_content = mimeview.to_unicode(old_content,
                                                  old_node.content_type)
            if new_node:
                new_content = new_node.get_content().read()
                if is_binary(new_content):
                    continue
                new_node_info = (new_node.path, new_node.rev)
                new_path = new_node.path
                new_content = mimeview.to_unicode(new_content,
                                                  new_node.content_type)
            else:
                old_node_path = repos.normalize_path(old_node.path)
                diff_old_path = repos.normalize_path(diff.old_path)
                new_path = posixpath.join(diff.new_path,
                                          old_node_path[len(diff_old_path)+1:])

            if old_content != new_content:
                context = 3
                options = diff_options[1]
                for option in options:
                    if option.startswith('-U'):
                        context = int(option[2:])
                        break
                if not old_node_info[0]:
                    old_node_info = new_node_info # support for 'A'dd changes
                req.write('Index: ' + new_path + CRLF)
                req.write('=' * 67 + CRLF)
                req.write('--- %s (revision %s)' % old_node_info + CRLF)
                req.write('+++ %s (revision %s)' % new_node_info + CRLF)
                for line in unified_diff(old_content.splitlines(),
                                         new_content.splitlines(), context,
                                         ignore_blank_lines='-B' in options,
                                         ignore_case='-i' in options,
                                         ignore_space_changes='-b' in options):
                    req.write(line + CRLF)
Ejemplo n.º 2
0
    def _render_diff(self, req, filename, repos, diff, diff_options):
        """Raw Unified Diff version"""
        req.send_response(200)
        req.send_header('Content-Type', 'text/plain;charset=utf-8')
        req.send_header('Content-Disposition', 'inline;'
                        'filename=%s.diff' % filename)
        req.end_headers()

        mimeview = Mimeview(self.env)
        for old_node, new_node, kind, change in repos.get_changes(**diff):
            # TODO: Property changes

            # Content changes
            if kind == Node.DIRECTORY:
                continue

            new_content = old_content = ''
            new_node_info = old_node_info = ('','')
            mimeview = Mimeview(self.env)

            if old_node:
                old_content = old_node.get_content().read()
                if is_binary(old_content):
                    continue
                old_node_info = (old_node.path, old_node.rev)
                old_content = mimeview.to_unicode(old_content,
                                                  old_node.content_type)
            if new_node:
                new_content = new_node.get_content().read()
                if is_binary(new_content):
                    continue
                new_node_info = (new_node.path, new_node.rev)
                new_path = new_node.path
                new_content = mimeview.to_unicode(new_content,
                                                  new_node.content_type)
            else:
                old_node_path = repos.normalize_path(old_node.path)
                diff_old_path = repos.normalize_path(diff.old_path)
                new_path = posixpath.join(diff.new_path,
                                          old_node_path[len(diff_old_path)+1:])

            if old_content != new_content:
                context = 3
                options = diff_options[1]
                for option in options:
                    if option.startswith('-U'):
                        context = int(option[2:])
                        break
                if not old_node_info[0]:
                    old_node_info = new_node_info # support for 'A'dd changes
                req.write('Index: ' + new_path + CRLF)
                req.write('=' * 67 + CRLF)
                req.write('--- %s (revision %s)' % old_node_info + CRLF)
                req.write('+++ %s (revision %s)' % new_node_info + CRLF)
                for line in unified_diff(old_content.splitlines(),
                                         new_content.splitlines(), context,
                                         ignore_blank_lines='-B' in options,
                                         ignore_case='-i' in options,
                                         ignore_space_changes='-b' in options):
                    req.write(line + CRLF)
Ejemplo n.º 3
0
    def notify(self,
               action,
               page,
               version=None,
               time=None,
               comment=None,
               author=None,
               ipnr=None,
               redirect=False,
               old_name=None):
        self.page = page
        self.change_author = author
        self.time = time
        self.action = action
        self.version = version
        self.redirect = redirect
        self.old_name = old_name
        #        self.env.log.debug("Notify Action: %s", action)
        #        self.env.log.debug("Page time: %r, %s", time, time)

        if action == "added":
            self.newwiki = True

        self.data['name'] = page.name
        self.data['old_name'] = old_name
        self.data['redirect'] = redirect
        self.data['text'] = page.text
        self.data['version'] = version
        self.data['author'] = author
        self.data['comment'] = comment
        self.data['ip'] = ipnr
        self.data['action'] = action
        self.data['link'] = self.env.abs_href.wiki(page.name)
        self.data['linkdiff'] = self.env.abs_href.wiki(page.name,
                                                       action='diff',
                                                       version=page.version)
        if page.version > 0 and action == 'modified':
            diff = diff_header % {
                'name': self.page.name,
                'version': self.page.version,
                'oldversion': self.page.version - 1
            }
            oldpage = WikiPage(self.env, page.name, page.version - 1)
            self.data["oldversion"] = oldpage.version
            self.data["oldtext"] = oldpage.text
            for line in unified_diff(oldpage.text.splitlines(),
                                     page.text.splitlines(),
                                     context=3):
                diff += "%s\n" % line
                self.wikidiff = diff
        self.data["wikidiff"] = self.wikidiff

        subject = self.format_subject(action.replace('_', ' '))

        NotifyEmail.notify(self, page.name, subject)
Ejemplo n.º 4
0
 def render_property_diff(self, name, old_context, old_props,
                          new_context, new_props, options):
     old, new = old_props[name], new_props[name]
     # Render as diff only if multiline (see #3002)
     if '\n' not in old and '\n' not in new:
         return None
     unidiff = '--- \n+++ \n' + \
               '\n'.join(unified_diff(old.splitlines(), new.splitlines(),
                                      options.get('contextlines', 3)))
     return tag.li('Property ', tag.strong(name),
                   Mimeview(self.env).render(old_context, 'text/x-diff',
                                             unidiff))
Ejemplo n.º 5
0
    def _format_plaintext(self, event):
        page = event.target
        data = dict(
            action=event.category,
            attachment=event.attachment,
            page=page,
            author=event.author,
            comment=event.comment,
            category=event.category,
            page_link=self.env.abs_href('wiki', page.name),
            project_name=self.env.project_name,
            project_desc=self.env.project_description,
            project_link=self.env.project_url or self.env.abs_href(),
        )
        old_page = WikiPage(self.env, page.name, page.version - 1)
        if page.version:
            data["changed"] = True
            data["diff_link"] = self.env.abs_href('wiki',
                                                  page.name,
                                                  action="diff",
                                                  version=page.version)
            if self.wiki_email_diff:
                # DEVEL: Formatter needs req object to get preferred language.
                diff_header = _("""
Index: %(name)s
==============================================================================
--- %(name)s (version: %(oldversion)s)
+++ %(name)s (version: %(version)s)
""")

                diff = "\n"
                diff += diff_header % {
                    'name': page.name,
                    'version': page.version,
                    'oldversion': page.version - 1
                }
                for line in unified_diff(old_page.text.splitlines(),
                                         page.text.splitlines(),
                                         context=3):
                    diff += "%s\n" % line
                data["diff"] = diff
        chrome = Chrome(self.env)
        dirs = []
        for provider in chrome.template_providers:
            dirs += provider.get_templates_dirs()
        templates = TemplateLoader(dirs, variable_lookup='lenient')
        template = templates.load('wiki_email_plaintext.txt',
                                  cls=NewTextTemplate)
        if template:
            stream = template.generate(**data)
            output = stream.render('text')
        return output
Ejemplo n.º 6
0
    def _format_plaintext(self, event):
        page = event.target
        data = dict(
            action=event.category,
            attachment=event.attachment,
            page=page,
            author=event.author,
            comment=event.comment,
            category=event.category,
            page_link=self.env.abs_href('wiki', page.name),
            project_name=self.env.project_name,
            project_desc=self.env.project_description,
            project_link=self.env.project_url or self.env.abs_href(),
        )
        old_page = WikiPage(self.env, page.name, page.version - 1)
        if page.version:
            data['changed'] = True
            data['diff_link'] = self.env.abs_href('wiki', page.name,
                                                  action='diff',
                                                  version=page.version)
            if self.wiki_email_diff:
                # DEVEL: Formatter needs req object to get preferred language.
                diff_header = _("""
Index: %(name)s
==============================================================================
--- %(name)s (version: %(oldversion)s)
+++ %(name)s (version: %(version)s)
""")

                diff = "\n"
                diff += diff_header % {
                    'name': page.name,
                    'version': page.version,
                    'oldversion': page.version - 1
                }
                for line in unified_diff(old_page.text.splitlines(),
                                         page.text.splitlines(), context=3):
                    diff += "%s\n" % line
                data['diff'] = diff
        chrome = Chrome(self.env)
        dirs = []
        for provider in chrome.template_providers:
            dirs += provider.get_templates_dirs()
        templates = TemplateLoader(dirs, variable_lookup='lenient')
        template = templates.load('wiki_email_plaintext.txt',
                                  cls=NewTextTemplate)
        if template:
            stream = template.generate(**data)
            return stream.render('text')
Ejemplo n.º 7
0
 def _format_plaintext(self, event):
     page = event.target
     data = dict(
         action = event.category,
         attachment = event.attachment,
         page = page,
         author = event.author,
         comment = event.comment,
         category = event.category,
         page_link = self.env.abs_href('wiki', page.name),
         project_name = self.env.project_name,
         project_desc = self.env.project_description,
         project_link = self.env.project_url or self.env.abs_href(),
     )
     old_page = WikiPage(self.env, page.name, page.version - 1)
     if page.version:
         data["changed"] = True
         data["diff_link"] = self.env.abs_href('wiki', page.name, 
                 action="diff", version=page.version)
         if self.wiki_email_diff:
             diff = "\n"
             diff += diff_header % { 'name': page.name,
                                    'version': page.version,
                                    'oldversion': page.version - 1
                                  }
             for line in unified_diff(old_page.text.splitlines(),
                                      page.text.splitlines(), context=3):
                 diff += "%s\n" % line
             data["diff"] = diff
     chrome = Chrome(self.env)        
     dirs = []
     for provider in chrome.template_providers:
         dirs += provider.get_templates_dirs()
     templates = TemplateLoader(dirs, variable_lookup='lenient')
     template = templates.load('wiki_email_plaintext.txt', 
             cls=NewTextTemplate)
     if template:
         stream = template.generate(**data)
         output = stream.render('text')
     return output
Ejemplo n.º 8
0
    def _render_diff(self, req, repos, chgset, diff_options):
        """Raw Unified Diff version"""
        req.send_response(200)
        req.send_header('Content-Type', 'text/plain;charset=utf-8')
        req.send_header('Content-Disposition',
                        'filename=Changeset%s.diff' % req.args.get('rev'))
        req.end_headers()

        for path, kind, change, base_path, base_rev in chgset.get_changes():
            if change == Changeset.ADD:
                old_node = None
            else:
                old_node = repos.get_node(base_path or path, base_rev)
            if change == Changeset.DELETE:
                new_node = None
            else:
                new_node = repos.get_node(path, chgset.rev)

            # TODO: Property changes

            # Content changes
            if kind == 'dir':
                continue

            default_charset = self.config.get('trac', 'default_charset')
            new_content = old_content = ''
            new_node_info = old_node_info = ('', '')

            if old_node:
                charset = mimeview.get_charset(old_node.content_type) or \
                          default_charset
                old_content = util.to_utf8(old_node.get_content().read(),
                                           charset)
                old_node_info = (old_node.path, old_node.rev)
            if mimeview.is_binary(old_content):
                continue

            if new_node:
                charset = mimeview.get_charset(new_node.content_type) or \
                          default_charset
                new_content = util.to_utf8(new_node.get_content().read(),
                                           charset)
                new_node_info = (new_node.path, new_node.rev)
            if mimeview.is_binary(new_content):
                continue

            if old_content != new_content:
                context = 3
                for option in diff_options[1]:
                    if option.startswith('-U'):
                        context = int(option[2:])
                        break
                req.write('Index: ' + path + util.CRLF)
                req.write('=' * 67 + util.CRLF)
                req.write('--- %s (revision %s)' % old_node_info + util.CRLF)
                req.write('+++ %s (revision %s)' % new_node_info + util.CRLF)
                for line in unified_diff(old_content.splitlines(),
                                         new_content.splitlines(),
                                         context,
                                         ignore_blank_lines='-B'
                                         in diff_options[1],
                                         ignore_case='-i' in diff_options[1],
                                         ignore_space_changes='-b'
                                         in diff_options[1]):
                    req.write(line + util.CRLF)
Ejemplo n.º 9
0
 def test_unified_diff_no_context(self):
     diff_lines = list(diff.unified_diff(['a'], ['b']))
     self.assertEqual(['@@ -1,1 +1,1 @@', '-a', '+b'], diff_lines)
Ejemplo n.º 10
0
    def _render_diff(self, req, repos, chgset, diff_options):
        """Raw Unified Diff version"""
        req.send_response(200)
        req.send_header('Content-Type', 'text/plain;charset=utf-8')
        req.send_header('Content-Disposition', 'inline;'
                        'filename=Changeset%s.diff' % chgset.rev)
        req.end_headers()

        for path, kind, change, base_path, base_rev in chgset.get_changes():
            if change == Changeset.ADD:
                old_node = None
            else:
                old_node = repos.get_node(base_path or path, base_rev)
            if change == Changeset.DELETE:
                new_node = None
            else:
                new_node = repos.get_node(path, chgset.rev)

            # TODO: Property changes

            # Content changes
            if kind == 'dir':
                continue

            default_charset = self.config.get('trac', 'default_charset')
            new_content = old_content = ''
            new_node_info = old_node_info = ('','')

            if old_node:
                charset = mimeview.get_charset(old_node.content_type) or \
                          default_charset
                old_content = util.to_utf8(old_node.get_content().read(),
                                           charset)
                old_node_info = (old_node.path, old_node.rev)
            if mimeview.is_binary(old_content):
                continue

            if new_node:
                charset = mimeview.get_charset(new_node.content_type) or \
                          default_charset
                new_content = util.to_utf8(new_node.get_content().read(),
                                           charset)
                new_node_info = (new_node.path, new_node.rev)
            if mimeview.is_binary(new_content):
                continue

            if old_content != new_content:
                context = 3
                for option in diff_options[1]:
                    if option.startswith('-U'):
                        context = int(option[2:])
                        break
                req.write('Index: ' + path + util.CRLF)
                req.write('=' * 67 + util.CRLF)
                req.write('--- %s (revision %s)' % old_node_info +
                          util.CRLF)
                req.write('+++ %s (revision %s)' % new_node_info +
                          util.CRLF)
                for line in unified_diff(old_content.splitlines(),
                                         new_content.splitlines(), context,
                                         ignore_blank_lines='-B' in diff_options[1],
                                         ignore_case='-i' in diff_options[1],
                                         ignore_space_changes='-b' in diff_options[1]):
                    req.write(line + util.CRLF)
Ejemplo n.º 11
0
 def test_unified_diff_no_context(self):
     diff_lines = list(diff.unified_diff(['a'], ['b']))
     self.assertEqual(['@@ -1,1 +1,1 @@', '-a', '+b'], diff_lines)
Ejemplo n.º 12
0
    def notify(self,
               action,
               page,
               version=None,
               time=None,
               comment=None,
               author=None,
               ipnr=None,
               redirect=False,
               old_name=None):
        self.page = page
        self.change_author = author
        self.time = time
        self.action = action
        self.version = version
        self.redirect = redirect
        self.old_name = old_name
        #        self.env.log.debug("Notify Action: %s", action)
        #        self.env.log.debug("Page time: %r, %s", time, time)

        if action == "added":
            self.newwiki = True

        self.data['name'] = page.name
        self.data['old_name'] = old_name
        self.data['redirect'] = redirect
        self.data['text'] = page.text
        self.data['version'] = version
        self.data['author'] = author
        self.data['comment'] = comment
        self.data['ip'] = ipnr
        self.data['action'] = action
        self.data['link'] = self.env.abs_href.wiki(page.name)
        self.data['linkdiff'] = self.env.abs_href.wiki(page.name,
                                                       action='diff',
                                                       version=page.version)
        if page.version > 0 and action == 'modified':
            diff = diff_header % {
                'name': self.page.name,
                'version': self.page.version,
                'oldversion': self.page.version - 1
            }
            oldpage = WikiPage(self.env, page.name, page.version - 1)
            self.data["oldversion"] = oldpage.version
            self.data["oldtext"] = oldpage.text
            for line in unified_diff(oldpage.text.splitlines(),
                                     page.text.splitlines(),
                                     context=3):
                diff += "%s\n" % line
                self.wikidiff = diff
        self.data["wikidiff"] = self.wikidiff

        self.subject = self.format_subject(action.replace('_', ' '))
        config = self.config['notification']
        if not config.getbool('smtp_enabled'):
            return
        self.replyto_email = config.get('smtp_replyto')
        self.from_email = self.from_email or self.replyto_email
        if not self.from_email and not self.replyto_email:
            message = tag(
                tag.p(_('Unable to send email due to identity crisis.')),
                # convert explicitly to `Fragment` to avoid breaking message
                # when passing `LazyProxy` object to `Fragment`
                tag.p(
                    to_fragment(
                        tag_(
                            "Neither %(from_)s nor %(reply_to)s are specified in the "
                            "configuration.",
                            from_=tag.strong('[notification] smtp_from'),
                            reply_to=tag.strong(
                                '[notification] smtp_replyto')))))
            raise TracError(message, _('SMTP Notification Error'))

        Notify.notify(self, page.name)
Ejemplo n.º 13
0
 def test_unified_diff_no_context(self):
     diff_lines = list(diff.unified_diff(["a"], ["b"]))
     self.assertEqual(["@@ -1,1 +1,1 @@", "-a", "+b"], diff_lines)
Ejemplo n.º 14
0
    def _render_diff(self, req, filename, repos, data):
        """Raw Unified Diff version"""
        req.send_response(200)
        req.send_header('Content-Type', 'text/x-patch;charset=utf-8')
        req.send_header('Content-Disposition',
                        content_disposition('inline', filename + '.diff'))
        buf = StringIO()
        mimeview = Mimeview(self.env)

        for old_node, new_node, kind, change in repos.get_changes(
            new_path=data['new_path'], new_rev=data['new_rev'],
            old_path=data['old_path'], old_rev=data['old_rev']):
            # TODO: Property changes

            # Content changes
            if kind == Node.DIRECTORY:
                continue

            new_content = old_content = ''
            new_node_info = old_node_info = ('','')
            mimeview = Mimeview(self.env)

            if old_node:
                if mimeview.is_binary(old_node.content_type, old_node.path):
                    continue
                old_content = old_node.get_content().read()
                if mimeview.is_binary(content=old_content):
                    continue
                old_node_info = (old_node.path, old_node.rev)
                old_content = mimeview.to_unicode(old_content,
                                                  old_node.content_type)
            if new_node:
                if mimeview.is_binary(new_node.content_type, new_node.path):
                    continue
                new_content = new_node.get_content().read()
                if mimeview.is_binary(content=new_content):
                    continue
                new_node_info = (new_node.path, new_node.rev)
                new_path = new_node.path
                new_content = mimeview.to_unicode(new_content,
                                                  new_node.content_type)
            else:
                old_node_path = repos.normalize_path(old_node.path)
                diff_old_path = repos.normalize_path(data['old_path'])
                new_path = posixpath.join(data['new_path'],
                                          old_node_path[len(diff_old_path)+1:])

            if old_content != new_content:
                options = data['diff']['options']
                context = options.get('contextlines', 3)
                if context < 0:
                    context = 3 # FIXME: unified_diff bugs with context=None
                ignore_blank_lines = options.get('ignoreblanklines')
                ignore_case = options.get('ignorecase')
                ignore_space = options.get('ignorewhitespace')
                if not old_node_info[0]:
                    old_node_info = new_node_info # support for 'A'dd changes
                buf.write('Index: ' + new_path + CRLF)
                buf.write('=' * 67 + CRLF)
                buf.write('--- %s\t(revision %s)' % old_node_info + CRLF)
                buf.write('+++ %s\t(revision %s)' % new_node_info + CRLF)
                for line in unified_diff(old_content.splitlines(),
                                         new_content.splitlines(), context,
                                         ignore_blank_lines=ignore_blank_lines,
                                         ignore_case=ignore_case,
                                         ignore_space_changes=ignore_space):
                    buf.write(line + CRLF)
                    
        diff_str = buf.getvalue().encode('utf-8')
        req.send_header('Content-Length', len(diff_str))
        req.end_headers()
        req.write(diff_str)
        raise RequestDone
    def notify(self, action, page,
               version=None,
               time=None,
               comment=None,
               author=None,
               ipnr=None,
               redirect=False,
               old_name=None):
        self.page = page
        self.change_author = author
        self.time = time
        self.action = action
        self.version = version
        self.redirect = redirect
        self.old_name = old_name
#        self.env.log.debug("Notify Action: %s", action)
#        self.env.log.debug("Page time: %r, %s", time, time)

        if action == "added":
            self.newwiki = True

        self.data['name'] = page.name
        self.data['old_name'] = old_name
        self.data['redirect'] = redirect
        self.data['text'] = page.text
        self.data['version'] = version
        self.data['author'] = author
        self.data['comment'] = comment
        self.data['ip'] = ipnr
        self.data['action'] = action
        self.data['link'] = self.env.abs_href.wiki(page.name)
        self.data['linkdiff'] = self.env.abs_href.wiki(page.name, action='diff',
                                                       version=page.version)
        if page.version > 0 and action == 'modified':
            diff = diff_header % {'name': self.page.name,
                                  'version': self.page.version,
                                  'oldversion': self.page.version - 1
                                  }
            oldpage = WikiPage(self.env, page.name, page.version - 1)
            self.data["oldversion"] = oldpage.version
            self.data["oldtext"] = oldpage.text
            for line in unified_diff(oldpage.text.splitlines(),
                                     page.text.splitlines(), context=3):
                diff += "%s\n" % line
                self.wikidiff = diff
        self.data["wikidiff"] = self.wikidiff

        self.subject = self.format_subject(action.replace('_', ' '))
        config = self.config['notification']
        if not config.getbool('smtp_enabled'):
            return
        self.replyto_email = config.get('smtp_replyto')
        self.from_email = self.from_email or self.replyto_email
        if not self.from_email and not self.replyto_email:
            message = tag(
                tag.p(_('Unable to send email due to identity crisis.')),
                # convert explicitly to `Fragment` to avoid breaking message
                # when passing `LazyProxy` object to `Fragment`
                tag.p(to_fragment(tag_(
                    "Neither %(from_)s nor %(reply_to)s are specified in the "
                    "configuration.",
                    from_=tag.strong('[notification] smtp_from'),
                    reply_to=tag.strong('[notification] smtp_replyto')))))
            raise TracError(message, _('SMTP Notification Error'))

        Notify.notify(self, page.name)
Ejemplo n.º 16
0
    def _get_userlog(self, req, db, user, sort):
        mimeview = Mimeview(self.env)
        repos = self.env.get_repository()
        diff_options = get_diff_options(req)
        cursor = db.cursor()
        cursor.execute("SELECT rev, time, message FROM revision "
                       "WHERE author='%s' ORDER BY time %s" % (user, sort))
                       # Have to sort by time because rev is a text field
                       # and sorts lexicographically rather than numerically
        changesets = []
        for rev, time, message in cursor:
            if self.wiki_format_messages:
                message = wiki_to_html(message, self.env, req,
                                              escape_newlines=True)
            else:
                message = html.PRE(message)
            prev = repos.get_node('/', rev).get_previous()
            if prev:
                prev_rev = prev[1]
            else:
                prev_rev = rev
            diffs = []
            changes = repos.get_changes(old_path='/', old_rev=prev_rev,
                                        new_path='/', new_rev=rev)
            for old_node, new_node, kind, change in changes:
                if kind == Node.DIRECTORY:
                    if change == Changeset.ADD:
                        diffs.append(('%s added' % new_node.path, ''))
                    elif change == Changeset.DELETE:
                        diffs.append(('%s deleted' % old_node.path, ''))
                    continue

                new_content = old_content = ''
                new_node_info = old_node_info = ('','')
                
                if old_node:
                    old_content = old_node.get_content().read()
                    if is_binary(old_content):
                        continue
                    old_node_info = (old_node.path, old_node.rev)
                    old_content = mimeview.to_unicode(old_content,
                                                      old_node.content_type)
                if new_node:
                    new_content = new_node.get_content().read()
                    if is_binary(new_content):
                        continue
                    new_node_info = (new_node.path, new_node.rev)
                    new_path = new_node.path
                    new_content = mimeview.to_unicode(new_content,
                                                      new_node.content_type)
                else:
                    old_node_path = repos.normalize_path(old_node.path)
                    diff_old_path = repos.normalize_path('/')
                    new_path = posixpath.join('/', old_node_path[len(diff_old_path)+1:])

                if old_content != new_content:
                    context = 3
                    options = diff_options[1]
                    for option in options:
                        if option.startswith('-U'):
                            context = int(option[2:])
                            break
                    if not old_node_info[0]:
                        old_node_info = new_node_info # support for 'A'dd changes
                    diff = 'Index: ' + new_path + CRLF
                    diff += '=' * 67 + CRLF
                    diff += '--- %s (revision %s)' % old_node_info + CRLF
                    diff += '+++ %s (revision %s)' % new_node_info + CRLF
                    for line in unified_diff(old_content.splitlines(),
                                             new_content.splitlines(), context,
                                             ignore_blank_lines='-B' in options,
                                             ignore_case='-i' in options,
                                             ignore_space_changes='-b' in options):
                        diff += line + CRLF
                    if change == Changeset.ADD:
                        diffs.append(('%s added' % (new_node.path,), diff))
                    elif change == Changeset.DELETE:
                        diffs.append(('%s deleted' % (old_node.path,), diff))
                    else:
                        diffs.append(('%s edited' % (new_node.path,), diff))
            changesets.append((int(rev), format_datetime(time), message, diffs))
        return changesets