~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge.py

  • Committer: Martin Pool
  • Date: 2005-08-24 00:34:21 UTC
  • Revision ID: mbp@sourcefrog.net-20050824003421-33dd8e5c739cad2a
- send trace messages out through python logging module

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
            d_file.write(line)
49
49
        os.chmod(dest, 0777 & os.stat(source).st_mode)
50
50
 
 
51
    def dump(self, lines, dest):
 
52
        """Copy the text and mode of a file
 
53
        :param source: The path of the file to copy
 
54
        :param dest: The distination file to create
 
55
        """
 
56
        d_file = file(dest, "wb")
 
57
        for line in lines:
 
58
            d_file.write(line)
 
59
 
51
60
    def add_suffix(self, name, suffix, last_new_name=None):
52
61
        """Rename a file to append a suffix.  If the new name exists, the
53
62
        suffix is added repeatedly until a non-existant name is found
72
81
        self.conflicts += 1
73
82
        
74
83
 
75
 
    def merge_conflict(self, new_file, this_path, base_path, other_path):
 
84
    def merge_conflict(self, new_file, this_path, base_lines, other_lines):
76
85
        """
77
86
        Handle diff3 conflicts by producing a .THIS, .BASE and .OTHER.  The
78
87
        main file will be a version with diff3 conflicts.
82
91
        :param other_path: Path to the file text for the OTHER tree
83
92
        """
84
93
        self.add_suffix(this_path, ".THIS")
85
 
        self.copy(base_path, this_path+".BASE")
86
 
        self.copy(other_path, this_path+".OTHER")
 
94
        self.dump(base_lines, this_path+".BASE")
 
95
        self.dump(other_lines, this_path+".OTHER")
87
96
        os.rename(new_file, this_path)
88
97
        self.conflict("Diff3 conflict encountered in %s" % this_path)
89
98
 
108
117
        if not self.ignore_zero:
109
118
            print "%d conflicts encountered.\n" % self.conflicts
110
119
            
111
 
class SourceFile(object):
112
 
    def __init__(self, path, id, present=None, isdir=None):
113
 
        self.path = path
114
 
        self.id = id
115
 
        self.present = present
116
 
        self.isdir = isdir
117
 
        self.interesting = True
118
 
 
119
 
    def __repr__(self):
120
 
        return "SourceFile(%s, %s)" % (self.path, self.id)
121
 
 
122
120
def get_tree(treespec, temp_root, label):
123
121
    location, revno = treespec
124
122
    branch = find_branch(location)
133
131
    return branch, MergeTree(base_tree, temp_path)
134
132
 
135
133
 
136
 
def abspath(tree, file_id):
137
 
    path = tree.inventory.id2path(file_id)
138
 
    if path == "":
139
 
        return "./."
140
 
    return "./" + path
141
 
 
142
134
def file_exists(tree, file_id):
143
135
    return tree.has_filename(tree.id2path(file_id))
144
136
    
145
 
def inventory_map(tree):
146
 
    inventory = {}
147
 
    for file_id in tree.inventory:
148
 
        path = abspath(tree, file_id)
149
 
        inventory[path] = SourceFile(path, file_id)
150
 
    return inventory
151
 
 
152
137
 
153
138
class MergeTree(object):
154
139
    def __init__(self, tree, tempdir):
157
142
            self.root = tree.basedir
158
143
        else:
159
144
            self.root = None
160
 
        self.inventory = inventory_map(tree)
161
145
        self.tree = tree
162
146
        self.tempdir = tempdir
163
147
        os.mkdir(os.path.join(self.tempdir, "texts"))
164
148
        self.cached = {}
165
149
 
 
150
    def __iter__(self):
 
151
        return self.tree.__iter__()
 
152
 
166
153
    def __contains__(self, file_id):
167
 
        return id in self.tree
 
154
        return file_id in self.tree
 
155
 
 
156
    def get_file(self, file_id):
 
157
        return self.tree.get_file(file_id)
168
158
 
169
159
    def get_file_sha1(self, id):
170
160
        return self.tree.get_file_sha1(id)
171
161
 
 
162
    def id2path(self, file_id):
 
163
        return self.tree.id2path(file_id)
 
164
 
 
165
    def has_id(self, file_id):
 
166
        return self.tree.has_id(file_id)
 
167
 
 
168
    def has_or_had_id(self, file_id):
 
169
        if file_id == self.tree.inventory.root.file_id:
 
170
            return True
 
171
        return self.tree.inventory.has_id(file_id)
 
172
 
172
173
    def readonly_path(self, id):
173
174
        if id not in self.tree:
174
175
            return None
256
257
             source_file.interesting = source_file.id in interesting_ids
257
258
 
258
259
 
259
 
def generate_cset_optimized(tree_a, tree_b, inventory_a, inventory_b,
260
 
                            interesting_ids=None):
 
260
def generate_cset_optimized(tree_a, tree_b, interesting_ids=None):
261
261
    """Generate a changeset.  If interesting_ids is supplied, only changes
