[PATCH] Add support for bzr diff to the "patch" bzrtool command

Goffredo Baroncelli kreijack at alice.it
Fri Mar 3 21:33:42 GMT 2006


Hi all,

the bazaar diff output incorporates additional tags to highlight that some
action ( as symlinking and/or renaming ) are happened in the past. 
So I patched the 'patch' command of the bzrtool plugin in order to support for 
the following additional tag

=== removed file
=== removed directory
=== removed symlink
=== added file
=== added directory
=== added symlink
=== target is			[ after === added symlink ]
=== renamed file
=== renamed directory
=== renamed symlink

example

$ bzr diff -r1..2
=== added symlink 'linkb'
=== target is 'b'
=== renamed file 'a' => 'b'
--- a
+++ b
@@ -1,1 +1,1 @@
-first line
+2nd line

$ bzr revert -r1
$ ls -l
-rw-r--r-- 1 ghigo ghigo 9 2006-03-03 22:14 a

$ bzr diff -r1..2 | patch
patching file a
$ ls -l
total 4
-rw-r--r-- 1 ghigo ghigo 9 2006-03-03 22:14 a

$ bzr revert -r1
$ bzr diff -r1..2 | bzr patch --bzrdiff
patching file b
symlinking 'b' => 'linkb'
renaming 'a' => 'b'
$ ls -l
total 4
-rw-r--r-- 1 ghigo ghigo 9 2006-03-03 22:14 b
lrwxrwxrwx 1 ghigo ghigo 1 2006-03-03 22:14 linkb -> b


You can see the patch at
http://goffredo-baroncelli.homelinux.net/bazaar-dev/diffbzrtools?cmd=diff;otherrevid=abentley@panoramicfeedback.com-20060302141119-7a5ee02eb6483c50;rev=;pathrevid=;path=

You can browse the source and the history at
http://goffredo-baroncelli.homelinux.net/bazaar-dev/diffbzrtools

You can pull the source with
bzr pull http://goffredo-baroncelli.homelinux.net/bazaar-dev/diffbzrtools

You can download the source from
http://goffredo-baroncelli.homelinux.net/bazaar-dev/diffbzrtools?cmd=export;rev=;path=;mode=tgz

Below the patch
------


=== modified file '__init__.py'
--- __init__.py	
+++ __init__.py	
@@ -98,16 +98,22 @@
 strip_help="""Strip the smallest prefix containing num leading slashes  from \
 each file name found in the patch file."""
 Option.OPTIONS['strip'] = Option('strip', type=int, help=strip_help)
+Option.OPTIONS['bzrdiff'] = Option('bzrdiff',type=None,
+                                help="""Handle extra bzr tags""")
 class cmd_patch(bzrlib.commands.Command):
     """Apply a named patch to the current tree.
     """
     takes_args = ['filename?']
-    takes_options = ['strip']
-    def run(self, filename=None, strip=1):
+    takes_options = ['strip','bzrdiff']
+    def run(self, filename=None, strip=-1, bzrdiff=0):
         from patch import patch
         from bzrlib.branch import Branch
         b = Branch.open_containing('.')[0]
-        return patch(b, filename, strip)
+        if strip == -1:
+            if bzrdiff: strip = 0
+            else:       strip = 1
+
+        return patch(b, filename, strip, legacy= not bzrdiff)
 
 
 class cmd_shelve(bzrlib.commands.Command):

=== modified file 'patch.py'
--- patch.py	
+++ patch.py	
@@ -14,11 +14,116 @@
 #    You should have received a copy of the GNU General Public License
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-import sys
+import sys, os
 from subprocess import Popen, PIPE
 from bzrlib.transport import get_transport
 from urlparse import urlsplit, urlunsplit
