/******************************************************************************* * Copyright (c) 2004, 2006 * Thomas Hallgren, Kenneth Olwing, Mitch Sonies * Pontus Rydin, Nils Unden, Peer Torngren * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed above, as Initial Contributors under such license. * The text of such license is available at www.eclipse.org. *******************************************************************************/ package org.eclipse.buckminster.manifest; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Difference { public enum RESULT { EQUAL, MATCHING, MERGABLE_NONMATCHING, NONMATCHING } private final Manifest m_left; private final Manifest m_right; private final Checksum[] m_leftOnlyChecksums; private final Checksum[] m_rightOnlyChecksums; private final Checksum[] m_commonChecksums; private final ChecksumPair[] m_nonMatchingChecksumPairs; private final PathEntry[] m_leftOnlyEntries; private final PathEntry[] m_rightOnlyEntries; private final PathEntry[] m_commonEntries; private final PathEntryPair[] m_matchingEntryPairs; private final PathEntryPair[] m_nonMatchingEntryPairs; private final RESULT m_result; /* package */Difference(Manifest left, Manifest right) { m_left = left; m_right = right; List<Checksum> leftOnlyChecksums = new ArrayList<Checksum>(); List<Checksum> rightOnlyChecksums = new ArrayList<Checksum>(); List<Checksum> commonChecksums = new ArrayList<Checksum>(); List<ChecksumPair> nonMatchingChecksumPairs = new ArrayList<ChecksumPair>(); List<PathEntry> leftOnlyEntries = new ArrayList<PathEntry>(); List<PathEntry> rightOnlyEntries = new ArrayList<PathEntry>(); List<PathEntry> commonEntries = new ArrayList<PathEntry>(); List<PathEntryPair> matchingEntryPairs = new ArrayList<PathEntryPair>(); List<PathEntryPair> nonMatchingEntryPairs = new ArrayList<PathEntryPair>(); for (Checksum leftChecksum : m_left.getAllChecksums()) { Checksum rightChecksum = m_right.getChecksum(leftChecksum.getAlgorithm(), leftChecksum.getAssumedLineSeparator()); if (rightChecksum == null) leftOnlyChecksums.add(leftChecksum); else if (leftChecksum.equals(rightChecksum)) commonChecksums.add(leftChecksum); else nonMatchingChecksumPairs.add(new ChecksumPair(leftChecksum, rightChecksum)); } for (Checksum rightChecksum : m_right.getAllChecksums()) if (m_left.getChecksum(rightChecksum.getAlgorithm(), rightChecksum.getAssumedLineSeparator()) == null) rightOnlyChecksums.add(rightChecksum); for (PathEntry leftEntry : m_left.getAllEntries()) { PathEntry rightEntry = m_right.getEntry(leftEntry.getName()); if (rightEntry == null) leftOnlyEntries.add(leftEntry); else if (leftEntry.equals(rightEntry)) commonEntries.add(leftEntry); else { PathEntryPair pep = new PathEntryPair(leftEntry, rightEntry); if (leftEntry.matches(rightEntry)) matchingEntryPairs.add(pep); else nonMatchingEntryPairs.add(pep); } } for (PathEntry rightEntry : m_right.getAllEntries()) if (m_left.getEntry(rightEntry.getName()) == null) rightOnlyEntries.add(rightEntry); m_leftOnlyChecksums = leftOnlyChecksums.toArray(Checksum.EMPTY_LIST); m_rightOnlyChecksums = rightOnlyChecksums.toArray(Checksum.EMPTY_LIST); m_commonChecksums = commonChecksums.toArray(Checksum.EMPTY_LIST); m_nonMatchingChecksumPairs = nonMatchingChecksumPairs.toArray(ChecksumPair.EMPTY_LIST); m_leftOnlyEntries = leftOnlyEntries.toArray(PathEntry.EMPTY_LIST); m_rightOnlyEntries = rightOnlyEntries.toArray(PathEntry.EMPTY_LIST); m_commonEntries = commonEntries.toArray(PathEntry.EMPTY_LIST); m_matchingEntryPairs = matchingEntryPairs.toArray(PathEntryPair.EMPTY_LIST); m_nonMatchingEntryPairs = nonMatchingEntryPairs.toArray(PathEntryPair.EMPTY_LIST); if (m_leftOnlyChecksums.length == 0 && m_rightOnlyChecksums.length == 0 && m_nonMatchingChecksumPairs.length == 0 && m_leftOnlyEntries.length == 0 && m_rightOnlyEntries.length == 0 && m_matchingEntryPairs.length == 0 && m_nonMatchingEntryPairs.length == 0) m_result = RESULT.EQUAL; else if (m_nonMatchingChecksumPairs.length == 0 && m_leftOnlyEntries.length == 0 && m_rightOnlyEntries.length == 0 && m_nonMatchingEntryPairs.length == 0) m_result = RESULT.MATCHING; else if (m_nonMatchingChecksumPairs.length == 0 && m_nonMatchingEntryPairs.length == 0) m_result = RESULT.MERGABLE_NONMATCHING; else m_result = RESULT.NONMATCHING; assert verifyResult(m_left, m_right, m_result) : "Unexpectedly illogical"; } public Checksum[] getLeftOnlyChecksums() { return m_leftOnlyChecksums; } public Checksum[] getRightOnlyChecksums() { return m_rightOnlyChecksums; } public Checksum[] getCommonChecksums() { return m_commonChecksums; } public ChecksumPair[] getNonMatchingChecksums() { return m_nonMatchingChecksumPairs; } public PathEntry[] getLeftOnlyEntries() { return m_leftOnlyEntries; } public PathEntry[] getRightOnlyEntries() { return m_rightOnlyEntries; } public PathEntry[] getCommonEntries() { return m_commonEntries; } public PathEntryPair[] getMatchingEntryPairs() { return m_matchingEntryPairs; } public PathEntryPair[] getNonMatchingEntryPairs() { return m_nonMatchingEntryPairs; } public RESULT getResult() { return m_result; } @Override public String toString() { StringBuilder sb = new StringBuilder(m_result.toString()); sb.append(" : "); sb.append("checksums=").append(m_commonChecksums.length); sb.append('/').append(m_leftOnlyChecksums.length); sb.append('/').append(m_rightOnlyChecksums.length); sb.append('/').append(m_nonMatchingChecksumPairs.length); sb.append(", "); sb.append("entries=").append(m_commonEntries.length); sb.append('/').append(m_leftOnlyEntries.length); sb.append('/').append(m_rightOnlyEntries.length); sb.append('/').append(m_matchingEntryPairs.length); sb.append('/').append(m_nonMatchingEntryPairs.length); sb.append(" : "); sb.append(Arrays.toString(new Manifest[] { m_left, m_right })); return sb.toString(); } public void report(PrintWriter pw) { this.report(pw, false); } public void report(PrintWriter pw, boolean differencesOnly) { pw.println("*** Manifest difference report ***"); pw.println("Result: " + m_result); pw.println("1: " + m_left); pw.println("2: " + m_right); if (m_result != RESULT.EQUAL) { // Top level checksums // pw.println("*** Top level checksum report ***"); if (!differencesOnly) { if (m_commonChecksums.length == 0) pw.println("There are no common checksums."); else { pw.println("The following checksum(s) are common (" + m_commonChecksums.length + "):"); for (Checksum c : m_commonChecksums) pw.println(c); } } if (m_leftOnlyChecksums.length == 0) { if (!differencesOnly) pw.println("There are no checksums exclusive to the first manifest."); } else { pw.println("The following checksum(s) are exclusive to the first manifest (" + m_leftOnlyChecksums.length + "):"); for (Checksum c : m_leftOnlyChecksums) pw.println(c); } if (m_rightOnlyChecksums.length == 0) { if (!differencesOnly) pw.println("There are no checksums exclusive to the second manifest."); } else { pw.println("The following checksum(s) are exclusive to the second manifest (" + m_rightOnlyChecksums.length + "):"); for (Checksum c : m_rightOnlyChecksums) pw.println(c); } if (m_nonMatchingChecksumPairs.length == 0) { if (!differencesOnly) pw.println("There are no checksums that conflict between the manifests."); } else { pw.println("The following checksum(s) conflict between the manifests (" + m_nonMatchingChecksumPairs.length + "):"); for (ChecksumPair cp : m_nonMatchingChecksumPairs) pw.println(cp); } // Entries // pw.println("*** Entry report ***"); if (!differencesOnly) { if (m_commonEntries.length == 0) pw.println("There are no common entries."); else { pw.println("The following entries are common (" + m_commonEntries.length + "):"); for (PathEntry pe : m_commonEntries) pw.println(pe); } } if (m_leftOnlyEntries.length == 0) { if (!differencesOnly) pw.println("There are no entries exclusive to the first manifest."); } else { pw.println("The following entry/entries are exclusive to the first manifest (" + m_leftOnlyEntries.length + "):"); for (PathEntry pe : m_leftOnlyEntries) pw.println(pe); } if (m_rightOnlyEntries.length == 0) { if (!differencesOnly) pw.println("There are no entries exclusive to the second manifest."); } else { pw.println("The following entry/entries are exclusive to the second manifest (" + m_rightOnlyEntries.length + "):"); for (PathEntry pe : m_rightOnlyEntries) pw.println(pe); } if (m_matchingEntryPairs.length == 0) { if (!differencesOnly) pw.println("There are no entries that only match between the manifests."); } else { pw.println("The following entry/entries match between the manifests (" + m_matchingEntryPairs.length + "):"); for (PathEntryPair pep : m_matchingEntryPairs) pw.println(pep); } if (m_nonMatchingEntryPairs.length == 0) { if (!differencesOnly) pw.println("There are no entries that conflict between the manifests."); } else { pw.println("The following entry/entries conflict between the manifests (" + m_nonMatchingEntryPairs.length + "):"); for (PathEntryPair pep : m_nonMatchingEntryPairs) pw.println(pep); } } } private static boolean verifyResult(Manifest left, Manifest right, Difference.RESULT result) { boolean equals = left.equals(right); return !((result == RESULT.EQUAL && !equals) || (result != RESULT.EQUAL && equals)); } }