[Pkg-bazaar-commits] ./bzr/unstable r850: - Merge merge updates from aaron
Martin Pool
mbp at sourcefrog.net
Fri Apr 10 08:21:14 UTC 2009
------------------------------------------------------------
revno: 850
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Thu 2005-07-07 18:02:16 +1000
message:
- Merge merge updates from aaron
aaron.bentley at utoronto.ca-20050706170931-9d2551019af3578d
modified:
TODO
bzrlib/changeset.py
bzrlib/merge.py
bzrlib/merge_core.py
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO 2005-07-04 12:22:34 +0000
+++ b/TODO 2005-07-07 08:02:16 +0000
@@ -17,6 +17,10 @@
Small things
------------
+* Merge should ignore the destination's working directory, otherwise
+ we get an error about the statcache when pulling from a remote
+ branch.
+
* Add of a file that was present in the base revision should put back
the previous file-id.
=== modified file 'bzrlib/changeset.py'
--- a/bzrlib/changeset.py 2005-06-06 04:17:53 +0000
+++ b/bzrlib/changeset.py 2005-07-07 08:02:16 +0000
@@ -24,7 +24,10 @@
NULL_ID = "!NULL"
-
+class OldFailedTreeOp(Exception):
+ def __init__(self):
+ Exception.__init__(self, "bzr-tree-change contains files from a"
+ " previous failed merge operation.")
def invert_dict(dict):
newdict = {}
for (key,value) in dict.iteritems():
@@ -826,10 +829,10 @@
my_sort(target_entries, shortest_to_longest)
return (source_entries, target_entries)
-def rename_to_temp_delete(source_entries, inventory, dir, conflict_handler,
- reverse):
+def rename_to_temp_delete(source_entries, inventory, dir, temp_dir,
+ conflict_handler, reverse):
"""Delete and rename entries as appropriate. Entries are renamed to temp
- names. A map of id -> temp name is returned.
+ names. A map of id -> temp name (or None, for deletions) is returned.
:param source_entries: The entries to rename and delete
:type source_entries: List of `ChangesetEntry`
@@ -842,16 +845,16 @@
:return: a mapping of id to temporary name
:rtype: Dictionary
"""
- temp_dir = os.path.join(dir, "temp")
temp_name = {}
for i in range(len(source_entries)):
entry = source_entries[i]
if entry.is_deletion(reverse):
path = os.path.join(dir, inventory[entry.id])
entry.apply(path, conflict_handler, reverse)
+ temp_name[entry.id] = None
else:
- to_name = temp_dir+"/"+str(i)
+ to_name = os.path.join(temp_dir, str(i))
src_path = inventory.get(entry.id)
if src_path is not None:
src_path = os.path.join(dir, src_path)
@@ -867,12 +870,12 @@
return temp_name
-def rename_to_new_create(temp_name, target_entries, inventory, changeset, dir,
- conflict_handler, reverse):
+def rename_to_new_create(changed_inventory, target_entries, inventory,
+ changeset, dir, conflict_handler, reverse):
"""Rename entries with temp names to their final names, create new files.
- :param temp_name: A mapping of id to temporary name
- :type temp_name: Dictionary
+ :param changed_inventory: A mapping of id to temporary name
+ :type changed_inventory: Dictionary
:param target_entries: The entries to apply changes to
:type target_entries: List of `ChangesetEntry`
:param changeset: The changeset to apply
@@ -883,22 +886,24 @@
:type reverse: bool
"""
for entry in target_entries:
- new_path = entry.get_new_path(inventory, changeset, reverse)
- if new_path is None:
+ new_tree_path = entry.get_new_path(inventory, changeset, reverse)
+ if new_tree_path is None:
continue
- new_path = os.path.join(dir, new_path)
- old_path = temp_name.get(entry.id)
+ new_path = os.path.join(dir, new_tree_path)
+ old_path = changed_inventory.get(entry.id)
if os.path.exists(new_path):
if conflict_handler.target_exists(entry, new_path, old_path) == \
"skip":
continue
if entry.is_creation(reverse):
entry.apply(new_path, conflict_handler, reverse)
+ changed_inventory[entry.id] = new_tree_path
else:
if old_path is None:
continue
try:
os.rename(old_path, new_path)
+ changed_inventory[entry.id] = new_tree_path
except OSError, e:
raise Exception ("%s is missing" % new_path)
@@ -1006,6 +1011,19 @@
Exception.__init__(self, msg)
self.filename = filename
+class NewContentsConflict(Exception):
+ def __init__(self, filename):
+ msg = "Conflicting contents for new file %s" % (filename)
+ Exception.__init__(self, msg)
+
+
+class MissingForMerge(Exception):
+ def __init__(self, filename):
+ msg = "The file %s was modified, but does not exist in this tree"\
+ % (filename)
+ Exception.__init__(self, msg)
+
+
class ExceptionConflictHandler(object):
def __init__(self, dir):
self.dir = dir
@@ -1066,6 +1084,12 @@
def missing_for_rename(self, filename):
raise MissingForRename(filename)
+ def missing_for_merge(self, file_id, inventory):
+ raise MissingForMerge(inventory.other.get_path(file_id))
+
+ def new_contents_conflict(self, filename, other_contents):
+ raise NewContentsConflict(filename)
+
def finalize():
pass
@@ -1086,8 +1110,19 @@
"""
if conflict_handler is None:
conflict_handler = ExceptionConflictHandler(dir)
- temp_dir = dir+"/temp"
- os.mkdir(temp_dir)
+ temp_dir = os.path.join(dir, "bzr-tree-change")
+ try:
+ os.mkdir(temp_dir)
+ except OSError, e:
+ if e.errno == errno.EEXIST:
+ try:
+ os.rmdir(temp_dir)
+ except OSError, e:
+ if e.errno == errno.ENOTEMPTY:
+ raise OldFailedTreeOp()
+ os.mkdir(temp_dir)
+ else:
+ raise
#apply changes that don't affect filenames
for entry in changeset.entries.itervalues():
@@ -1102,21 +1137,14 @@
(source_entries, target_entries) = get_rename_entries(changeset, inventory,
reverse)
- temp_name = rename_to_temp_delete(source_entries, inventory, dir,
- conflict_handler, reverse)
+ changed_inventory = rename_to_temp_delete(source_entries, inventory, dir,
+ temp_dir, conflict_handler,
+ reverse)
- rename_to_new_create(temp_name, target_entries, inventory, changeset, dir,
- conflict_handler, reverse)
+ rename_to_new_create(changed_inventory, target_entries, inventory,
+ changeset, dir, conflict_handler, reverse)
os.rmdir(temp_dir)
- r_inventory = invert_dict(inventory)
- new_entries, removed_entries = get_inventory_change(inventory,
- r_inventory, changeset, reverse)
- new_inventory = {}
- for path, file_id in new_entries.iteritems():
- new_inventory[file_id] = path
- for file_id in removed_entries:
- new_inventory[file_id] = None
- return new_inventory
+ return changed_inventory
def apply_changeset_tree(cset, tree, reverse=False):
@@ -1133,17 +1161,13 @@
def get_inventory_change(inventory, new_inventory, cset, reverse=False):
new_entries = {}
remove_entries = []
- r_inventory = invert_dict(inventory)
- r_new_inventory = invert_dict(new_inventory)
for entry in cset.entries.itervalues():
if entry.needs_rename():
- old_path = r_inventory.get(entry.id)
- if old_path is not None:
- remove_entries.append(old_path)
+ new_path = entry.get_new_path(inventory, cset)
+ if new_path is None:
+ remove_entries.append(entry.id)
else:
- new_path = entry.get_new_path(inventory, cset)
- if new_path is not None:
- new_entries[new_path] = entry.id
+ new_entries[new_path] = entry.id
return new_entries, remove_entries
@@ -1517,15 +1541,23 @@
return self.inventory.get(id)
def get_name(self, id):
- return os.path.basename(self.get_path(id))
+ path = self.get_path(id)
+ if path is None:
+ return None
+ else:
+ return os.path.basename(path)
def get_dir(self, id):
path = self.get_path(id)
if path == "":
return None
+ if path is None:
+ return None
return os.path.dirname(path)
def get_parent(self, id):
+ if self.get_path(id) is None:
+ return None
directory = self.get_dir(id)
if directory == '.':
directory = './.'
=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py 2005-06-06 11:53:29 +0000
+++ b/bzrlib/merge.py 2005-07-07 08:02:16 +0000
@@ -80,6 +80,12 @@
moved_path = self.add_suffix(target, ".moved")
self.conflict("Moved existing %s to %s" % (target, moved_path))
+ def rmdir_non_empty(self, filename):
+ """Handle the case where the dir to be removed still has contents"""
+ self.conflict("Directory %s not removed because it is not empty"\
+ % filename)
+ return "skip"
+
def finalize(self):
if not self.ignore_zero:
print "%d conflicts encountered.\n" % self.conflicts
@@ -121,8 +127,6 @@
def inventory_map(tree):
inventory = {}
for file_id in tree.inventory:
- if not file_exists(tree, file_id):
- continue
path = abspath(tree, file_id)
inventory[path] = SourceFile(path, file_id)
return inventory
@@ -142,6 +146,8 @@
self.cached = {}
def readonly_path(self, id):
+ if id not in self.tree:
+ return None
if self.root is not None:
return self.tree.abspath(self.tree.id2path(id))
else:
=== modified file 'bzrlib/merge_core.py'
--- a/bzrlib/merge_core.py 2005-06-06 04:17:53 +0000
+++ b/bzrlib/merge_core.py 2005-07-07 08:02:16 +0000
@@ -48,55 +48,22 @@
for entry in cset.entries.itervalues():
if entry.is_boring():
new_cset.add_entry(entry)
- elif entry.is_creation(False):
- if inventory.this.get_path(entry.id) is None:
- new_cset.add_entry(entry)
- else:
- this_contents = get_this_contents(entry.id)
- other_contents = entry.contents_change.new_contents
- if other_contents == this_contents:
- boring_entry = changeset.ChangesetEntry(entry.id,
- entry.new_parent,
- entry.new_path)
- new_cset.add_entry(boring_entry)
- else:
- conflict_handler.contents_conflict(this_contents,
- other_contents)
-
- elif entry.is_deletion(False):
- if inventory.this.get_path(entry.id) is None:
- boring_entry = changeset.ChangesetEntry(entry.id, entry.parent,
- entry.path)
- new_cset.add_entry(boring_entry)
- elif entry.contents_change is not None:
- this_contents = get_this_contents(entry.id)
- base_contents = entry.contents_change.old_contents
- if base_contents == this_contents:
- new_cset.add_entry(entry)
- else:
- entry_path = inventory.this.get_path(entry.id)
- conflict_handler.rem_contents_conflict(entry_path,
- this_contents,
- base_contents)
-
- else:
- new_cset.add_entry(entry)
else:
- entry = get_merge_entry(entry, inventory, base, other,
- conflict_handler)
- if entry is not None:
- new_cset.add_entry(entry)
+ new_entry = make_merged_entry(entry, inventory, conflict_handler)
+ new_contents = make_merged_contents(entry, this, base, other,
+ conflict_handler)
+ new_entry.contents_change = new_contents
+ new_entry.metadata_change = make_merged_metadata(entry, base, other)
+ new_cset.add_entry(new_entry)
+
return new_cset
-
-def get_merge_entry(entry, inventory, base, other, conflict_handler):
+def make_merged_entry(entry, inventory, conflict_handler):
this_name = inventory.this.get_name(entry.id)
this_parent = inventory.this.get_parent(entry.id)
this_dir = inventory.this.get_dir(entry.id)
if this_dir is None:
this_dir = ""
- if this_name is None:
- return conflict_handler.merge_missing(entry.id, inventory)
base_name = inventory.base.get_name(entry.id)
base_parent = inventory.base.get_parent(entry.id)
@@ -133,17 +100,65 @@
old_dir = this_dir
new_parent = other_parent
new_dir = other_dir
- old_path = os.path.join(old_dir, old_name)
+ if old_name is not None and old_parent is not None:
+ old_path = os.path.join(old_dir, old_name)
+ else:
+ old_path = None
new_entry = changeset.ChangesetEntry(entry.id, old_parent, old_name)
- if new_name is not None or new_parent is not None:
+ if new_name is not None and new_parent is not None:
new_entry.new_path = os.path.join(new_dir, new_name)
else:
new_entry.new_path = None
new_entry.new_parent = new_parent
-
- base_path = base.readonly_path(entry.id)
- other_path = other.readonly_path(entry.id)
+ return new_entry
+
+
+def make_merged_contents(entry, this, base, other, conflict_handler):
+ contents = entry.contents_change
+ if contents is None:
+ return None
+ this_path = this.readonly_path(entry.id)
+ def make_diff3():
+ if this_path is None:
+ return conflict_handler.missing_for_merge(entry.id, inventory)
+ base_path = base.readonly_path(entry.id)
+ other_path = other.readonly_path(entry.id)
+ return changeset.Diff3Merge(base_path, other_path)
+
+ if isinstance(contents, changeset.PatchApply):
+ return make_diff3()
+ if isinstance(contents, changeset.ReplaceContents):
+ if contents.old_contents is None and contents.new_contents is None:
+ return None
+ if contents.new_contents is None:
+ if this_path is not None and os.path.exists(this_path):
+ return contents
+ else:
+ return None
+ elif contents.old_contents is None:
+ if this_path is None or not os.path.exists(this_path):
+ return contents
+ else:
+ this_contents = file(this_path, "rb").read()
+ if this_contents == contents.new_contents:
+ return None
+ else:
+ other_path = other.readonly_path(entry.id)
+ conflict_handler.new_contents_conflict(this_path,
+ other_path)
+ elif isinstance(contents.old_contents, changeset.FileCreate) and \
+ isinstance(contents.new_contents, changeset.FileCreate):
+ return make_diff3()
+ else:
+ raise Exception("Unhandled merge scenario")
+
+def make_merged_metadata(entry, base, other):
+ if entry.metadata_change is not None:
+ base_path = base.readonly_path(entry.id)
+ other_path = other.readonly_path(entry.id)
+ return PermissionsMerge(base_path, other_path)
+def get_merge_entry(entry, inventory, base, other, conflict_handler):
if entry.contents_change is not None:
new_entry.contents_change = changeset.Diff3Merge(base_path, other_path)
if entry.metadata_change is not None:
@@ -210,6 +225,9 @@
def full_path(self, id):
return self.abs_path(self.inventory[id])
+ def readonly_path(self, id):
+ return self.full_path(id)
+
def change_path(self, id, path):
new = os.path.join(self.dir, self.inventory[id])
os.rename(self.abs_path(self.inventory[id]), self.abs_path(path))
@@ -329,14 +347,60 @@
Inventory(self.base.inventory),
Inventory(self.other.inventory))
conflict_handler = changeset.ExceptionConflictHandler(self.this.dir)
- return make_merge_changeset(self.cset, all_inventory, self.this.dir,
- self.base.dir, self.other.dir,
- conflict_handler)
+ return make_merge_changeset(self.cset, all_inventory, self.this,
+ self.base, self.other, conflict_handler)
+
+ def apply_inv_change(self, inventory_change, orig_inventory):
+ orig_inventory_by_path = {}
+ for file_id, path in orig_inventory.iteritems():
+ orig_inventory_by_path[path] = file_id
+
+ def parent_id(file_id):
+ try:
+ parent_dir = os.path.dirname(orig_inventory[file_id])
+ except:
+ print file_id
+ raise
+ if parent_dir == "":
+ return None
+ return orig_inventory_by_path[parent_dir]
+
+ def new_path(file_id):
+ if inventory_change.has_key(file_id):
+ return inventory_change[file_id]
+ else:
+ parent = parent_id(file_id)
+ if parent is None:
+ return orig_inventory[file_id]
+ dirname = new_path(parent)
+ return os.path.join(dirname, orig_inventory[file_id])
+
+ new_inventory = {}
+ for file_id in orig_inventory.iterkeys():
+ path = new_path(file_id)
+ if path is None:
+ continue
+ new_inventory[file_id] = path
+
+ for file_id, path in inventory_change.iteritems():
+ if orig_inventory.has_key(file_id):
+ continue
+ new_inventory[file_id] = path
+ return new_inventory
+
+
+
def apply_changeset(self, cset, conflict_handler=None, reverse=False):
- self.this.inventory = \
- changeset.apply_changeset(cset, self.this.inventory,
- self.this.dir, conflict_handler,
- reverse)
+ inventory_change = changeset.apply_changeset(cset,
+ self.this.inventory,
+ self.this.dir,
+ conflict_handler, reverse)
+ self.this.inventory = self.apply_inv_change(inventory_change,
+ self.this.inventory)
+
+
+
+
def cleanup(self):
shutil.rmtree(self.dir)
More information about the Pkg-bazaar-commits
mailing list