-def patch(branch, location, strip):
+
+class BzrTagProc:
+    """This class handle the additional bazaar diff tags
+
+        TODO:
+          error handling
+    """
+    def __init__(self):
+        self.renamed = None
+        self.link = None
+
+    def _extractname(self, s):
+        x = s[0]
+        i = 1
+        ls = len(s)
+
+        while i < ls:
+            if s[i] == '\\':
+                assert(i+1 < ls )
+                i += 2
+                continue
+
+            if s[i] == x:
+                return s[1:i],i+1
+
+            i += 1
+
+        assert(False)
+
+    def extractname(self, s):
+        space = s.find(" ",9)    # find the 2nd space
+        assert(space)
+        return self._extractname(s[space+1:])[0]
+
+    def extractnames(self, s):
+        space = s.find(" ",10)    # find the 2nd space
+        assert(space)
+        s=s[space+1:]
+        source, pos = self._extractname(s)
+        assert( pos +4 < len(s) )
+        dest,  dummy = self._extractname(s[pos+4:])
+
+        return source,dest
+
+    def flush(self):
+        self.process( )
+
+    def process(self, cmd = None):
+        if self.renamed:
+            os.rename(self.renamed[0], self.renamed[1])
+            self.renamed = None
+
+        if not cmd: return
+
+        if ( cmd.startswith("removed file") or 
+             cmd.startswith("removed symlink") ):
+
+            target = self.extractname(cmd)
+            print "removing '%s'"%target
+            os.unlink(target)
+
+        elif cmd.startswith("removed directory"):
+
+            target = self.extractname(cmd)
+            print "removing '%s'"%target
+            os.rmdir(target)
+
+        elif cmd.startswith("added file"):
+            target = self.extractname(cmd)
+            print "adding '%s'"%target
+            f = open(target,"w")
+            f.close( )
+
+        elif cmd.startswith("added directory"):
+            target = self.extractname(cmd)
+            print "adding '%s'"%target
+            os.mkdir(target)
+
+        elif cmd.startswith("added symlink"):
+            assert(not self.link)
+            self.link = self.extractname(cmd)
+
+        elif cmd.startswith("target is"):
+            assert(self.link)
+            source = self.extractname(cmd)
+            print "symlinking '%s' => '%s'"%(source, self.link)
+            os.symlink(source, self.link)
+            self.link = None
+
+        elif ( cmd.startswith("renamed symlink") or
+               cmd.startswith("renamed file") or
+               cmd.startswith("renamed directory") ):
+
+            space = cmd.find(" ",10)    # find the 2nd space
+            assert(space)
+            source,dest = self.extractnames(cmd[space+1:])
+            print "renaming '%s' => '%s'"%(source,dest)
+
+            os.rename(source,dest)
+
+        else:
+            sys.stderr.write("Unsupported tag: '%s'\n"%cmd)
+
+
+
+def patch(branch, location, strip, legacy):
     """Apply a patch to a branch, using patch(1).  URLs may be used."""
     my_file = None
     if location is None:
@@ -33,8 +138,30 @@
         if my_file is None:
             my_file = file(location, 'rb')
     cmd = ['patch', '--directory', branch.base, '--strip', str(strip)]
-    child_proc = Popen(cmd, stdin=PIPE)
-    for line in my_file:
-        child_proc.stdin.write(line)
-    child_proc.stdin.close()
-    return child_proc.wait()
+    r = 0
+    if legacy:
+        child_proc = Popen(cmd, stdin=PIPE)
+        for line in my_file:
+            child_proc.stdin.write(line)
+        child_proc.stdin.close()
+        r = child_proc.wait()
+    else:
+        bzr_tags_proc = BzrTagProc( )
+        child_proc = None
+        for line in my_file:
+            if line.startswith("=== "):
+                if child_proc:
+                    child_proc.stdin.close()
+                    r = child_proc.wait()
+                    child_proc = None
+                bzr_tags_proc.process(line[4:])
+            else:
+                if not child_proc:
+                    child_proc = Popen(cmd, stdin=PIPE)
+                #sys.stdout.write("# %s"%line)
+                child_proc.stdin.write(line)
+        if child_proc:
+            child_proc.stdin.close()
+            r = child_proc.wait()
+        bzr_tags_proc.flush( )
+    return r
\ No newline at end of file


Goffredo

-- 
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack_AT_inwind.it>
Key fingerprint = CE3C 7E01 6782 30A3 5B87  87C0 BB86 505C 6B2A CFF9
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 191 bytes
Desc: not available
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20060303/30564a96/attachment.pgp 


More information about the bazaar mailing list