~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to patch.py

  • Committer: ghigo
  • Date: 2006-03-13 20:19:41 UTC
  • mto: This revision was merged to the branch mainline in revision 330.
  • Revision ID: ghigo@venice-20060313201941-1322dc5ba24517d6
Use the TreeTransform class, on the basis of the suggest of
Aaron Bentley 

---------------------------------------

Goffredo Baroncelli wrote:
| On Monday 13 March 2006 01:36, Aaron Bentley wrote:
|
|>Hi Goffredo,
|
|
| Hi Aaron,
|
|
|>I'm still waiting for your thoughts on this.  As I said, I'm willing to
|>merge it, given that it's optional.  On the other hand, there are
|>situations where it will lead to data loss, so using TreeTransform may
|>be a better approach.
|
|
| I updated the patch in order to solve some concerns. But you are right, I
| have to use the TreeTransform class. My big problem is the lack of
| documentation on how use the class: could you answer to some my question ?

Sure.  Any failings in the documentation are my fault.

| The TreeTransform class is instantiated on the working tree: but how we
| inform the class that a file is:
| - changed ( updated )

Get the trans_id with trans_id_tree_file_id
Delete the current contents with delete_contents
Add new contents with create_file (or symlink, directory)

| - created

Call new_file

| - deleted

Get the trans_id with trans_id_tree_file_id
Delete the current contents with delete_versioned

| - renamed/moved ( is it the same ? )

Get the trans_id with trans_id_tree_file_id
Call adjust_path

| Then how we can manage the conflict ?

If you create a filesystem conflict, the transform won't apply.  If you
call resolve_conflicts, it will fix filesystem conflicts, so the
transform will apply.

Text conflicts are up to you to manage.

| Reading the code, what I understood is that:
| - for every file touched, It must assign a trans_id using the function
create_path( )

create_path is only for new files.  For existing files, you should get
them from trans_id_tree_file_id, trans_id_tree_path, or trans_id_file_id.

| - the creation of a file/directory/symlink is perfomed via the
create_{directory,symlink,file)
| function

You can, but there are also the new_file, new_directory, new_symlink
convenience methods.

| - the deletion of a file ( directory, symlink ? ) is scheduled by the
| unversion_file/delete_contents depending if a file is versioned.

For a versioned file, you'd have to do both.  Or, you can use
delete_versioned_file.

| - the renaming of a directory/file/symlink is perfomed by the
adjust_path function

Right.

| - I dont understood how we manage the content change

Content changes are content deletion and content creation.

Aaron

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
from urlparse import urlsplit, urlunsplit
21
21
from bzrlib.workingtree import WorkingTree
22
22
import bzrlib.add
 
23
import bzrlib.transform
 
24
import bzrlib.branch
 
25
import bzrlib.bzrdir
23
26
 
24
 
class BzrTagProc:
25
 
    """This class handle the additional bazaar diff tags
 
27
class BzrPatchProc:
 
28
    """This class process the bzr patch
26
29
 
27
30
        TODO:
28
31
          error handling
 
32
          execute attribute support
