On Wed, Nov 30, 2005 at 11:10:57PM +0000, Daniel Carrera wrote:
> Richard A. Smith wrote:
> >darcs unpull
> >
> >You can then select the patches you want to back out and the copy of the 
> >file you desire will be the version you are interested in.
> 
> What would be really nice is to output the contents of one specific file 
> as it was before patch xyz was applied. I think that's what Rob wants, 
> and it's certainly something I would want.
> 
> Is there a way to do this?

Yes. You can do "darcs annotate file -p patch" and parse the annotate
output. If you just want the file contents, write a script that parses the
XML output and show you the "clean" file.

If you need sample code, you can find it in darcsweb's annotate parsing.


Oh, well, it's too tempting; the script is attached =P

darcs annotate --xml-output filename -p "Patch description" | ./ann2ascii

will do the trick.

I haven't tested it a lot, and could be cleaner; but I guess it's useful
as an example.

Thanks,
                Alberto

#!/usr/bin/env python

# Set this to the encoding your repos are in.

#encoding = 'latin1'
encoding = 'utf8'


#
# You shouldn't need to touch anything past here
#


import sys
import xml.sax

# I _hate_ this.
def fixu8(s):
        openpos = s.find('[_')
        if openpos < 0:
                # small optimization to avoid the conversion to utf8 and
                # entering the loop
                if type(s) == unicode:
                        # workaround for python < 2.4
                        return s.encode('utf8')
                else:
                        return s.decode(encoding).encode('utf8')

        s = s.encode(encoding).decode('raw_unicode_escape')
        while openpos >= 0:
                closepos = s.find('_]', openpos)
                if closepos < 0:
                        # not closed, probably just luck
                        break

                # middle should be something like 'c3', so we get it by
                # removing the first three characters ("[_\")
                middle = s[openpos + 3:closepos]
                if len(middle) == 2:
                        # now we turn middle into the character "\xc3"
                        char = chr(int(middle, 16))

                        # finally, replace s with our new improved string, and
                        # repeat the ugly procedure
                        char = char.decode('raw_unicode_escape')
                        mn = '[_\\' + middle + '_]'
                        s = s.replace(mn, char, 1)
                openpos = s.find('[_', openpos + 1)

        if encoding != 'utf8':
                s = s.encode('utf8')
        else:
                s = s.encode('raw_unicode_escape', 'replace')
        return s


class Annotate:
        def __init__(self):
                self.fname = ""
                self.creator_hash = ""
                self.created_as = ""
                self.lastchange_hash = ""
                self.lastchange_author = ""
                self.lastchange_name = ""
                self.lastchange_date = None
                self.firstdate = None
                self.lastdate = None
                self.lines = []
                self.patches = {}

        class Line:
                def __init__(self):
                        self.text = ""
                        self.phash = None
                        self.pauthor = None
                        self.pdate = None

        def write(self):
                for l in self.lines:
                        if not l.text:
                                sys.stdout.write('\n')
                        else:
                                sys.stdout.write(l.text)


def parse_annotate(src):
        import xml.dom.minidom

        annotate = Annotate()

        # FIXME: convert the source to UTF8; it _has_ to be a way to let
        # minidom know the source encoding
        s = ""
        for i in src:
                s += fixu8(i)

        dom = xml.dom.minidom.parseString(s)

        file = dom.getElementsByTagName("file")[0]
        annotate.fname = fixu8(file.getAttribute("name"))

        createinfo = dom.getElementsByTagName("created_as")[0]
        annotate.created_as = fixu8(createinfo.getAttribute("original_name"))

        creator = createinfo.getElementsByTagName("patch")[0]
        annotate.creator_hash = fixu8(creator.getAttribute("hash"))

        mod = dom.getElementsByTagName("modified")[0]
        lastpatch = mod.getElementsByTagName("patch")[0]
        annotate.lastchange_hash = fixu8(lastpatch.getAttribute("hash"))
        annotate.lastchange_author = fixu8(lastpatch.getAttribute("author"))

        lastname = lastpatch.getElementsByTagName("name")[0]
        lastname = lastname.childNodes[0].wholeText
        annotate.lastchange_name = fixu8(lastname)

        lastdate = lastpatch.getAttribute("date")
        annotate.lastchange_date = lastdate

        annotate.patches[annotate.lastchange_hash] = annotate.lastchange_date

        # these will be overriden by the real dates later
        annotate.firstdate = lastdate
        annotate.lastdate = 0

        file = dom.getElementsByTagName("file")[0]

        for l in file.childNodes:
                # we're only intrested in normal and added lines
                if l.nodeName not in ["normal_line", "added_line"]:
                        continue
                line = Annotate.Line()

                if l.nodeName == "normal_line":
                        patch = l.getElementsByTagName("patch")[0]
                        phash = patch.getAttribute("hash")
                        pauthor = patch.getAttribute("author")
                        pdate = patch.getAttribute("date")
                else:
                        # added lines inherit the creation from the annotate
                        # patch
                        phash = annotate.lastchange_hash
                        pauthor = annotate.lastchange_author
                        pdate = annotate.lastchange_date

                text = ""
                for node in l.childNodes:
                        if node.nodeType == node.TEXT_NODE:
                                text += node.wholeText

                # strip all "\n"s at the beginning; because the way darcs
                # formats the xml output it makes the DOM parser to add "\n"s
                # in front of it
                text = text.lstrip("\n")

                line.text = fixu8(text)
                line.phash = fixu8(phash)
                line.pauthor = fixu8(pauthor)
                line.pdate = pdate
                annotate.lines.append(line)
                annotate.patches[line.phash] = line.pdate

                if pdate > annotate.lastdate:
                        annotate.lastdate = pdate
                if pdate < annotate.firstdate:
                        annotate.firstdate = pdate

        return annotate



ann = parse_annotate(sys.stdin)
ann.write()

_______________________________________________
darcs-users mailing list
[email protected]
http://www.abridgegame.org/mailman/listinfo/darcs-users

Reply via email to