def conflict_file(left_dir, left_distro, right_dir, right_distro, dest_dir, filename): """Copy both files as conflicts of each other.""" left_src = "%s/%s" % (left_dir, filename) right_src = "%s/%s" % (right_dir, filename) dest = "%s/%s" % (dest_dir, filename) logger.debug("Conflicted: %s", filename) tree.remove(dest) # We need to take care here .. if one of the items involved in a # conflict is a directory then it might have children and we don't want # to throw an error later. # # We get round this by making the directory a symlink to the conflicted # one. # # Fortunately this is so rare it may never happen! if tree.exists(left_src): tree.copyfile(left_src, "%s.%s" % (dest, left_distro.upper())) if os.path.isdir(left_src): os.symlink("%s.%s" % (os.path.basename(dest), left_distro.upper()), dest) if tree.exists(right_src): tree.copyfile(right_src, "%s.%s" % (dest, right_distro.upper())) if os.path.isdir(right_src): os.symlink("%s.%s" % (os.path.basename(dest), right_distro.upper()), dest)
def handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files): """Handle the common case of a file in both left and right.""" if filename == "debian/changelog": # two-way merge of changelogs try: merge_changelog(left_dir, right_dir, merged_dir, filename) except: return True elif filename.endswith(".po") and not \ same_file(left_stat, left_dir, right_stat, right_dir, filename): # two-way merge of po contents (do later) po_files.append(filename) return False elif filename.endswith(".pot") and not \ same_file(left_stat, left_dir, right_stat, right_dir, filename): # two-way merge of pot contents if merge_pot(left_dir, right_dir, merged_dir, filename): conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True elif base_stat is not None and S_ISREG(base_stat.st_mode): # was file in base: diff3 possible if merge_file(left_dir, left_name, left_distro, base_dir, right_dir, right_name, right_distro, merged_dir, filename): return True elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # same file in left and right logger.debug("%s and %s both turned into same file: %s", left_distro, right_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: # general file conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True # Apply permissions merge_attr(base_dir, left_dir, right_dir, merged_dir, filename) return False
def publish_patch(distro, pv, filename, list_file): """Publish the latest version of the patch for all to see.""" publish_filename = published_file(distro, pv) tree.ensure(publish_filename) if os.path.isfile(publish_filename): os.unlink(publish_filename) os.link(filename, publish_filename) logger.info("Published %s", tree.subdir(config.get('ROOT'), publish_filename)) print >> list_file, "%s %s" % ( pv.package, tree.subdir("%s/published" % config.get('ROOT'), publish_filename)) # Remove older patches for junk in os.listdir(os.path.dirname(publish_filename)): junkpath = "%s/%s" % (os.path.dirname(publish_filename), junk) if os.path.isfile(junkpath) \ and junk != os.path.basename(publish_filename): os.unlink(junkpath) # Publish extracted patches output = "%s/extracted" % os.path.dirname(publish_filename) if os.path.isdir(output): tree.remove(output) dpatch_dir = dpatch_directory(distro, pv) if os.path.isdir(dpatch_dir): for dpatch in tree.walk(dpatch_dir): if not len(dpatch): continue src_filename = "%s/%s" % (dpatch_dir, dpatch) dest_filename = "%s/%s" % (output, dpatch) logger.info("Published %s", tree.subdir(config.get('ROOT'), dest_filename)) tree.ensure(dest_filename) tree.copyfile(src_filename, dest_filename)
def extract_dpatches(dirname, source): """Extract patches from debian/patches.""" srcdir = unpack_directory(source) patchdir = "%s/debian/patches" % srcdir if not os.path.isdir(patchdir): logging.debug("No debian/patches") return for patch in tree.walk(patchdir): if os.path.basename(patch) in ["00list", "series", "README", ".svn", "CVS", ".bzr", ".git"]: continue elif not len(patch): continue logging.debug("%s", patch) src_filename = "%s/%s" % (patchdir, patch) dest_filename = "%s/%s" % (dirname, patch) ensure(dest_filename) tree.copyfile(src_filename, dest_filename)
def handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files): """Handle the common case of a file in both left and right.""" if filename == "debian/changelog": # two-way merge of changelogs merge_changelog(left_dir, right_dir, merged_dir, filename) elif filename.endswith(".po") and not \ same_file(left_stat, left_dir, right_stat, right_dir, filename): # two-way merge of po contents (do later) po_files.append(filename) return False elif filename.endswith(".pot") and not \ same_file(left_stat, left_dir, right_stat, right_dir, filename): # two-way merge of pot contents if merge_pot(left_dir, right_dir, merged_dir, filename): conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True elif base_stat is not None and S_ISREG(base_stat.st_mode): # was file in base: diff3 possible if merge_file(left_dir, left_name, left_distro, base_dir, right_dir, right_name, right_distro, merged_dir, filename): return True elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # same file in left and right logging.debug("%s and %s both turned into same file: %s", left_distro, right_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: # general file conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True # Apply permissions merge_attr(base_dir, left_dir, right_dir, merged_dir, filename) return False
def publish_patch(distro, source, filename, list_file): """Publish the latest version of the patch for all to see.""" publish_filename = published_file(distro, source) ensure(publish_filename) if os.path.isfile(publish_filename): os.unlink(publish_filename) os.link(filename, publish_filename) logging.info("Published %s", tree.subdir(ROOT, publish_filename)) print("%s %s" % (source["Package"], tree.subdir("%s/published" % ROOT, publish_filename)), file=list_file) # Remove older patches for junk in os.listdir(os.path.dirname(publish_filename)): junkpath = "%s/%s" % (os.path.dirname(publish_filename), junk) if os.path.isfile(junkpath) \ and junk != os.path.basename(publish_filename): os.unlink(junkpath) # Publish extracted patches output = "%s/extracted" % os.path.dirname(publish_filename) if os.path.isdir(output): tree.remove(output) dpatch_dir = dpatch_directory(distro, source) if os.path.isdir(dpatch_dir): for dpatch in tree.walk(dpatch_dir): if not len(dpatch): continue src_filename = "%s/%s" % (dpatch_dir, dpatch) dest_filename = "%s/%s" % (output, dpatch) logging.info("Published %s", tree.subdir(ROOT, dest_filename)) ensure(dest_filename) tree.copyfile(src_filename, dest_filename)
def extract_dpatches(dirname, pv): """Extract patches from debian/patches.""" srcdir = unpack_directory(pv) patchdir = "%s/debian/patches" % srcdir if not os.path.isdir(patchdir): logger.debug("No debian/patches") return for patch in tree.walk(patchdir): if os.path.basename(patch) in [ "00list", "series", "README", ".svn", "CVS", ".bzr", ".git" ]: continue elif not len(patch): continue logger.debug("%s", patch) src_filename = "%s/%s" % (patchdir, patch) dest_filename = "%s/%s" % (dirname, patch) tree.ensure(dest_filename) tree.copyfile(src_filename, dest_filename)
def handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files, result): """Handle the common case of a file in both left and right.""" do_attrs = True if base_stat and \ same_file(base_stat, base_dir, left_stat, left_dir, filename): # same file contents in base and left, meaning that the left # side was unmodified, so take the right side as-is logger.debug("%s was unmodified on the left", filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # same file contents in left and right logger.debug("%s and %s both turned into same file: %s", left_distro, right_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: conflicts, deferred = \ merge_file_contents(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files) if conflicts: result.conflicts.add(filename) do_attrs = False if deferred: do_attrs = False else: result.modified_files.add(filename) # Merge file permissions if do_attrs: merge_attr(base_dir, left_dir, right_dir, merged_dir, filename, result)
def merge_file(left_dir, left_name, left_distro, base_dir, right_dir, right_name, right_distro, merged_dir, filename): """Merge a file using diff3.""" dest = "%s/%s" % (merged_dir, filename) ensure(dest) with open(dest, "w") as output: status = shell.run(("diff3", "-E", "-m", "-L", left_name, "%s/%s" % (left_dir, filename), "-L", "BASE", "%s/%s" % (base_dir, filename), "-L", right_name, "%s/%s" % (right_dir, filename)), stdout=output, okstatus=(0, 1, 2)) if status != 0: if not tree.exists(dest) or os.stat(dest).st_size == 0: # Probably binary if same_file(os.stat("%s/%s" % (left_dir, filename)), left_dir, os.stat("%s/%s" % (right_dir, filename)), right_dir, filename): logging.debug("binary files are the same: %s", filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(os.stat("%s/%s" % (base_dir, filename)), base_dir, os.stat("%s/%s" % (left_dir, filename)), left_dir, filename): logging.debug("preserving binary change in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(os.stat("%s/%s" % (base_dir, filename)), base_dir, os.stat("%s/%s" % (right_dir, filename)), right_dir, filename): logging.debug("preserving binary change in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: logging.debug("binary file conflict: %s", filename) conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True else: logging.debug("Conflict in %s", filename) return True else: return False
def merge_file(left_dir, left_name, left_distro, base_dir, right_dir, right_name, right_distro, merged_dir, filename): """Merge a file using diff3.""" dest = "%s/%s" % (merged_dir, filename) tree.ensure(dest) with open(dest, "w") as output: status = shell.run(("diff3", "-E", "-m", "-L", left_name, "%s/%s" % (left_dir, filename), "-L", "BASE", "%s/%s" % (base_dir, filename), "-L", right_name, "%s/%s" % (right_dir, filename)), stdout=output, okstatus=(0,1,2)) if status != 0: if not tree.exists(dest) or os.stat(dest).st_size == 0: # Probably binary if same_file(os.stat("%s/%s" % (left_dir, filename)), left_dir, os.stat("%s/%s" % (right_dir, filename)), right_dir, filename): logger.debug("binary files are the same: %s", filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(os.stat("%s/%s" % (base_dir, filename)), base_dir, os.stat("%s/%s" % (left_dir, filename)), left_dir, filename): logger.debug("preserving binary change in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(os.stat("%s/%s" % (base_dir, filename)), base_dir, os.stat("%s/%s" % (right_dir, filename)), right_dir, filename): logger.debug("preserving binary change in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: logger.debug("binary file conflict: %s", filename) conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) return True else: logger.debug("Conflict in %s", filename) return True else: return False
def do_merge(left_dir, left, base_dir, right_dir, right, merged_dir): """Do the heavy lifting of comparing and merging.""" logger.debug("Producing merge in %s", tree.subdir(ROOT, merged_dir)) conflicts = [] po_files = [] left_name = left.package.name left_distro = left.package.distro.name right_name = right.package.name right_distro = right.package.distro.name # See what format each is and whether they're both quilt left_format = left.getSources()["Format"] right_format = right.getSources()["Format"] both_formats_quilt = left_format == right_format == "3.0 (quilt)" if both_formats_quilt: logger.debug("Only merging debian directory since both " "formats 3.0 (quilt)") # Look for files in the base and merge them if they're in both new # files (removed files get removed) for filename in tree.walk(base_dir): # If both packages are 3.0 (quilt), ignore everything except the # debian directory if both_formats_quilt and not tree.under("debian", filename): continue if tree.under(".pc", filename): # Not interested in merging quilt metadata continue base_stat = os.lstat("%s/%s" % (base_dir, filename)) try: left_stat = os.lstat("%s/%s" % (left_dir, filename)) except OSError: left_stat = None try: right_stat = os.lstat("%s/%s" % (right_dir, filename)) except OSError: right_stat = None if left_stat is None and right_stat is None: # Removed on both sides pass elif left_stat is None: logger.debug("removed from %s: %s", left_distro, filename) if not same_file(base_stat, base_dir, right_stat, right_dir, filename): # Changed on RHS conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) elif right_stat is None: # Removed on RHS only logger.debug("removed from %s: %s", right_distro, filename) if not same_file(base_stat, base_dir, left_stat, left_dir, filename): # Changed on LHS conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) elif S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files if handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files): conflicts.append(filename) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, left_stat, left_dir, filename): # right has changed in some way, keep that one logger.debug("preserving non-file change in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, right_stat, right_dir, filename): # left has changed in some way, keep that one logger.debug("preserving non-file change in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: # all three differ, mark a conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) # Look for files in the left hand side that aren't in the base, # conflict if new on both sides or copy into the tree for filename in tree.walk(left_dir): # If both packages are 3.0 (quilt), ignore everything except the # debian directory if both_formats_quilt and not tree.under("debian", filename): continue if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if tree.exists("%s/%s" % (base_dir, filename)): continue if not tree.exists("%s/%s" % (right_dir, filename)): logger.debug("new in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) continue left_stat = os.lstat("%s/%s" % (left_dir, filename)) right_stat = os.lstat("%s/%s" % (right_dir, filename)) if S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files if handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, None, None, merged_dir, filename, po_files): conflicts.append(filename) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) else: # they differ, mark a conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) # Copy new files on the right hand side only into the tree for filename in tree.walk(right_dir): if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if both_formats_quilt and not tree.under("debian", filename): # Always copy right version for quilt non-debian files if not tree.exists("%s/%s" % (left_dir, filename)): logger.debug("new in %s: %s", right_distro, filename) else: if tree.exists("%s/%s" % (base_dir, filename)): continue if tree.exists("%s/%s" % (left_dir, filename)): continue logger.debug("new in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) # Handle po files separately as they need special merging for filename in po_files: if merge_po(left_dir, right_dir, merged_dir, filename): conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) continue merge_attr(base_dir, left_dir, right_dir, merged_dir, filename) return conflicts
def do_merge(left_dir, left_name, left_format, left_distro, base_dir, right_dir, right_name, right_format, right_distro, merged_dir): """Do the heavy lifting of comparing and merging.""" logger.debug("Producing merge in %s", merged_dir) result = MergeData() po_files = [] both_formats_quilt = left_format == right_format == "3.0 (quilt)" if both_formats_quilt: logger.debug("Only merging debian directory since both " "formats 3.0 (quilt)") # Look for files in the base and merge them if they're in both new # files (removed files get removed) for filename in tree.walk(base_dir): # If both packages are 3.0 (quilt), ignore everything except the # debian directory if both_formats_quilt and not tree.under("debian", filename): continue if tree.under(".pc", filename): # Not interested in merging quilt metadata continue base_stat = os.lstat("%s/%s" % (base_dir, filename)) try: left_stat = os.lstat("%s/%s" % (left_dir, filename)) except OSError: left_stat = None try: right_stat = os.lstat("%s/%s" % (right_dir, filename)) except OSError: right_stat = None if left_stat is None and right_stat is None: # Removed on both sides pass elif left_stat is None: logger.debug("removed from %s: %s", left_distro, filename) if not same_file(base_stat, base_dir, right_stat, right_dir, filename): # Changed on RHS result.conflicts.add(filename) else: result.removed_files.add(filename) elif right_stat is None: # Removed on RHS only logger.debug("removed from %s: %s", right_distro, filename) if not same_file(base_stat, base_dir, left_stat, left_dir, filename): # Changed on LHS result.conflicts.add(filename) elif S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files, result) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, left_stat, left_dir, filename): # right has changed in some way, keep that one logger.debug("preserving non-file change in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, right_stat, right_dir, filename): # left has changed in some way, keep that one logger.debug("preserving non-file change in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) result.modified_files.add(filename) else: # all three differ, mark a conflict result.conflicts.add(filename) # Look for files in the left hand side that aren't in the base, # conflict if new on both sides or copy into the tree for filename in tree.walk(left_dir): # If both packages are 3.0 (quilt), ignore everything except the # debian directory if both_formats_quilt and not tree.under("debian", filename): continue if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if tree.exists("%s/%s" % (base_dir, filename)): continue if not tree.exists("%s/%s" % (right_dir, filename)): logger.debug("new in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) result.added_files.add(filename) continue left_stat = os.lstat("%s/%s" % (left_dir, filename)) right_stat = os.lstat("%s/%s" % (right_dir, filename)) if S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, None, None, merged_dir, filename, po_files, result) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) else: # they differ, mark a conflict result.conflicts.add(filename) # Copy new files on the right hand side only into the tree for filename in tree.walk(right_dir): if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if both_formats_quilt and not tree.under("debian", filename): # Always copy right version for quilt non-debian files if not tree.exists("%s/%s" % (left_dir, filename)): logger.debug("new in %s: %s", right_distro, filename) else: if tree.exists("%s/%s" % (base_dir, filename)): continue if tree.exists("%s/%s" % (left_dir, filename)): continue logger.debug("new in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) # Handle po files separately as they need special merging for filename in po_files: if not merge_po(left_dir, right_dir, merged_dir, filename): result.conflicts.add(filename) continue merge_attr(base_dir, left_dir, right_dir, merged_dir, filename, result) result.modified_files.add(filename) for conflict in result.conflicts: conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, conflict) return result
def do_merge(left_dir, left_name, left_distro, base_dir, right_dir, right_name, right_distro, merged_dir): """Do the heavy lifting of comparing and merging.""" logging.debug("Producing merge in %s", tree.subdir(ROOT, merged_dir)) conflicts = [] po_files = [] # Look for files in the base and merge them if they're in both new # files (removed files get removed) for filename in tree.walk(base_dir): if tree.under(".pc", filename): # Not interested in merging quilt metadata continue base_stat = os.lstat("%s/%s" % (base_dir, filename)) try: left_stat = os.lstat("%s/%s" % (left_dir, filename)) except OSError: left_stat = None try: right_stat = os.lstat("%s/%s" % (right_dir, filename)) except OSError: right_stat = None if left_stat is None and right_stat is None: # Removed on both sides pass elif left_stat is None: logging.debug("removed from %s: %s", left_distro, filename) if not same_file(base_stat, base_dir, right_stat, right_dir, filename): # Changed on RHS conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) elif right_stat is None: # Removed on RHS only logging.debug("removed from %s: %s", right_distro, filename) if not same_file(base_stat, base_dir, left_stat, left_dir, filename): # Changed on LHS conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) elif S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files if handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, base_stat, base_dir, merged_dir, filename, po_files): conflicts.append(filename) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, left_stat, left_dir, filename): # right has changed in some way, keep that one logging.debug("preserving non-file change in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) elif same_file(base_stat, base_dir, right_stat, right_dir, filename): # left has changed in some way, keep that one logging.debug("preserving non-file change in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) else: # all three differ, mark a conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) # Look for files in the left hand side that aren't in the base, # conflict if new on both sides or copy into the tree for filename in tree.walk(left_dir): if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if tree.exists("%s/%s" % (base_dir, filename)): continue if not tree.exists("%s/%s" % (right_dir, filename)): logging.debug("new in %s: %s", left_distro, filename) tree.copyfile("%s/%s" % (left_dir, filename), "%s/%s" % (merged_dir, filename)) continue left_stat = os.lstat("%s/%s" % (left_dir, filename)) right_stat = os.lstat("%s/%s" % (right_dir, filename)) if S_ISREG(left_stat.st_mode) and S_ISREG(right_stat.st_mode): # Common case: left and right are both files if handle_file(left_stat, left_dir, left_name, left_distro, right_dir, right_stat, right_name, right_distro, None, None, merged_dir, filename, po_files): conflicts.append(filename) elif same_file(left_stat, left_dir, right_stat, right_dir, filename): # left and right are the same, doesn't matter which we keep tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) else: # they differ, mark a conflict conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) # Copy new files on the right hand side only into the tree for filename in tree.walk(right_dir): if tree.under(".pc", filename): # Not interested in merging quilt metadata continue if tree.exists("%s/%s" % (base_dir, filename)): continue if tree.exists("%s/%s" % (left_dir, filename)): continue logging.debug("new in %s: %s", right_distro, filename) tree.copyfile("%s/%s" % (right_dir, filename), "%s/%s" % (merged_dir, filename)) # Handle po files separately as they need special merging for filename in po_files: if merge_po(left_dir, right_dir, merged_dir, filename): conflict_file(left_dir, left_distro, right_dir, right_distro, merged_dir, filename) conflicts.append(filename) continue merge_attr(base_dir, left_dir, right_dir, merged_dir, filename) return conflicts