29
33
    """
30
 
    def __init__(self, tree):
31
 
        self.renamed = None
 
34
    def __init__(self, tt, tree, bzrdir):
32
35
        self.link = None
 
36
        self.changes = []
 
37
        self.command = None
 
38
        self.target_id = None
 
39
        self.tt = tt
33
40
        self.tree = tree
 
41
        self.skipchange = True
 
42
 
 
43
        self.bzrdir = bzrdir
 
44
        self.branch =  self.bzrdir.open_branch( )
 
45
        self.repo = self.bzrdir.find_repository( )
 
46
        h = self.branch.revision_history( )
 
47
        self.inv = self.repo.get_inventory(h[-1])
 
48
 
 
49
 
 
50
    def get_fileid_no(self, path):
 
51
        print "+++++++++++++++",path,"+++++++++++++++++"
 
52
        return self.inv.path2id(path)
 
53
 
 
54
 
 
55
    def get_transid(self, path):
 
56
        print "****************",path,"*****************"
 
57
        return self.tt.trans_id_tree_path(path)
 
58
 
34
59
 
35
60
    def _extractname(self, s):
36
61
        x = s[0]
44
69
                continue
45
70
 
46
71
            if s[i] == x:
47
 
                return s[1:i],i+1
 
72
                return s[3:i],i+1
48
73
 
49
74
            i += 1
50
75
 
51
76
        assert(False)
52
77
 
53
78
    def extractname(self, s):
54
 
        space = s.find(" ",9)    # find the 2nd space
 
79
        space = s.find(" ",13)    # find the 2nd space
55
80
        assert(space)
56
81
        return self._extractname(s[space+1:])[0]
57
82
 
58
83
    def extractnames(self, s):
59
 
        space = s.find(" ",10)    # find the 2nd space
 
84
        space = s.find(" ",14)    # find the 2nd space
60
85
        assert(space)
61
86
        s=s[space+1:]
62
87
        source, pos = self._extractname(s)
68
93
    def flush(self):
69
94
        self.process( )
70
95
 
71
 
    def add(self,name):
72
 
        action = bzrlib.add.add_action_add_and_print
73
 
        added, ignored = bzrlib.add.smart_add([name], False, action)
 
96
    def do_patch(self, changes, targetid):
 
97
        # applay change to target_id
 
98
        print "******** do patch *********"
 
99
        print changes
 
100
        print "******** do patch *********"
 
101
        self.changes = []
74
102
 
75
103
    def process(self, cmd = None):
76
 
        if self.renamed:
77
 
            os.rename(self.renamed[0], self.renamed[1])
78
 
            self.renamed = None
79
 
 
80
 
        if not cmd: return
81
 
 
82
 
        if ( cmd.startswith("removed file") or 
83
 
             cmd.startswith("removed symlink") ):
84
 
 
85
 
            target = self.extractname(cmd)
86
 
            print "removing '%s'"%target
87
 
            if not cmd.startswith("removed file"):
88
 
                os.unlink(target)
89
 
            self.tree.remove([target])
90
 
 
91
 
        elif cmd.startswith("removed directory"):
92
 
 
93
 
            target = self.extractname(cmd)
94
 
            print "removing '%s'"%target
95
 
            os.rmdir(target)
96
 
            self.tree.remove([target])
97
 
 
98
 
        elif cmd.startswith("added file"):
99
 
            target = self.extractname(cmd)
100
 
            print "adding '%s'"%target
101
 
            f = open(target,"w")
102
 
            f.close( )
103
 
            self.add(target)
104
 
 
105
 
        elif cmd.startswith("added directory"):
106
 
            target = self.extractname(cmd)
107
 
            print "adding '%s'"%target
108
 
            os.mkdir(target)
109
 
            self.add(target)
110
 
 
111
 
        elif cmd.startswith("added symlink"):
 
104
 
 
105
        while cmd and len(cmd) and cmd[-1] in "\n\r":
 
106
            cmd = cmd[:-1]
 
107
 
 
108
        if ( cmd == None or cmd.startswith("===") ) and self.changes:
 
109
            assert(self.target_id)
 
110
            self.do_patch(self.changes, self.target_id)
 
111
            self.target_id = None
 
112
            self.changes = []
 
113
 
 
114
        if cmd == None: return
 
115
        if not cmd.startswith("==="):
 
116
            if self.skipchange: return
 
117
            assert(self.target_id)
 
118
            self.changes.append(cmd)
 
119
            return
 
120
 
 
121
        # thr target_id is set during a rename; but there is possibility
 
122
        # that after a rename, is not to do a change
 
123
        self.target_id = None
 
124
        # skip change
 
125
        self.skipchange = False
 
126
 
 
127
        if ( cmd.startswith("=== removed file") or
 
128
             cmd.startswith("=== removed directory") or
 
129
             cmd.startswith("=== removed symlink") ):
 
130
 
 
131
            target = self.extractname(cmd)
 
132
            tid = self.get_transid(target)
 
133
            self.tt.delete_versioned(tid)
 
134
            print "removing '%s'"%target
 
135
            self.skipchange = True
 
136
 
 
137
        elif cmd.startswith("=== added file"):
 
138
            target = self.extractname(cmd)
 
139
            self.target_id = self.get_transid(target)
 
140
 
 
141
        elif cmd.startswith("=== modified file"):
 
142
            target = self.extractname(cmd)
 
143
            self.target_id = self.get_transid(target)
 
144
 
 
145
        elif cmd.startswith("=== added directory"):
 
146
            target = self.extractname(cmd)
 
147
            pdir = os.path.basedir(target)
 
148
            pname = os.path.basename(target)
 
149
            pdir_id = self.get_transid(pdir)
 
150
            self.tt.new_directory(pname, pdir_id)
 
151
            print "adding '%s'"%target
 
152
 
 
153
        elif cmd.startswith("=== added symlink"):
112
154
            assert(not self.link)
113
155
            self.link = self.extractname(cmd)
114
156
 
115
 
        elif cmd.startswith("target is"):
 
157
        elif cmd.startswith("=== target is"):
116
158
            assert(self.link)
117
159
            target = self.extractname(cmd)
 
160
            pdir = os.path.basedir(self.link)
 
161
            pname = os.path.basename(self.link)
 
162
            pdir_id = self.get_transid(pdir)
 
163
            self.tt.new_symlink(pname, pdir_id, target )
118
164
            print "symlinking '%s' => '%s'"%(target, self.link)
119
 
            os.symlink(target, self.link)
120
165
            self.link = None
121
 
            self.add(self.link)
122
 
 
123
 
        elif ( cmd.startswith("renamed symlink") or
124
 
               cmd.startswith("renamed file") or
125
 
               cmd.startswith("renamed directory") ):
126
 
 
127
 
            space = cmd.find(" ",10)    # find the 2nd space
 
166
 
 
167
        elif ( cmd.startswith("=== renamed symlink") or
 
168
               cmd.startswith("=== renamed file") or
 
169
               cmd.startswith("=== renamed directory") ):
 
170
 
 
171
            space = cmd.find(" ",14)    # find the 2nd space
128
172
            assert(space)
129
173
            source,dest = self.extractnames(cmd[space+1:])
 
174
            sourceid = self.get_transid(source)
 
175
            pdir = os.path.basedir(dest)
 
176
            pname = os.path.basename(dest)
 
177
            pdir_id = self.get_transid(pdir)
 
178
            self.tt.adjust_path(pname, pdir_id, sourceid)
 
179
 
130
180
            print "renaming '%s' => '%s'"%(source,dest)
131
181
 
132
 
            #os.rename(source,dest)
133
 
            self.tree.rename_one(source,dest)
134
182
 
135
183
        else:
136
184
            sys.stderr.write("Unsupported tag: '%s'\n"%cmd)
137
185
 
138
 
 
 
186
    def apply(self):
 
187
        self.tt.apply( )
 
188
 
 
189
 
 
190
 
 
191
def do_patch(p):
 
192
 
 
193
    tree = WorkingTree.open_containing(u'.')[0]
 
194
    tt = bzrlib.transform.TreeTransform(tree)
 
195
    bzrdir = bzrlib.bzrdir.BzrDir.open(".")
 
196
    bzr_tags_proc = BzrPatchProc(tt, tree, bzrdir)
 
197
 
 
198
    for l in p:
 
199
        # we have to remove the \n\r
 
200
        bzr_tags_proc.process(l)
 
201
 
 
202
    bzr_tags_proc.flush( )
 
203
    bzr_tags_proc.apply( )
139
204
 
140
205
def patch(branch, location, strip, legacy):
141
206
    """Apply a patch to a branch, using patch(1).  URLs may be used."""
160
225
        child_proc.stdin.close()
161
226
        r = child_proc.wait()
162
227
    else:
163
 
        bzr_tags_proc = BzrTagProc(WorkingTree.open_containing(u'.')[0])
164
 
        child_proc = None
165
 
        for line in my_file:
166
 
            if line.startswith("=== "):
167
 
                if child_proc:
168
 
                    child_proc.stdin.close()
169
 
                    r = child_proc.wait()
170
 
                    child_proc = None
171
 
                bzr_tags_proc.process(line[4:])
172
 
            else:
173
 
                if not child_proc:
174
 
                    child_proc = Popen(cmd, stdin=PIPE)
175
 
                #sys.stdout.write("# %s"%line)
176
 
                child_proc.stdin.write(line)
177
 
        if child_proc:
178
 
            child_proc.stdin.close()
179
 
            r = child_proc.wait()
180
 
        bzr_tags_proc.flush( )
 
228
        #bzr_tags_proc = BzrTagProc(WorkingTree.open_containing(u'.')[0])
 
229
        #child_proc = None
 
230
        #for line in my_file:
 
231
            #if line.startswith("=== "):
 
232
                #if child_proc:
 
233
                    #child_proc.stdin.close()
 
234
                    #r = child_proc.wait()
 
235
                    #child_proc = None
 
236
                #bzr_tags_proc.process(line[4:])
 
237
            #else:
 
238
                #if not child_proc:
 
239
                    #child_proc = Popen(cmd, stdin=PIPE)
 
240
                ##sys.stdout.write("# %s"%line)
 
241
                #child_proc.stdin.write(line)
 
242
        #if child_proc:
 
243
            #child_proc.stdin.close()
 
244
            #r = child_proc.wait()
 
245
        #bzr_tags_proc.flush( )
 
246
        do_patch(sys.stdin.readlines( ))
181
247
    return r
 
 
b'\\ No newline at end of file'