262
262
    to those files will be shown.  Metadata changes are stripped.
263
263
    """ 
264
 
    if interesting_ids is not None:
265
 
        set_interesting(inventory_a, inventory_b, interesting_ids)
266
 
    cset =  generate_changeset(tree_a, tree_b, inventory_a, inventory_b)
 
264
    cset =  generate_changeset(tree_a, tree_b, interesting_ids)
267
265
    for entry in cset.entries.itervalues():
268
266
        entry.metadata_change = None
269
267
    return cset
273
271
                ignore_zero=False, merge_type=ApplyMerge3, backup_files=False,
274
272
                interesting_ids=None):
275
273
 
276
 
    def merge_factory(base_file, other_file):
277
 
        contents_change = merge_type(base_file, other_file)
 
274
    def merge_factory(file_id, base, other):
 
275
        contents_change = merge_type(file_id, base, other)
278
276
        if backup_files:
279
277
            contents_change = BackupBeforeChange(contents_change)
280
278
        return contents_change
281
 
    
282
 
    def generate_cset(tree_a, tree_b, inventory_a, inventory_b):
283
 
        return generate_cset_optimized(tree_a, tree_b, inventory_a, inventory_b,
284
 
                                       interesting_ids)
285
279
 
286
280
    this_tree = get_tree((this_branch.base, None), tempdir, "this")[1]
287
281
 
288
282
    def get_inventory(tree):
289
 
        return tree.inventory
 
283
        return tree.tree.inventory
290
284
 
291
285
    inv_changes = merge_flex(this_tree, base_tree, other_tree,
292
 
                             generate_cset, get_inventory,
 
286
                             generate_cset_optimized, get_inventory,
293
287
                             MergeConflictHandler(base_tree.root,
294
288
                                                  ignore_zero=ignore_zero),
295
 
                             merge_factory=merge_factory)
 
289
                             merge_factory=merge_factory, 
 
290
                             interesting_ids=interesting_ids)
296
291
 
297
292
    adjust_ids = []
298
293
    for id, path in inv_changes.iteritems():
300
295
            if path == '.':
301
296
                path = ''
302
297
            else:
303
 
                assert path.startswith('./')
 
298
                assert path.startswith('./'), "path is %s" % path
304
299
            path = path[2:]
305
300
        adjust_ids.append((path, id))
306
301
    if len(adjust_ids) > 0:
312
307
    old_entries = this_branch.read_working_inventory()
313
308
    new_inventory = {}
314
309
    by_path = {}
 
310
    new_entries_map = {} 
 
311
    for path, file_id in new_entries:
 
312
        if path is None:
 
313
            continue
 
314
        new_entries_map[file_id] = path
 
315
 
 
316
    def id2path(file_id):
 
317
        path = new_entries_map.get(file_id)
 
318
        if path is not None:
 
319
            return path
 
320
        entry = old_entries[file_id]
 
321
        if entry.parent_id is None:
 
322
            return entry.name
 
323
        return os.path.join(id2path(entry.parent_id), entry.name)
 
324
        
315
325
    for file_id in old_entries:
316
326
        entry = old_entries[file_id]
317
 
        path = old_entries.id2path(file_id)
 
327
        path = id2path(file_id)
318
328
        new_inventory[file_id] = (path, file_id, entry.parent_id, entry.kind)
319
329
        by_path[path] = file_id
320
330