From de97d643046c04e2b9a916af33fd394a43d1072f Mon Sep 17 00:00:00 2001 From: Michael Valenta Date: Tue, 15 Jul 2008 14:45:29 +0000 Subject: Bug 207704 Decouple org.eclipse.compare from UI --- bundles/org.eclipse.compare/META-INF/MANIFEST.MF | 5 +- .../org/eclipse/compare/internal/Utilities.java | 2 +- .../compare/internal/patch/DiffProject.java | 108 --- .../eclipse/compare/internal/patch/FileDiff.java | 248 ------ .../compare/internal/patch/FileDiffResult.java | 326 -------- .../org/eclipse/compare/internal/patch/Hunk.java | 451 ----------- .../compare/internal/patch/HunkDiffNode.java | 1 + .../eclipse/compare/internal/patch/HunkResult.java | 294 ------- .../compare/internal/patch/HunkTypedElement.java | 1 + .../compare/internal/patch/InputPatchPage.java | 1 + .../eclipse/compare/internal/patch/LineReader.java | 137 ---- .../internal/patch/PatchCompareEditorInput.java | 6 +- .../compare/internal/patch/PatchFileDiffNode.java | 25 +- .../internal/patch/PatchFileTypedElement.java | 17 +- .../compare/internal/patch/PatchMessages.java | 8 +- .../internal/patch/PatchMessages.properties | 6 - .../internal/patch/PatchProjectDiffNode.java | 1 + .../compare/internal/patch/PatchReader.java | 663 ---------------- .../compare/internal/patch/PatchWizard.java | 7 +- .../eclipse/compare/internal/patch/Patcher.java | 204 +---- .../compare/internal/patch/PreviewPatchPage2.java | 2 + .../internal/patch/RetargetPatchElementDialog.java | 3 + .../internal/patch/UnmatchedHunkTypedElement.java | 14 +- .../internal/patch/WorkspaceFileDiffResult.java | 11 +- .../compare/internal/patch/WorkspacePatcher.java | 56 +- .../eclipse/compare/patch/ApplyPatchOperation.java | 32 +- .../org/eclipse/compare/patch/IFilePatch.java | 89 --- .../eclipse/compare/patch/IFilePatchResult.java | 94 --- .../compare/org/eclipse/compare/patch/IHunk.java | 82 -- .../eclipse/compare/patch/PatchConfiguration.java | 122 --- .../eclipse/compare/patch/WorkspacePatcherUI.java | 2 +- .../org.eclipse.compare.core/META-INF/MANIFEST.MF | 2 +- .../compare/internal/core/patch/DiffProject.java | 98 +++ .../compare/internal/core/patch/FileDiff.java | 260 ++++++ .../internal/core/patch/FileDiffResult.java | 335 ++++++++ .../eclipse/compare/internal/core/patch/Hunk.java | 446 +++++++++++ .../compare/internal/core/patch/HunkResult.java | 296 +++++++ .../compare/internal/core/patch/IHunkFilter.java | 27 + .../compare/internal/core/patch/LineReader.java | 269 +++++++ .../compare/internal/core/patch/PatchReader.java | 669 ++++++++++++++++ .../compare/internal/core/patch/Utilities.java | 31 + .../compare/internal/patch/DiffProject.java | 98 --- .../eclipse/compare/internal/patch/FileDiff.java | 260 ------ .../compare/internal/patch/FileDiffResult.java | 335 -------- .../org/eclipse/compare/internal/patch/Hunk.java | 446 ----------- .../eclipse/compare/internal/patch/HunkResult.java | 294 ------- .../eclipse/compare/internal/patch/LineReader.java | 137 ---- .../compare/internal/patch/PatchReader.java | 669 ---------------- .../eclipse/compare/internal/patch/Patcher.java | 877 --------------------- .../eclipse/compare/internal/patch/Utilities.java | 31 - .../internal/patch/WorkspaceFileDiffResult.java | 53 -- .../compare/internal/patch/WorkspacePatcher.java | 377 --------- .../src/org/eclipse/compare/patch/PatchParser.java | 18 +- .../org.eclipse.compare/META-INF/MANIFEST.MF | 5 +- .../org/eclipse/compare/internal/Utilities.java | 2 +- .../compare/internal/patch/Attic/LineReader.java | 137 ---- .../compare/internal/patch/DiffProject.java | 108 --- .../eclipse/compare/internal/patch/FileDiff.java | 248 ------ .../compare/internal/patch/FileDiffResult.java | 326 -------- .../org/eclipse/compare/internal/patch/Hunk.java | 451 ----------- .../compare/internal/patch/HunkDiffNode.java | 1 + .../eclipse/compare/internal/patch/HunkResult.java | 294 ------- .../compare/internal/patch/HunkTypedElement.java | 1 + .../compare/internal/patch/InputPatchPage.java | 1 + .../eclipse/compare/internal/patch/LineReader.java | 137 ---- .../internal/patch/PatchCompareEditorInput.java | 6 +- .../compare/internal/patch/PatchFileDiffNode.java | 25 +- .../internal/patch/PatchFileTypedElement.java | 17 +- .../compare/internal/patch/PatchMessages.java | 8 +- .../internal/patch/PatchMessages.properties | 6 - .../internal/patch/PatchProjectDiffNode.java | 1 + .../compare/internal/patch/PatchReader.java | 663 ---------------- .../compare/internal/patch/PatchWizard.java | 7 +- .../eclipse/compare/internal/patch/Patcher.java | 204 +---- .../compare/internal/patch/PreviewPatchPage2.java | 2 + .../internal/patch/RetargetPatchElementDialog.java | 3 + .../internal/patch/UnmatchedHunkTypedElement.java | 14 +- .../internal/patch/WorkspaceFileDiffResult.java | 11 +- .../compare/internal/patch/WorkspacePatcher.java | 56 +- .../eclipse/compare/patch/ApplyPatchOperation.java | 32 +- .../eclipse/compare/patch/Attic/IFilePatch.java | 89 --- .../org/eclipse/compare/patch/IFilePatch.java | 89 --- .../eclipse/compare/patch/IFilePatchResult.java | 94 --- .../compare/org/eclipse/compare/patch/IHunk.java | 82 -- .../eclipse/compare/patch/PatchConfiguration.java | 122 --- .../eclipse/compare/patch/WorkspacePatcherUI.java | 2 +- .../eclipse/compare/tests/FileDiffResultTest.java | 8 +- .../org/eclipse/compare/tests/LineReaderTest.java | 2 +- .../src/org/eclipse/compare/tests/PatchTest.java | 11 +- 89 files changed, 2793 insertions(+), 9518 deletions(-) delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/HunkResult.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/LineReader.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java delete mode 100644 bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/DiffProject.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiff.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiffResult.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Hunk.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/HunkResult.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/IHunkFilter.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/LineReader.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/PatchReader.java create mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Utilities.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/DiffProject.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiff.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiffResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Hunk.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/HunkResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/LineReader.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/PatchReader.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Patcher.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Utilities.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspacePatcher.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Attic/LineReader.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/HunkResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/LineReader.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/Attic/IFilePatch.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java delete mode 100644 bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java diff --git a/bundles/org.eclipse.compare/META-INF/MANIFEST.MF b/bundles/org.eclipse.compare/META-INF/MANIFEST.MF index 773eb2378..c2120a365 100644 --- a/bundles/org.eclipse.compare/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.compare/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.compare; singleton:=true -Bundle-Version: 3.4.0.qualifier +Bundle-Version: 3.4.100.qualifier Bundle-Activator: org.eclipse.compare.internal.CompareUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -23,7 +23,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="[3.3.0,4.0.0)", org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)", org.eclipse.ui.editors;bundle-version="[3.3.0,4.0.0)", - org.eclipse.ui.forms;bundle-version="[3.2.0,4.0.0)" + org.eclipse.ui.forms;bundle-version="[3.2.0,4.0.0)", + org.eclipse.compare.core;bundle-version="[3.4.100,4.0.0)";visibility:=reexport Bundle-ActivationPolicy: lazy Import-Package: com.ibm.icu.util, com.ibm.icu.text diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java index dbc7d67f8..0ef89503f 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java @@ -16,7 +16,7 @@ import java.util.List; import org.eclipse.compare.*; import org.eclipse.compare.contentmergeviewer.IDocumentRange; -import org.eclipse.compare.internal.patch.HunkResult; +import org.eclipse.compare.internal.core.patch.HunkResult; import org.eclipse.compare.patch.IHunk; import org.eclipse.compare.structuremergeviewer.DiffNode; import org.eclipse.compare.structuremergeviewer.ICompareInput; diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java deleted file mode 100644 index f5469efb4..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.*; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.model.IWorkbenchAdapter; - -/** - * A diff project represents a project that was read from a workspace patch. - * It contains the set of file diffs that were associated with the project - * in the patch file. - */ -public class DiffProject { - - private IProject fProject; - private Set fDiffs= new HashSet(); - - /** - * Create a diff project for the given workspace project. - * @param project a workspace project - */ - public DiffProject(IProject project) { - this.fProject= project; - } - - /** - * Add the file diff to this project. - * @param diff the file diff. - */ - void add(FileDiff diff) { - fDiffs.add(diff); - if (diff.getProject() != this) - diff.setProject(this); - } - - - /** - * Return the workspace project associated with this diff project. - * @return the workspace project associated with this project - */ - public IProject getProject() { - return this.fProject; - } - - /** - * Return the name of this project. - * @return the name of this project - */ - public String getName() { - return fProject.getName(); - } - - /** - * Return the file at the given path relative to this project. - * @param path the relative path - * @return the file at the given path relative to this project - */ - public IFile getFile(IPath path) { - return fProject.getFile(path); - } - - public ImageDescriptor getImageDescriptor() { - Object o= fProject.getAdapter(IWorkbenchAdapter.class); - if (o instanceof IWorkbenchAdapter) { - ImageDescriptor id= ((IWorkbenchAdapter) o).getImageDescriptor(fProject); - return id; - } - return null; - } - - /** - * Remove the file diff from this project. - * @param diff the diff to be removed - */ - public void remove(FileDiff diff) { - fDiffs.remove(diff); - } - - /** - * Return whether this project contains the given diff. - * @param diff a file diff - * @return whether this project contains the given diff - */ - public boolean contains(FileDiff diff) { - return fDiffs.contains(diff); - } - - /** - * Return the file diffs associated with this project. - * @return the file diffs associated with this project - */ - public FileDiff[] getFileDiffs() { - return (FileDiff[]) fDiffs.toArray(new FileDiff[fDiffs.size()]); - } -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java deleted file mode 100644 index 701f5b14a..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java +++ /dev/null @@ -1,248 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.compare.patch.IFilePatchResult; -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Path; - -/** - * A file diff represents a set of hunks that were associated with the - * same path in a patch file. - */ -public class FileDiff implements IFilePatch { - - private IPath fOldPath, fNewPath; - private long oldDate, newDate; - private List fHunks= new ArrayList(); - private DiffProject fProject; //the project that contains this diff - private String header; - private int addedLines, removedLines; - - /** - * Create a file diff for the given path and date information. - * @param oldPath the path of the before state of the file - * @param oldDate the timestamp of the before state - * @param newPath the path of the after state - * @param newDate the timestamp of the after state - */ - protected FileDiff(IPath oldPath, long oldDate, IPath newPath, long newDate) { - fOldPath= oldPath; - this.oldDate = oldDate; - fNewPath= newPath; - this.newDate = newDate; - } - - /** - * Return the parent project or null if there isn't one. - * @return the parent project or null - */ - public DiffProject getProject() { - return fProject; - } - - /** - * Set the project of this diff to the given project. - * This method should only be called from - * {@link DiffProject#add(FileDiff)} - * @param diffProject the parent project - */ - void setProject(DiffProject diffProject) { - if (fProject == diffProject) - return; - if (fProject != null) - fProject.remove(this); - this.fProject= diffProject; - } - - /** - * Get the path of the file diff. - * @param reverse whether the path of the before state or after state - * should be used - * @return the path of the file diff - */ - protected IPath getPath(boolean reverse) { - if (getDiffType(reverse) == Differencer.ADDITION) { - if (reverse) - return fOldPath; - return fNewPath; - } - if (reverse && fNewPath != null) - return fNewPath; - if (fOldPath != null) - return fOldPath; - return fNewPath; - } - - /** - * Add the hunk to this file diff. - * @param hunk the hunk - */ - protected void add(Hunk hunk) { - fHunks.add(hunk); - hunk.setParent(this); - } - - /** - * Remove the hunk from this file diff - * @param hunk the hunk - */ - protected void remove(Hunk hunk) { - fHunks.remove(hunk); - } - - /** - * Return the hunks associated with this file diff. - * @return the hunks associated with this file diff - */ - public Hunk[] getHunks() { - return (Hunk[]) fHunks.toArray(new Hunk[fHunks.size()]); - } - - /** - * Return the number of hunks associated with this file diff. - * @return the number of hunks associated with this file diff - */ - public int getHunkCount() { - return fHunks.size(); - } - - /** - * Return the difference type of this file diff. - * @param reverse whether the patch is being reversed - * @return the type of this file diff - */ - public int getDiffType(boolean reverse) { - if (fHunks.size() == 1) { - boolean add = false; - boolean delete = false; - Iterator iter = fHunks.iterator(); - while (iter.hasNext()){ - Hunk hunk = (Hunk) iter.next(); - int type =hunk.getHunkType(reverse); - if (type == Hunk.ADDED){ - add = true; - } else if (type == Hunk.DELETED ){ - delete = true; - } - } - if (add && !delete){ - return Differencer.ADDITION; - } else if (!add && delete){ - return Differencer.DELETION; - } - } - return Differencer.CHANGE; - } - - /** - * Return the path of this file diff with the specified number - * of leading segments striped. - * @param strip the number of leading segments to strip from the path - * @param reverse whether the patch is being reversed - * @return the path of this file diff with the specified number - * of leading segments striped - */ - protected IPath getStrippedPath(int strip, boolean reverse) { - IPath path= getPath(reverse); - if (strip > 0 && strip < path.segmentCount()) - path= path.removeFirstSegments(strip); - return path; - } - - /** - * Return the segment count of the path of this file diff. - * @return the segment count of the path of this file diff - */ - public int segmentCount() { - //Update prefix count - go through all of the diffs and find the smallest - //path segment contained in all diffs. - int length= 99; - if (fOldPath != null) - length= Math.min(length, fOldPath.segmentCount()); - if (fNewPath != null) - length= Math.min(length, fNewPath.segmentCount()); - return length; - } - - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor) { - FileDiffResult result = new FileDiffResult(this, configuration); - result.refresh(contents, monitor); - return result; - } - - public IPath getTargetPath(PatchConfiguration configuration) { - return getStrippedPath(configuration.getPrefixSegmentStripCount(), configuration.isReversed()); - } - - public FileDiff asRelativeDiff() { - if (fProject == null) - return this; - IPath adjustedOldPath = null; - if (fOldPath != null) { - adjustedOldPath = new Path(null, fProject.getName()).append(fOldPath); - } - IPath adjustedNewPath = null; - if (fNewPath != null) { - adjustedNewPath = new Path(null, fProject.getName()).append(fNewPath); - } - FileDiff diff = new FileDiff(adjustedOldPath, 0, adjustedNewPath, 0); - for (Iterator iterator = fHunks.iterator(); iterator.hasNext();) { - Hunk hunk = (Hunk) iterator.next(); - // Creating the hunk adds it to the parent diff - new Hunk(diff, hunk); - } - return diff; - } - - public void setHeader(String header) { - this.header = header; - } - - public String getHeader() { - return header; - } - - public long getBeforeDate() { - return oldDate; - } - - public long getAfterDate() { - return newDate; - } - - public void setAddedLines(int addedLines) { - this.addedLines = addedLines; - } - - public void setRemovedLines(int removedLines) { - this.removedLines = removedLines; - } - - public int getAddedLines() { - return addedLines; - } - - public int getRemovedLines() { - return removedLines; - } - -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java deleted file mode 100644 index 84ca27166..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java +++ /dev/null @@ -1,326 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.*; - -import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.patch.*; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; -import org.eclipse.osgi.util.NLS; - -public class FileDiffResult implements IFilePatchResult { - - private FileDiff fDiff; - private boolean fMatches= false; - private boolean fDiffProblem; - private String fErrorMessage; - private Map fHunkResults = new HashMap(); - private List fBeforeLines, fAfterLines; - private final PatchConfiguration configuration; - private String charset; - - public FileDiffResult(FileDiff diff, PatchConfiguration configuration) { - super(); - fDiff = diff; - this.configuration = configuration; - } - - public PatchConfiguration getConfiguration() { - return configuration; - } - - public boolean canApplyHunk(Hunk hunk) { - HunkResult result = getHunkResult(hunk); - return result.isOK() && !fDiffProblem; - } - - /** - * Refreshes the state of the diff to {no matches, no problems} and checks to see what hunks contained - * by this Diff can actually be applied. - * - * Checks to see: - * 1) if the target file specified in fNewPath exists and is patchable - * 2) which hunks contained by this diff can actually be applied to the file - * @param storage the contents being patched or null for an addition - * @param monitor a progress monitor or null if no progress monitoring is desired - */ - public void refresh(IStorage storage, IProgressMonitor monitor) { - fMatches= false; - fDiffProblem= false; - boolean create= false; - charset = Utilities.getCharset(storage); - //If this diff is an addition, make sure that it doesn't already exist - boolean exists = targetExists(storage); - if (fDiff.getDiffType(getConfiguration().isReversed()) == Differencer.ADDITION) { - if ((!exists || isEmpty(storage)) && canCreateTarget(storage)) { - fMatches= true; - } else { - // file already exists - fDiffProblem= true; - fErrorMessage= PatchMessages.PreviewPatchPage_FileExists_error; - } - create= true; - } else { //This diff is not an addition, try to find a match for it - //Ensure that the file described by the path exists and is modifiable - if (exists) { - fMatches= true; - } else { - // file doesn't exist - fDiffProblem= true; - fErrorMessage= PatchMessages.PreviewPatchPage_FileDoesNotExist_error; - } - } - - if (fDiffProblem) { - // We couldn't find the target file or the patch is trying to add a - // file that already exists but we need to initialize the hunk - // results for display - fBeforeLines = new ArrayList(getLines(storage, false)); - fAfterLines = fMatches ? new ArrayList() : fBeforeLines; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setMatches(false); - } - } else { - // If this diff has no problems discovered so far, try applying the patch - patch(getLines(storage, create), monitor); - } - - if (containsProblems()) { - if (fMatches) { - // Check to see if we have at least one hunk that matches - fMatches = false; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - if (result.isOK()) { - fMatches = true; - break; - } - } - } - } - } - - protected boolean canCreateTarget(IStorage storage) { - return true; - } - - protected boolean targetExists(IStorage storage) { - return storage != null; - } - - protected List getLines(IStorage storage, boolean create) { - List lines = Patcher.load(storage, create); - return lines; - } - - protected boolean isEmpty(IStorage storage) { - if (storage == null) - return true; - return Patcher.load(storage, false).isEmpty(); - } - - /* - * Tries to patch the given lines with the specified Diff. - * Any hunk that couldn't be applied is returned in the list failedHunks. - */ - public void patch(List lines, IProgressMonitor monitor) { - fBeforeLines = new ArrayList(); - fBeforeLines.addAll(lines); - if (getConfiguration().getFuzz() != 0) { - calculateFuzz(fBeforeLines, monitor); - } - int shift= 0; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setShift(shift); - if (result.patch(lines)) { - shift = result.getShift(); - } - } - fAfterLines = lines; - } - - protected boolean getDiffProblem() { - return fDiffProblem; - } - - /** - * Returns whether this Diff has any problems - * @return true if this Diff or any of its children Hunks have a problem, false if it doesn't - */ - protected boolean containsProblems() { - if (fDiffProblem) - return true; - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - return true; - } - return false; - } - - public String getLabel() { - String label= getTargetPath().toString(); - if (this.fDiffProblem) - return NLS.bind(PatchMessages.Diff_2Args, new String[] {label, fErrorMessage}); - return label; - } - - public boolean hasMatches() { - return fMatches; - } - - /** - * Return the lines of the target file with all matched hunks applied. - * @return the lines of the target file with all matched hunks applied - */ - public List getLines() { - return fAfterLines; - } - - /** - * Calculate the fuzz factor that will allow the most hunks to be matched. - * @param lines the lines of the target file - * @param monitor a progress monitor - * @return the fuzz factor or -1 if no hunks could be matched - */ - public int calculateFuzz(List lines, IProgressMonitor monitor) { - if (monitor == null) - monitor = new NullProgressMonitor(); - fBeforeLines = new ArrayList(lines); - // TODO: What about deletions? - if (fDiff.getDiffType(getConfiguration().isReversed()) == Differencer.ADDITION) { - // Additions don't need to adjust the fuzz factor - // TODO: What about the after lines? - return -1; - } - int shift= 0; - int highestFuzz = -1; // the maximum fuzz factor for all hunks - String name = getTargetPath() != null ? getTargetPath().lastSegment() : ""; //$NON-NLS-1$ - Hunk[] hunks = fDiff.getHunks(); - for (int j = 0; j < hunks.length; j++) { - Hunk h = hunks[j]; - monitor.subTask(NLS.bind(PatchMessages.PreviewPatchPage_GuessFuzzProgress_format, new String[] {name, Integer.toString(j + 1)})); - HunkResult result = getHunkResult(h); - result.setShift(shift); - int fuzz = result.calculateFuzz(lines, monitor); - shift = result.getShift(); - if (fuzz > highestFuzz) - highestFuzz = fuzz; - monitor.worked(1); - } - fAfterLines = lines; - return highestFuzz; - } - - public IPath getTargetPath() { - return fDiff.getStrippedPath(getConfiguration().getPrefixSegmentStripCount(), getConfiguration().isReversed()); - } - - private HunkResult getHunkResult(Hunk hunk) { - HunkResult result = (HunkResult)fHunkResults.get(hunk); - if (result == null) { - result = new HunkResult(this, hunk); - fHunkResults .put(hunk, result); - } - return result; - } - - List getFailedHunks() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result.getHunk()); - } - return failedHunks; - } - - private HunkResult[] getFailedHunkResults() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result); - } - return (HunkResult[]) failedHunks.toArray(new HunkResult[failedHunks.size()]); - } - - public FileDiff getDiff() { - return fDiff; - } - - List getBeforeLines() { - return fBeforeLines; - } - - List getAfterLines() { - return fAfterLines; - } - - public HunkResult[] getHunkResults() { - return (HunkResult[]) fHunkResults.values().toArray(new HunkResult[fHunkResults.size()]); - } - - public InputStream getOriginalContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getBeforeLines()); - return asInputStream(contents, getCharset()); - } - - public InputStream getPatchedContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getLines()); - return asInputStream(contents, getCharset()); - } - - public String getCharset() { - return charset; - } - - protected boolean isPreserveLineDelimeters() { - return false; - } - - public IHunk[] getRejects() { - return getFailedHunkResults(); - } - - public boolean hasRejects() { - return getFailedHunkResults().length > 0; - } - - public static InputStream asInputStream(String contents, String charSet) { - byte[] bytes = null; - if (charSet != null) { - try { - bytes = contents.getBytes(charSet); - } catch (UnsupportedEncodingException e) { - CompareUIPlugin.log(e); - } - } - if (bytes == null) { - bytes = contents.getBytes(); - } - return new ByteArrayInputStream(bytes); - } - -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java deleted file mode 100644 index 9469fcb11..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java +++ /dev/null @@ -1,451 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.runtime.Assert; - -/** - * A Hunk describes a range of changed lines and some context lines. - */ -public class Hunk { - - public static final int ADDED = 0x1; - public static final int DELETED = 0x2; - public static final int CHANGED = 0x4; - public static final int UNKNOWN = 0x8; - - private FileDiff fParent; - private int fOldStart, fOldLength; - private int fNewStart, fNewLength; - private String[] fLines; - private int hunkType; - - public Hunk(FileDiff parent, Hunk toCopy) { - fParent = parent; - if (fParent != null) { - fParent.add(this); - } - - fOldStart = toCopy.fOldStart; - fOldLength = toCopy.fOldLength; - fNewStart = toCopy.fNewStart; - fNewLength = toCopy.fOldLength; - fLines = toCopy.fLines; - hunkType = toCopy.hunkType; - } - - public Hunk(FileDiff parent, int[] oldRange, int[] newRange, List lines, boolean encounteredPlus, boolean encounteredMinus, boolean encounteredSpace) { - - fParent= parent; - if (fParent != null) - fParent.add(this); - - if (oldRange[0] > 0) - fOldStart= oldRange[0]-1; // line number start at 0! - else - fOldStart= 0; - fOldLength= oldRange[1]; - if (newRange[0] > 0) - fNewStart= newRange[0]-1; // line number start at 0! - else - fNewStart= 0; - fNewLength= newRange[1]; - - fLines= (String[]) lines.toArray(new String[lines.size()]); - - if (encounteredSpace && (encounteredPlus || encounteredMinus)){ - hunkType = CHANGED; - } else if (encounteredPlus && !encounteredMinus && !encounteredSpace){ - hunkType = ADDED; - } else if (!encounteredPlus && encounteredMinus && !encounteredSpace) { - hunkType = DELETED; - } else { - hunkType = UNKNOWN; - } - } - - /* - * Returns the contents of this hunk. - * Each line starts with a control character. Their meaning is as follows: - * - */ - String getContent() { - StringBuffer sb= new StringBuffer(); - for (int i= 0; i < fLines.length; i++) { - String line= fLines[i]; - sb.append(line.substring(0, Patcher.length(line))); - sb.append('\n'); - } - return sb.toString(); - } - - /* - * Returns a descriptive String for this hunk. - * It is in the form old_start,old_length -> new_start,new_length. - */ - String getDescription() { - StringBuffer sb= new StringBuffer(); - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" -> "); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - return sb.toString(); - } - - String getRejectedDescription() { - StringBuffer sb= new StringBuffer(); - sb.append("@@ -"); //$NON-NLS-1$ - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" +"); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - sb.append(" @@"); //$NON-NLS-1$ - return sb.toString(); - } - - int getHunkType(boolean reverse) { - if (reverse) { - if (hunkType == ADDED) - return DELETED; - if (hunkType == DELETED) - return ADDED; - } - return hunkType; - } - - void setHunkType(int hunkType) { - this.hunkType = hunkType; - } - - public String[] getLines() { - return fLines; - } - - /** - * Set the parent of this hunk. This method - * should only be invoked from {@link FileDiff#add(Hunk)} - * @param diff the parent of this hunk - */ - void setParent(FileDiff diff) { - if (fParent == diff) - return; - if (fParent != null) - fParent.remove(this); - fParent = diff; - } - - public FileDiff getParent() { - return fParent; - } - - /* - * Tries to apply the given hunk on the specified lines. - * The parameter shift is added to the line numbers given - * in the hunk. - */ - public boolean tryPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - int deleteMatches = 0; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s = fLines[i]; - Assert.isTrue(s.length() > 0); - String line = s.substring(1); - char controlChar = s.charAt(0); - - if (controlChar == ' ') { // context lines - - if (pos < 0 || pos >= lines.size()) - return false; - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - return false; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - return false; - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (pos < 0 || pos >= lines.size()) // out of the file - return false; - if (linesMatch(configuration, line, (String) lines.get(pos))) { - deleteMatches++; - pos++; - continue; // line matched, continue with the next one - } - - // We must remove all lines at once, return false if this - // fails. In other words, all lines considered for deletion - // must be found one by one. - - // if (deleteMatches <= 0) - return false; - // pos++; - } else if (isAddedDelimeter(controlChar, reverse)) { - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - return false; - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - // we don't have to do anything more for a 'try' - } else - Assert.isTrue(false, "tryPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - - // check following context lines if exist - if (!contextLinesMatched - && fuzz > 0 - && contextLines.size() > fuzz - && !checkFollowingContextLines(configuration, lines, fuzz, pos, - contextLines)) - return false; - - return true; - } - - private boolean checkPrecedingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - - // ignore from the beginning - for (int j = fuzz; j < contextLines.size(); j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - return true; - } - - private boolean checkFollowingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - if (!contextLines.isEmpty()) { - // ignore from the end - for (int j = 0; j < contextLines.size() - fuzz; j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - } - return true; - } - - int getStart(boolean reverse) { - if (reverse) { - return fNewStart; - } - return fOldStart; - } - - private int getLength(boolean reverse) { - if (reverse) { - return fNewLength; - } - return fOldLength; - } - - private int getShift(boolean reverse) { - if (reverse) { - return fOldLength - fNewLength; - } - return fNewLength - fOldLength; - } - - int doPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s= fLines[i]; - Assert.isTrue(s.length() > 0); - String line= s.substring(1); - char controlChar= s.charAt(0); - if (controlChar == ' ') { - // context lines - Assert.isTrue(pos < lines.size(), "doPatch: inconsistency in context"); //$NON-NLS-1$ - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - Assert.isTrue(false, "doPatch: context doesn't match"); //$NON-NLS-1$ -// pos++; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - lines.remove(pos); - } else if (isAddedDelimeter(controlChar, reverse)) { - // added lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (getLength(reverse) == 0 && pos+1 < lines.size()) - lines.add(pos+1, line); - else - lines.add(pos, line); - pos++; - } else - Assert.isTrue(false, "doPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - return getShift(reverse); - } - - private boolean isDeletedDelimeter(char controlChar, boolean reverse) { - return (!reverse && controlChar == '-') || (reverse && controlChar == '+'); - } - - private boolean isAddedDelimeter(char controlChar, boolean reverse) { - return (reverse && controlChar == '-') || (!reverse && controlChar == '+'); - } - - /* - * Compares two strings. - * If fIgnoreWhitespace is true whitespace is ignored. - */ - private boolean linesMatch(PatchConfiguration configuration, String line1, String line2) { - if (configuration.isIgnoreWhitespace()) - return stripWhiteSpace(line1).equals(stripWhiteSpace(line2)); - if (isIgnoreLineDelimiter()) { - int l1= Patcher.length(line1); - int l2= Patcher.length(line2); - if (l1 != l2) - return false; - return line1.regionMatches(0, line2, 0, l1); - } - return line1.equals(line2); - } - - private boolean isIgnoreLineDelimiter() { - return true; - } - - /* - * Returns the given string with all whitespace characters removed. - * Whitespace is defined by Character.isWhitespace(...). - */ - private String stripWhiteSpace(String s) { - StringBuffer sb= new StringBuffer(); - int l= s.length(); - for (int i= 0; i < l; i++) { - char c= s.charAt(i); - if (!Character.isWhitespace(c)) - sb.append(c); - } - return sb.toString(); - } - - public String getContents(boolean isAfterState, boolean reverse) { - StringBuffer result= new StringBuffer(); - for (int i= 0; i - Bug 181919 LineReader creating unneeded garbage - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.runtime.Assert; - -public class LineReader { - - private boolean fHaveChar= false; - private int fLastChar; - private boolean fSawEOF= false; - private BufferedReader fReader; - private boolean fIgnoreSingleCR= false; - private StringBuffer fBuffer= new StringBuffer(); - - public LineReader(BufferedReader reader) { - fReader= reader; - Assert.isNotNull(reader); - } - - void ignoreSingleCR() { - fIgnoreSingleCR= true; - } - - /** - * Reads a line of text. A line is considered to be terminated by any one - * of a line feed ('\n'), a carriage return ('\r'), or a carriage return - * followed immediately by a line-feed. - * @return A string containing the contents of the line including - * the line-termination characters, or null if the end of the - * stream has been reached - * @exception IOException If an I/O error occurs - */ - /* package */ String readLine() throws IOException { - try { - while (!fSawEOF) { - int c= readChar(); - if (c == -1) { - fSawEOF= true; - break; - } - fBuffer.append((char)c); - if (c == '\n') - break; - if (c == '\r') { - c= readChar(); - if (c == -1) { - fSawEOF= true; - break; // EOF - } - if (c != '\n') { - if (fIgnoreSingleCR) { - fBuffer.append((char)c); - continue; - } - fHaveChar= true; - fLastChar= c; - } else - fBuffer.append((char)c); - break; - } - } - - if (fBuffer.length() != 0) { - return fBuffer.toString(); - } - return null; - } finally { - fBuffer.setLength(0); - } - } - - /* package */ void close() { - try { - fReader.close(); - } catch (IOException ex) { - // silently ignored - } - } - - public List readLines() { - try { - List lines= new ArrayList(); - String line; - while ((line= readLine()) != null) - lines.add(line); - return lines; - } catch (IOException ex) { - // NeedWork - //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); - } finally { - close(); - } - return null; - } - - /* - * Returns the number of characters in the given string without - * counting a trailing line separator. - */ - /* package */ int lineContentLength(String line) { - if (line == null) - return 0; - int length= line.length(); - for (int i= length-1; i >= 0; i--) { - char c= line.charAt(i); - if (c =='\n' || c == '\r') - length--; - else - break; - } - return length; - } - - //---- private - - private int readChar() throws IOException { - if (fHaveChar) { - fHaveChar= false; - return fLastChar; - } - return fReader.read(); - } -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java index c80ef9436..278296a00 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java @@ -14,6 +14,10 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.*; import org.eclipse.compare.internal.*; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.HunkResult; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.runtime.Assert; @@ -391,7 +395,7 @@ public abstract class PatchCompareEditorInput extends CompareEditorInput { public Viewer findStructureViewer(Viewer oldViewer, ICompareInput input, Composite parent) { - if (Utilities.isHunk(input)) + if (org.eclipse.compare.internal.Utilities.isHunk(input)) return null; return super.findStructureViewer(oldViewer, input, parent); } diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java index 5bc0e31e2..15cfa5a22 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java @@ -11,6 +11,8 @@ package org.eclipse.compare.internal.patch; import org.eclipse.compare.*; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.resources.IFile; @@ -26,7 +28,28 @@ public class PatchFileDiffNode extends PatchDiffNode implements IContentChangeLi private static int getKind(FileDiffResult result) { if (!result.hasMatches()) return Differencer.NO_CHANGE; - return result.getDiff().getDiffType(result.getConfiguration().isReversed()) | Differencer.RIGHT; + int fileDiffKind = result.getDiff().getDiffType(result.getConfiguration().isReversed()); + int kind = convertFileDiffTypeToDifferencerType(fileDiffKind); + return kind | Differencer.RIGHT; + } + + private static int convertFileDiffTypeToDifferencerType(int fileDiffKind) { + int kind; + switch (fileDiffKind) { + case FileDiff.ADDITION: + kind = Differencer.ADDITION; + break; + case FileDiff.DELETION: + kind = Differencer.DELETION; + break; + case FileDiff.CHANGE: + kind = Differencer.CHANGE; + break; + default: + kind = Differencer.CHANGE; + break; + } + return kind; } private static ITypedElement getRightElement(FileDiffResult result) { diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java index 04c519f2f..6f99a65bc 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java @@ -10,12 +10,21 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.List; -import org.eclipse.compare.*; +import org.eclipse.compare.CompareUI; +import org.eclipse.compare.IEncodedStreamContentAccessor; +import org.eclipse.compare.ITypedElement; import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.core.resources.*; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.swt.graphics.Image; @@ -88,7 +97,7 @@ public class PatchFileTypedElement implements ITypedElement, IEncodedStreamConte } else { lines = result.getBeforeLines(); } - String contents = Patcher.createString(getPatcher().isPreserveLineDelimeters(), lines); + String contents = LineReader.createString(getPatcher().isPreserveLineDelimeters(), lines); String charSet = getCharset(); byte[] bytes = null; if (charSet != null) { diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java index a2f101730..1a92a7463 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java @@ -14,7 +14,7 @@ import org.eclipse.osgi.util.NLS; public final class PatchMessages extends NLS { - private static final String BUNDLE_NAME = "org.eclipse.compare.internal.patch.PatchMessages";//$NON-NLS-1$ + private static final String BUNDLE_NAME = "org.eclipse.compare.internal.ui.patch.PatchMessages";//$NON-NLS-1$ private PatchMessages() { // Do not instantiate @@ -66,15 +66,9 @@ public final class PatchMessages extends NLS { public static String PreviewPatchPage_ReversePatch_text; public static String PreviewPatchPage_FuzzFactor_text; public static String PreviewPatchPage_FuzzFactor_tooltip; - public static String PreviewPatchPage_FileExists_error; - public static String PreviewPatchPage_FileDoesNotExist_error; public static String PreviewPatchPage_GuessFuzz_text; - public static String PreviewPatchPage_GuessFuzzProgress_text; - public static String PreviewPatchPage_GuessFuzzProgress_format; public static String PreviewPatchPage_FuzzUsed; public static String PreviewPatchPage_AllContextIgnored; - public static String Patcher_Marker_message; - public static String Patcher_Task_message; static { NLS.initializeMessages(BUNDLE_NAME, PatchMessages.class); diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties index 4e442b412..29224b777 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties @@ -88,17 +88,13 @@ PreviewPatchPage2_OrphanedHunk=Unmatched Patch Segment PreviewPatchPage2_MatchedHunk=Matched Hunk PreviewPatchPage2_IgnoreWSAction=Ignore whitespace PreviewPatchPage_FuzzFactor_tooltip=Allow this number of context lines to be ignored -PreviewPatchPage_FileExists_error=(file already exists) PreviewPatchPage2_IgnoreWSTooltip=Ignore whitespace PreviewPatchPage2_IgnoreWhitespace=Ignore whitespace PreviewPatchPage2_PatchedLocalFile=Patched Local File PreviewPatchPage2_CalculateReverse=Calculating reverse -PreviewPatchPage_FileDoesNotExist_error=(file does not exist) PreviewPatchPage_RetargetPatch=Retarget Patch PreviewPatchPage_SelectProject=Select the new target project for the portion of the patch targeted to project ''{0}'': PreviewPatchPage_GuessFuzz_text= &Guess -PreviewPatchPage_GuessFuzzProgress_text= Guessing Fuzz Factor... -PreviewPatchPage_GuessFuzzProgress_format= {0} (hunk #{1}) PreviewPatchPage_FuzzUsed=(fuzz factor used: {0}) PreviewPatchPage_AllContextIgnored=(fuzz factor used: {0}, all context lines ignored) PreviewPatchPage2_ShowMatched=Show &matched hunks @@ -108,8 +104,6 @@ PreviewPatchLabelDecorator_ProjectDoesNotExist=(Project does not exist in worksp # # Patcher # -Patcher_Marker_message=Rejected patch -Patcher_Task_message=Patching Diff_2Args={0} {1} HunkMergePage_Merged=(merged) HunkMergePage_GenerateRejectFile=G&enerate a .rej file for unmerged hunks diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java index 8b71f761a..4c6834f5f 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java @@ -12,6 +12,7 @@ package org.eclipse.compare.internal.patch; import org.eclipse.compare.CompareUI; import org.eclipse.compare.ITypedElement; +import org.eclipse.compare.internal.core.patch.DiffProject; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.jface.resource.LocalResourceManager; diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java deleted file mode 100644 index 7d0fa5af7..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java +++ /dev/null @@ -1,663 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; -import java.util.*; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.*; -import org.eclipse.swt.SWT; - -import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.SimpleDateFormat; - -public class PatchReader { - - private static final boolean DEBUG= false; - - private static final String DEV_NULL= "/dev/null"; //$NON-NLS-1$ - - protected static final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; //$NON-NLS-1$ - - // diff formats - // private static final int CONTEXT= 0; - // private static final int ED= 1; - // private static final int NORMAL= 2; - // private static final int UNIFIED= 3; - - // we recognize the following date/time formats - private DateFormat[] fDateFormats= new DateFormat[] { - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy"), //$NON-NLS-1$ - new SimpleDateFormat("yyyy/MM/dd kk:mm:ss"), //$NON-NLS-1$ - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy", Locale.US) //$NON-NLS-1$ - }; - - private boolean fIsWorkspacePatch; - private DiffProject[] fDiffProjects; - private FileDiff[] fDiffs; - - // API for writing new multi-project patch format - public static final String MULTIPROJECTPATCH_HEADER= "### Eclipse Workspace Patch"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_VERSION= "1.0"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_PROJECT= "#P"; //$NON-NLS-1$ - - /** - * Create a patch reader for the default date formats. - */ - public PatchReader() { - // nothing here - } - - /** - * Create a patch reader for the given date formats. - * - * @param dateFormats - * Array of DateFormats to be used when - * extracting dates from the patch. - */ - public PatchReader(DateFormat[] dateFormats) { - this(); - fDateFormats = dateFormats; - } - - public void parse(BufferedReader reader) throws IOException { - List diffs= new ArrayList(); - HashMap diffProjects= new HashMap(4); - String line= null; - boolean reread= false; - String diffArgs= null; - String fileName= null; - // no project means this is a single patch,create a placeholder project for now - // which will be replaced by the target selected by the user in the preview pane - String project= ""; //$NON-NLS-1$ - fIsWorkspacePatch= false; - - LineReader lr= new LineReader(reader); - if (!"carbon".equals(SWT.getPlatform())) //$NON-NLS-1$ - lr.ignoreSingleCR(); - - // Test for our format - line= lr.readLine(); - if (line != null && line.startsWith(PatchReader.MULTIPROJECTPATCH_HEADER)) { - fIsWorkspacePatch= true; - } else { - parse(lr, line); - return; - } - - // read leading garbage - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - if (line.length() < 4) - continue; // too short - - if (line.startsWith(PatchReader.MULTIPROJECTPATCH_PROJECT)) { - project= line.substring(2).trim(); - continue; - } - - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - continue; - } - if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - continue; - } - - if (line.startsWith("--- ")) { //$NON-NLS-1$ - // if there is no current project or - // the current project doesn't equal the newly parsed project - // reset the current project to the newly parsed one, create a new DiffProject - // and add it to the array - DiffProject diffProject; - if (!diffProjects.containsKey(project)) { - IProject iproject= ResourcesPlugin.getWorkspace().getRoot().getProject(project); - diffProject= new DiffProject(iproject); - diffProjects.put(project, diffProject); - } else { - diffProject= (DiffProject) diffProjects.get(project); - } - - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName, diffProject); - diffArgs= fileName= null; - reread= true; - } - } - - lr.close(); - - fDiffProjects= (DiffProject[]) diffProjects.values().toArray(new DiffProject[diffProjects.size()]); - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private String readUnifiedDiff(List diffs, LineReader lr, String line, String diffArgs, String fileName, DiffProject diffProject) throws IOException { - List newDiffs= new ArrayList(); - String nextLine= readUnifiedDiff(newDiffs, lr, line, diffArgs, fileName); - for (Iterator iter= newDiffs.iterator(); iter.hasNext();) { - FileDiff diff= (FileDiff) iter.next(); - diffProject.add(diff); - diffs.add(diff); - } - return nextLine; - } - - public void parse(LineReader lr, String line) throws IOException { - List diffs= new ArrayList(); - boolean reread= false; - String diffArgs= null; - String fileName= null; - List headerLines = new ArrayList(); - - // read leading garbage - reread= line!=null; - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - - // remember some infos - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - } else if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - } else if (line.startsWith("--- ")) { //$NON-NLS-1$ - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } else if (line.startsWith("*** ")) { //$NON-NLS-1$ - line= readContextDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } - - // Any lines we read here are header lines. - // However, if reread is set, we will add them to the header on the next pass through - if (!reread) { - headerLines.add(line); - } - } - - lr.close(); - - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private void setHeader(FileDiff diff, List headerLines) { - String header = Patcher.createString(false, headerLines); - diff.setHeader(header); - headerLines.clear(); - } - - /* - * Returns the next line that does not belong to this diff - */ - protected String readUnifiedDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("+++ ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List lines= new ArrayList(); - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return null; - - if (reader.lineContentLength(line) == 0) { - //System.out.println("Warning: found empty line in hunk; ignored"); - //lines.add(' ' + line); - continue; - } - - char c= line.charAt(0); - switch (c) { - case '@': - if (line.startsWith("@@ ")) { //$NON-NLS-1$ - // flush old hunk - if (lines.size() > 0) { - new Hunk(diff, oldRange, newRange, lines,encounteredPlus, encounteredMinus, encounteredSpace); - lines.clear(); - } - - // format: @@ -oldStart,oldLength +newStart,newLength @@ - extractPair(line, '-', oldRange); - extractPair(line, '+', newRange); - continue; - } - break; - case ' ': - encounteredSpace = true; - lines.add(line); - continue; - case '+': - encounteredPlus = true; - lines.add(line); - continue; - case '-': - encounteredMinus = true; - lines.add(line); - continue; - case '\\': - if (line.indexOf("newline at end") > 0) { //$NON-NLS-1$ - int lastIndex= lines.size(); - if (lastIndex > 0) { - line= (String) lines.get(lastIndex-1); - int end= line.length()-1; - char lc= line.charAt(end); - if (lc == '\n') { - end--; - if (end > 0 && line.charAt(end) == '\r') - end--; - } else if (lc == '\r') { - end--; - } - line= line.substring(0, end+1); - lines.set(lastIndex-1, line); - } - continue; - } - break; - default: - if (DEBUG) { - int a1= c, a2= 0; - if (line.length() > 1) - a2= line.charAt(1); - System.out.println("char: " + a1 + " " + a2); //$NON-NLS-1$ //$NON-NLS-2$ - } - break; - } - return line; - } - } finally { - if (lines.size() > 0) - new Hunk(diff, oldRange, newRange, lines, encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Returns the next line that does not belong to this diff - */ - private String readContextDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("--- ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List oldLines= new ArrayList(); - List newLines= new ArrayList(); - List lines= oldLines; - - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return line; - - int l= line.length(); - if (l == 0) - continue; - if (l > 1) { - switch (line.charAt(0)) { - case '*': - if (line.startsWith("***************")) { // new hunk //$NON-NLS-1$ - // flush old hunk - if (oldLines.size() > 0 || newLines.size() > 0) { - new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - oldLines.clear(); - newLines.clear(); - } - continue; - } - if (line.startsWith("*** ")) { // old range //$NON-NLS-1$ - // format: *** oldStart,oldEnd *** - extractPair(line, ' ', oldRange); - oldRange[1]= oldRange[1]-oldRange[0]+1; - lines= oldLines; - continue; - } - break; - case ' ': // context line - if (line.charAt(1) == ' ') { - lines.add(line); - continue; - } - break; - case '+': // addition - if (line.charAt(1) == ' ') { - encounteredPlus = true; - lines.add(line); - continue; - } - break; - case '!': // change - if (line.charAt(1) == ' ') { - encounteredSpace = true; - lines.add(line); - continue; - } - break; - case '-': - if (line.charAt(1) == ' ') { // deletion - encounteredMinus = true; - lines.add(line); - continue; - } - if (line.startsWith("--- ")) { // new range //$NON-NLS-1$ - // format: *** newStart,newEnd *** - extractPair(line, ' ', newRange); - newRange[1]= newRange[1]-newRange[0]+1; - lines= newLines; - continue; - } - break; - default: - break; - } - } - return line; - } - } finally { - // flush last hunk - if (oldLines.size() > 0 || newLines.size() > 0) - new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Creates a List of lines in the unified format from - * two Lists of lines in the 'classic' format. - */ - private List unifyLines(List oldLines, List newLines) { - List result= new ArrayList(); - - String[] ol= (String[]) oldLines.toArray(new String[oldLines.size()]); - String[] nl= (String[]) newLines.toArray(new String[newLines.size()]); - - int oi= 0, ni= 0; - - while (true) { - - char oc= 0; - String o= null; - if (oi < ol.length) { - o= ol[oi]; - oc= o.charAt(0); - } - - char nc= 0; - String n= null; - if (ni < nl.length) { - n= nl[ni]; - nc= n.charAt(0); - } - - // EOF - if (oc == 0 && nc == 0) - break; - - // deletion in old - if (oc == '-') { - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '-'); - continue; - } - - // addition in new - if (nc == '+') { - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '+'); - continue; - } - - // differing lines on both sides - if (oc == '!' && nc == '!') { - // remove old - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '!'); - - // add new - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '!'); - - continue; - } - - // context lines - if (oc == ' ' && nc == ' ') { - do { - Assert.isTrue(o.equals(n), "non matching context lines"); //$NON-NLS-1$ - result.add(' ' + o.substring(2)); - oi++; - ni++; - if (oi >= ol.length || ni >= nl.length) - break; - o= ol[oi]; - n= nl[ni]; - } while (o.charAt(0) == ' ' && n.charAt(0) == ' '); - continue; - } - - if (oc == ' ') { - do { - result.add(' ' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == ' '); - continue; - } - - if (nc == ' ') { - do { - result.add(' ' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == ' '); - continue; - } - - Assert.isTrue(false, "unexpected char <" + oc + "> <" + nc + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - return result; - } - - /* - * @return the parsed time/date in milliseconds or IFilePatch.DATE_UNKNOWN - * (0) on error - */ - private long extractDate(String[] args, int n) { - if (n < args.length) { - String line= args[n]; - for (int i= 0; i < fDateFormats.length; i++) { - fDateFormats[i].setLenient(true); - try { - Date date= fDateFormats[i].parse(line); - return date.getTime(); - } catch (ParseException ex) { - // silently ignored - } - } - // System.err.println("can't parse date: <" + line + ">"); - } - return IFilePatch.DATE_UNKNOWN; - } - - /* - * Returns null if file name is "/dev/null". - */ - private IPath extractPath(String[] args, int n, String path2) { - if (n < args.length) { - String path= args[n]; - if (DEV_NULL.equals(path)) - return null; - int pos= path.lastIndexOf(':'); - if (pos >= 0) - path= path.substring(0, pos); - if (path2 != null && !path2.equals(path)) { - if (DEBUG) System.out.println("path mismatch: " + path2); //$NON-NLS-1$ - path= path2; - } - return new Path(path); - } - return null; - } - - /* - * Tries to extract two integers separated by a comma. - * The parsing of the line starts at the position after - * the first occurrence of the given character start an ends - * at the first blank (or the end of the line). - * If only a single number is found this is assumed to be the start of a one line range. - * If an error occurs the range -1,-1 is returned. - */ - private void extractPair(String line, char start, int[] pair) { - pair[0]= pair[1]= -1; - int startPos= line.indexOf(start); - if (startPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find \'" + start + "\'"); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - line= line.substring(startPos+1); - int endPos= line.indexOf(' '); - if (endPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find end blank"); //$NON-NLS-1$ - return; - } - line= line.substring(0, endPos); - int comma= line.indexOf(','); - if (comma >= 0) { - pair[0]= Integer.parseInt(line.substring(0, comma)); - pair[1]= Integer.parseInt(line.substring(comma+1)); - } else { // abbreviated form for one line patch - pair[0]= Integer.parseInt(line); - pair[1]= 1; - } - } - - - /* - * Breaks the given string into tab separated substrings. - * Leading and trailing whitespace is removed from each token. - */ - private String[] split(String line) { - List l= new ArrayList(); - StringTokenizer st= new StringTokenizer(line, "\t"); //$NON-NLS-1$ - while (st.hasMoreElements()) { - String token= st.nextToken().trim(); - if (token.length() > 0) - l.add(token); - } - return (String[]) l.toArray(new String[l.size()]); - } - - public boolean isWorkspacePatch() { - return fIsWorkspacePatch; - } - - public DiffProject[] getDiffProjects() { - return fDiffProjects; - } - - public FileDiff[] getDiffs() { - return fDiffs; - } - - public FileDiff[] getAdjustedDiffs() { - if (!isWorkspacePatch() || fDiffs.length == 0) - return fDiffs; - List result = new ArrayList(); - for (int i = 0; i < fDiffs.length; i++) { - FileDiff diff = fDiffs[i]; - result.add(diff.asRelativeDiff()); - } - return (FileDiff[]) result.toArray(new FileDiff[result.size()]); - } - -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java index 2ff465773..4ddf19677 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java @@ -16,6 +16,7 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ExceptionHandler; +import org.eclipse.compare.internal.Utilities; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.ISchedulingRule; @@ -150,7 +151,11 @@ public class PatchWizard extends Wizard { WorkspaceModifyOperation op = new WorkspaceModifyOperation(scheduleRule) { protected void execute(IProgressMonitor monitor) throws InvocationTargetException { try { - fPatcher.applyAll(monitor, getShell(), PatchMessages.PatchWizard_title); + fPatcher.applyAll(monitor, new Patcher.IFileValidator() { + public boolean validateResources(IFile[] resoures) { + return Utilities.validateResources(resoures, getShell(), PatchMessages.PatchWizard_title); + } + }); } catch (CoreException e) { throw new InvocationTargetException(e); } diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java index 9b8bea9b3..1590dc864 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java @@ -16,7 +16,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.Reader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; @@ -27,12 +26,17 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.compare.internal.Utilities; +import org.eclipse.compare.internal.core.Messages; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.Hunk; +import org.eclipse.compare.internal.core.patch.IHunkFilter; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.compare.internal.core.patch.PatchReader; +import org.eclipse.compare.internal.core.patch.Utilities; import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IEncodedStorage; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; @@ -46,8 +50,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Shell; /** * A Patcher @@ -55,7 +57,7 @@ import org.eclipse.swt.widgets.Shell; * - holds onto the parsed data and the options to use when applying the patches, * - knows how to apply the patches to files and folders. */ -public class Patcher { +public class Patcher implements IHunkFilter { static protected final String REJECT_FILE_EXTENSION= ".rej"; //$NON-NLS-1$ @@ -65,6 +67,10 @@ public class Patcher { * Property used to associate a patcher with a {@link PatchConfiguration} */ public static final String PROP_PATCHER = "org.eclipse.compare.patcher"; //$NON-NLS-1$ + + public interface IFileValidator { + boolean validateResources(IFile[] array); + } // diff formats // private static final int CONTEXT= 0; @@ -86,6 +92,7 @@ public class Patcher { public Patcher() { configuration = new PatchConfiguration(); configuration.setProperty(PROP_PATCHER, this); + configuration.setProperty(IHunkFilter.HUNK_FILTER_PROPERTY, this); } /* @@ -105,7 +112,7 @@ public class Patcher { /* * Returns true if new value differs from old. */ - boolean setStripPrefixSegments(int strip) { + public boolean setStripPrefixSegments(int strip) { if (strip != getConfiguration().getPrefixSegmentStripCount()) { getConfiguration().setPrefixSegmentStripCount(strip); return true; @@ -120,7 +127,7 @@ public class Patcher { /* * Returns true if new value differs from old. */ - boolean setFuzz(int fuzz) { + public boolean setFuzz(int fuzz) { if (fuzz != getConfiguration().getFuzz()) { getConfiguration().setFuzz(fuzz); return true; @@ -128,14 +135,14 @@ public class Patcher { return false; } - int getFuzz(){ + public int getFuzz(){ return getConfiguration().getFuzz(); } /* * Returns true if new value differs from old. */ - boolean setIgnoreWhitespace(boolean ignoreWhitespace) { + public boolean setIgnoreWhitespace(boolean ignoreWhitespace) { if (ignoreWhitespace != getConfiguration().isIgnoreWhitespace()) { getConfiguration().setIgnoreWhitespace(ignoreWhitespace); return true; @@ -143,7 +150,7 @@ public class Patcher { return false; } - boolean isIgnoreWhitespace() { + public boolean isIgnoreWhitespace() { return getConfiguration().isIgnoreWhitespace(); } @@ -158,7 +165,7 @@ public class Patcher { //---- parsing patch files public void parse(IStorage storage) throws IOException, CoreException { - BufferedReader reader = createReader(storage); + BufferedReader reader = LineReader.createReader(storage); try { parse(reader); } finally { @@ -169,32 +176,6 @@ public class Patcher { } } - public static BufferedReader createReader(IStorage storage) throws CoreException { - String charset = null; - if (storage instanceof IEncodedStorage) { - IEncodedStorage es = (IEncodedStorage) storage; - charset = es.getCharset(); - } - InputStreamReader in = null; - if (charset != null) { - InputStream contents = storage.getContents(); - try { - in = new InputStreamReader(contents, charset); - } catch (UnsupportedEncodingException e) { - CompareUIPlugin.log(e); - try { - contents.close(); - } catch (IOException e1) { - // Ignore - } - } - } - if (in == null) { - in = new InputStreamReader(storage.getContents()); - } - return new BufferedReader(in); - } - public void parse(BufferedReader reader) throws IOException { PatchReader patchReader= new PatchReader(); patchReader.parse(reader); @@ -233,9 +214,7 @@ public class Patcher { //---- applying a patch file - public void applyAll(IProgressMonitor pm, Shell shell, String title) throws CoreException { - - final int WORK_UNIT= 10; + public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { int i; @@ -259,18 +238,20 @@ public class Patcher { FileDiff diff= fDiffs[i]; if (isEnabled(diff)) { switch (diff.getDiffType(isReversed())) { - case Differencer.CHANGE: + case FileDiff.CHANGE: list.add(createPath(container, getPath(diff))); break; } } } } - if (! Utilities.validateResources(list, shell, title)) + if (! validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { return; + } + final int WORK_UNIT= 10; if (pm != null) { - String message= PatchMessages.Patcher_Task_message; + String message= Messages.Patcher_0; pm.beginTask(message, fDiffs.length*WORK_UNIT); } @@ -293,22 +274,22 @@ public class Patcher { int type= diff.getDiffType(isReversed()); switch (type) { - case Differencer.ADDITION: + case FileDiff.ADDITION: // patch it and collect rejected hunks List result= apply(diff, file, true, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; - case Differencer.DELETION: + case FileDiff.DELETION: file.delete(true, true, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; - case Differencer.CHANGE: + case FileDiff.CHANGE: // patch it and collect rejected hunks result= apply(diff, file, false, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; } @@ -320,7 +301,7 @@ public class Patcher { store(getRejected(failed), file, pm); try { IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message); + marker.setAttribute(IMarker.MESSAGE, Messages.Patcher_1); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException ex) { // NeedWork @@ -348,66 +329,9 @@ public class Patcher { return pp; } - /* - * Reads the contents from the given file and returns them as - * a List of lines. - */ - public static List load(IStorage file, boolean create) { - List lines= null; - if (!create && file != null && exists(file)) { - // read current contents - String charset = Utilities.getCharset(file); - InputStream is= null; - try { - is= file.getContents(); - - Reader streamReader= null; - try { - streamReader= new InputStreamReader(is, charset); - } catch (UnsupportedEncodingException x) { - // use default encoding - streamReader= new InputStreamReader(is); - } - - BufferedReader reader= new BufferedReader(streamReader); - lines = readLines(reader); - } catch(CoreException ex) { - // TODO - CompareUIPlugin.log(ex); - } finally { - if (is != null) - try { - is.close(); - } catch(IOException ex) { - // silently ignored - } - } - } - - if (lines == null) - lines= new ArrayList(); - return lines; - } - - private static boolean exists(IStorage file) { - if (file instanceof IFile) { - return ((IFile) file).exists(); - } - return true; - } - - private static List readLines(BufferedReader reader) { - List lines; - LineReader lr= new LineReader(reader); - if (!"carbon".equals(SWT.getPlatform())) //$NON-NLS-1$ - lr.ignoreSingleCR(); - lines= lr.readLines(); - return lines; - } - List apply(FileDiff diff, IFile file, boolean create, List failedHunks) { FileDiffResult result = getDiffResult(diff); - List lines = Patcher.load(file, create); + List lines = LineReader.load(file, create); result.patch(lines, null); failedHunks.addAll(result.getFailedHunks()); if (hasCachedContents(diff)) { @@ -454,34 +378,7 @@ public class Patcher { } } - - - /* - * Concatenates all strings found in the given List. - */ - public static String createString(boolean preserveLineDelimeters, List lines) { - StringBuffer sb= new StringBuffer(); - Iterator iter= lines.iterator(); - if (preserveLineDelimeters) { - while (iter.hasNext()) - sb.append((String)iter.next()); - } else { - String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ - while (iter.hasNext()) { - String line= (String)iter.next(); - int l= length(line); - if (l < line.length()) { // line has delimiter - sb.append(line.substring(0, l)); - sb.append(lineSeparator); - } else { - sb.append(line); - } - } - } - return sb.toString(); - } - - protected boolean isPreserveLineDelimeters() { + public boolean isPreserveLineDelimeters() { return false; } @@ -526,25 +423,6 @@ public class Patcher { // a leaf return container.getFile(path); } - - /* - * Returns the length (excluding a line delimiter CR, LF, CR/LF) - * of the given string. - */ - /* package */ static int length(String s) { - int l= s.length(); - if (l > 0) { - char c= s.charAt(l-1); - if (c == '\r') - return l-1; - if (c == '\n') { - if (l > 1 && s.charAt(l-2) == '\r') - return l-2; - return l-1; - } - } - return l; - } public IResource getTarget() { return fTarget; @@ -555,7 +433,7 @@ public class Patcher { } - protected IFile getTargetFile(FileDiff diff) { + public IFile getTargetFile(FileDiff diff) { IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); return existsInTarget(path); } @@ -692,7 +570,7 @@ public class Patcher { */ public int guessFuzzFactor(IProgressMonitor monitor) { try { - monitor.beginTask(PatchMessages.PreviewPatchPage_GuessFuzzProgress_text, IProgressMonitor.UNKNOWN); + monitor.beginTask(Messages.Patcher_2, IProgressMonitor.UNKNOWN); FileDiff[] diffs= getDiffs(); if (diffs==null||diffs.length<=0) return -1; @@ -701,7 +579,7 @@ public class Patcher { FileDiff d= diffs[i]; IFile file= getTargetFile(d); if (file != null && file.exists()) { - List lines= load(file, false); + List lines= LineReader.load(file, false); FileDiffResult result = getDiffResult(d); int f = result.calculateFuzz(lines, monitor); if (f > fuzz) @@ -799,7 +677,7 @@ public class Patcher { byte[] contents = (byte[])contentCache.get(diff); if (contents != null) { BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contents))); - return readLines(reader); + return LineReader.readLines(reader); } return null; } @@ -874,4 +752,8 @@ public class Patcher { } return false; } + + public boolean select(Hunk hunk) { + return isEnabled(hunk); + } } diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java index f68bca774..71a0a2bfc 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java @@ -19,6 +19,8 @@ import org.eclipse.compare.CompareUI; import org.eclipse.compare.internal.ComparePreferencePage; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ICompareUIConstants; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java index 0dde4ce09..8ec175c90 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java @@ -12,6 +12,9 @@ package org.eclipse.compare.internal.patch; import java.util.ArrayList; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.Dialog; diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java index 1cd0a18ca..1588fb9b3 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java @@ -10,12 +10,20 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.List; -import org.eclipse.compare.*; +import org.eclipse.compare.IContentChangeListener; +import org.eclipse.compare.IContentChangeNotifier; +import org.eclipse.compare.IEditableContent; +import org.eclipse.compare.ITypedElement; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ContentChangeNotifier; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.HunkResult; +import org.eclipse.compare.internal.core.patch.LineReader; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; @@ -89,7 +97,7 @@ public class UnmatchedHunkTypedElement extends HunkTypedElement implements ICont return new ByteArrayInputStream(getPatcher().getCachedContents(getDiff())); // Otherwise return the after state of the diff result List lines = getHunkResult().getDiffResult().getAfterLines(); - String content = Patcher.createString(getHunkResult().getDiffResult().isPreserveLineDelimeters(), lines); + String content = LineReader.createString(getHunkResult().getDiffResult().isPreserveLineDelimeters(), lines); byte[] bytes = null; if (getCharset() != null) try { diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java index 6a334213c..dd816ae61 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java @@ -12,8 +12,13 @@ package org.eclipse.compare.internal.patch; import java.util.List; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.LineReader; import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.*; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IStorage; public class WorkspaceFileDiffResult extends FileDiffResult { @@ -34,7 +39,7 @@ public class WorkspaceFileDiffResult extends FileDiffResult { protected List getLines(IStorage storage, boolean create) { IFile file= getTargetFile(); - List lines = Patcher.load(file, create); + List lines = LineReader.load(file, create); return lines; } @@ -42,7 +47,7 @@ public class WorkspaceFileDiffResult extends FileDiffResult { return Patcher.getPatcher(getConfiguration()); } - protected IFile getTargetFile() { + public IFile getTargetFile() { return getPatcher().getTargetFile(getDiff()); } diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java index 2ba0e76ec..84ff8deb4 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java @@ -10,15 +10,32 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.compare.internal.core.Messages; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.compare.internal.core.patch.PatchReader; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceRuleFactory; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.MultiRule; -import org.eclipse.swt.widgets.Shell; /** * A Patcher @@ -50,15 +67,15 @@ public class WorkspacePatcher extends Patcher { return fDiffProjects; } - boolean isWorkspacePatch() { + public boolean isWorkspacePatch() { return fIsWorkspacePatch; } //---- parsing patch files - public void applyAll(IProgressMonitor pm, Shell shell, String title) throws CoreException { + public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { if (!fIsWorkspacePatch) { - super.applyAll(pm, shell, title); + super.applyAll(pm, validator); } else { final int WORK_UNIT= 10; @@ -70,12 +87,13 @@ public class WorkspacePatcher extends Patcher { list.addAll(Arrays.asList(getTargetFiles(diffProject))); } // validate the files for editing - if (!Utilities.validateResources(list, shell, title)) + if (!validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { return; + } FileDiff[] diffs = getDiffs(); if (pm != null) { - String message= PatchMessages.Patcher_Task_message; + String message= Messages.WorkspacePatcher_0; pm.beginTask(message, diffs.length * WORK_UNIT); } @@ -95,22 +113,22 @@ public class WorkspacePatcher extends Patcher { int type= diff.getDiffType(isReversed()); switch (type) { - case Differencer.ADDITION : + case FileDiff.ADDITION : // patch it and collect rejected hunks List result= apply(diff, file, true, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; - case Differencer.DELETION : + case FileDiff.DELETION : file.delete(true, true, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; - case Differencer.CHANGE : + case FileDiff.CHANGE : // patch it and collect rejected hunks result= apply(diff, file, false, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; } @@ -127,7 +145,7 @@ public class WorkspacePatcher extends Patcher { store(getRejected(failed), file, pm); try { IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message); + marker.setAttribute(IMarker.MESSAGE, Messages.WorkspacePatcher_1); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException ex) { // NeedWork @@ -168,7 +186,7 @@ public class WorkspacePatcher extends Patcher { return (IFile[]) files.toArray(new IFile[files.size()]); } - protected IFile getTargetFile(FileDiff diff) { + public IFile getTargetFile(FileDiff diff) { IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); DiffProject project = getProject(diff); if (project != null) @@ -354,7 +372,7 @@ public class WorkspacePatcher extends Patcher { return null; } - int getStripPrefixSegments() { + public int getStripPrefixSegments() { // Segments are never stripped from a workspace patch if (isWorkspacePatch()) return 0; diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java index 1e83ca4aa..13447df03 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java @@ -10,14 +10,16 @@ *******************************************************************************/ package org.eclipse.compare.patch; -import java.io.BufferedReader; -import java.io.IOException; - import org.eclipse.compare.CompareConfiguration; -import org.eclipse.compare.internal.*; -import org.eclipse.compare.internal.patch.*; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.compare.internal.ComparePreferencePage; +import org.eclipse.compare.internal.CompareUIPlugin; +import org.eclipse.compare.internal.patch.PatchWizard; +import org.eclipse.compare.internal.patch.PatchWizardDialog; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPart; @@ -74,7 +76,7 @@ public class ApplyPatchOperation implements Runnable { * @throws CoreException if an error occurs reading the contents from the storage */ public static boolean isPatch(IStorage storage) throws CoreException { - return parsePatch(storage).length > 0; + return PatchParser.parsePatch(storage).length > 0; } /** @@ -84,19 +86,7 @@ public class ApplyPatchOperation implements Runnable { * @throws CoreException if an error occurs reading the contents from the storage */ public static IFilePatch[] parsePatch(IStorage storage) throws CoreException { - BufferedReader reader = Patcher.createReader(storage); - try { - PatchReader patchReader= new PatchReader(); - patchReader.parse(reader); - return patchReader.getAdjustedDiffs(); - } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, e.getMessage(), e)); - } finally { - try { - reader.close(); - } catch (IOException e) { //ignored - } - } + return PatchParser.parsePatch(storage); } /** diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java deleted file mode 100644 index 21646d916..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; - -/** - * A representation of a file patch that can be applied to an input stream. - *

- * This interface is not intended to be implemented by clients. Clients can - * obtain file patches by calling - * {@link ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage)}. - *

- * - * @see ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage) - * @since 3.3 - * @noimplement - */ -public interface IFilePatch { - - /** - * Special constant that will be returned from get getBeforeDate() or - * getAfterDate() if the date is unknown. Equal to Midnight, Jan 1, 1970 - * GMT. - * - * @since 3.4 - */ - public static long DATE_UNKNOWN = 0; - - /** - * Return the target path for this patch. The target path may differ - * depending on whether the patch is being reversed or not. - * - * @param configuration the patch configuration - * @return the target path for this patch - * @see PatchConfiguration#isReversed() - */ - public IPath getTargetPath(PatchConfiguration configuration); - - /** - * Apply this patch to the given file contents. The result provides the - * original and patch contents and also indicates whether some portions of - * the patch (called hunks) failed to apply. - * - * @param contents the file contents - * @param configuration the patch configuration - * @param monitor a progress monitor - * @return the result of the patch application - */ - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor); - - /** - * Return the header information of the patch or - * null if there was no header text. - * The header may be multi-line. - * @return the header information of the patch or - * null - */ - public String getHeader(); - - /** - * Returns the milliseconds time value of the before date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the before date from the patch - * @since 3.4 - */ - public long getBeforeDate(); - - /** - * Returns the milliseconds time value of the after date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the after date from the patch - * @since 3.4 - */ - public long getAfterDate(); -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java deleted file mode 100644 index 4f229c3aa..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.io.InputStream; - -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.runtime.CoreException; - -/** - * A file patch result provides the results of an attempt to apply an - * {@link IFilePatch} to the contents of a file. * - *

- * This interface is not intended to be implemented by clients. Clients can - * obtain patch results from an {@link IFilePatch}. - *

- * - * @see IFilePatch - * @since 3.3 - */ -public interface IFilePatchResult { - - /** - * Return a stream the contains the original contents of the file before - * any portions of the patch have been applied. - * @return a stream to the original contents of the file before - * any portions of the patch have been applied - * @see #getPatchedContents() - */ - public InputStream getOriginalContents(); - - /** - * Return a stream that contains the file with as much of the patch - * applied as possible. if {@link #hasMatches()} returns false - * then the patched contents will match the original contents. Otherwise, - * at least a portion of the patch could be successfully applied. if - * {@link #hasRejects()} returns false, then the entire patch was - * applied. Otherwise, portions could not be applied. The portions that could - * not be applied can be obtained by calling {@link #getRejects()}. - * - * @return a stream that contains the file with as much of the patch - * applied as possible. - */ - public InputStream getPatchedContents(); - - /** - * Return whether the patch has portions that were successfully applied. - * @return whether the patch has portions that were successfully applied - * @see #getPatchedContents() - */ - public boolean hasMatches(); - - /** - * Return whether the patch has portions that were not successfully applied. - * @return whether the patch has portions that were not successfully applied - * @see #getPatchedContents() - */ - public boolean hasRejects(); - - /** - * Return the portions of the patch (referred to a hunks) that could not - * be applied. - * @return the portions of the patch (referred to a hunks) that could not - * be applied - * @see #getPatchedContents() - */ - public IHunk[] getRejects(); - - /** - * Returns the name of a charset encoding to be used when decoding the contents - * of this result into characters. Returns null if a proper - * encoding cannot be determined. - *

- * Note that this method does not check whether the result is a supported - * charset name. Callers should be prepared to handle - * UnsupportedEncodingException where this charset is used. - *

- * - * @return the name of a charset, or null - * @exception CoreException if an error happens while determining - * the charset. See any refinements for more information. - * @see IEncodedStorage - */ - public String getCharset() throws CoreException; - -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java deleted file mode 100644 index 126150c0d..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.io.InputStream; - -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; - -/** - * Interface that represents a hunk. A hunk is a portion of a patch. It - * identifies where the hunk is to be located in the target file. One use of - * this interface is a means to communicate to content merge viewers that one of - * the sides of a compare input is a patch hunk. Clients can determine which - * side it is by adapting the side to this interface (see {@link IAdaptable}. - *

- * This interface is not intended to be implemented by clients but can be - * obtained from an {@link IFilePatchResult} - *

- * - * @since 3.3 - * - */ -public interface IHunk { - - /** - * Return a label that can be used to describe the hunk. - * @return a label that can be used to describe the hunk - */ - public String getLabel(); - - /** - * Return the start position of the hunk in the target file. - * - * @return the start position of the hunk in the target file. - */ - public int getStartPosition(); - - /** - * Return the original contents from which the hunk was generated. - * The returned contents usually only represent a portion of the - * file from which the hunk was generated. - * @return the original contents from which the hunk was generated - */ - public InputStream getOriginalContents(); - - /** - * Return the contents that contain the modifications for this hunk. - * The returned contents usually only represent a portion of the - * file that was modified. - * @return the contents that contain the modifications for this hunk - */ - public InputStream getPatchedContents(); - - /** - * Returns the name of a charset encoding to be used when decoding the contents - * of this hunk into characters. Returns null if a proper - * encoding cannot be determined. - *

- * Note that this method does not check whether the result is a supported - * charset name. Callers should be prepared to handle - * UnsupportedEncodingException where this charset is used. - *

- * - * @return the name of a charset, or null - * @exception CoreException if an error happens while determining - * the charset. See any refinements for more information. - * @see IEncodedStorage - */ - public String getCharset() throws CoreException; - - -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java deleted file mode 100644 index 3287a4585..000000000 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.util.HashMap; - -/** - * A patch configuration allows clients to set parameters that control how a patch - * is applied. - *

- * This class may be instantiated by clients but is not intended to be subclassed. - *

- * @see IFilePatch - * @since 3.3 - */ -public class PatchConfiguration { - - private int fStripPrefixSegments; - private int fFuzz; - private boolean fIgnoreWhitespace= false; - private boolean fReverse= false; - private HashMap properties = new HashMap(); - - /** - * Return whether the patch should be reversed when applied. - * @return whether the patch should be reversed when applied - */ - public boolean isReversed() { - return fReverse; - } - - /** - * Set whether the patch should be reversed when applied. - * @param reversed whether the patch should be reversed when applied - */ - public void setReversed(boolean reversed) { - this.fReverse = reversed; - } - - /** - * Return the number of prefix segments to be stripped when attempting - * to apply a patch. - * @return the number of prefix segments to be stripped when attempting - * to apply a patch - */ - public int getPrefixSegmentStripCount() { - return fStripPrefixSegments; - } - - /** - * Set the number of prefix segments to be stripped when attempting - * to apply a patch. - * @param stripCount the number of prefix segments to be stripped when attempting - * to apply a patch. - */ - public void setPrefixSegmentStripCount(int stripCount) { - this.fStripPrefixSegments = stripCount; - } - - /** - * Return the fuzz factor to be used when applying a patch. - * If the fuzz factor is set to -1, then the patcher is to make a best - * effort to apply the patch by adjusting the fuzz factor - * accordingly. - * @return the fuzz factor to be used when applying a patch. - */ - public int getFuzz() { - return fFuzz; - } - - /** - * Set the fuzz factor to be used when applying a patch. - * @param fuzz the fuzz factor to be used when applying a patch. - */ - public void setFuzz(int fuzz) { - fFuzz = fuzz; - } - - /** - * Return whether whitespace should be ignored. - * @return whether whitespace should be ignored - */ - public boolean isIgnoreWhitespace() { - return fIgnoreWhitespace; - } - - /** - * Set whether whitespace should be ignored - * @param ignoreWhitespace whether whitespace should be ignored - */ - public void setIgnoreWhitespace(boolean ignoreWhitespace) { - fIgnoreWhitespace = ignoreWhitespace; - } - - /** - * Return the property associated with the given key or - * null if there is no property for the key. - * @param key the key - * @return the property associated with the given key or - * null - */ - public Object getProperty(String key) { - return properties.get(key); - } - - /** - * Set the property associated with the given key - * @param key the key - * @param value the value to be associated with the key - */ - public void setProperty(String key, Object value) { - properties.put(key, value); - } -} diff --git a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java index 7f44392e0..d19688b08 100644 --- a/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java +++ b/bundles/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.compare.patch; -import org.eclipse.compare.internal.patch.PatchReader; +import org.eclipse.compare.internal.core.patch.PatchReader; import org.eclipse.core.resources.IProject; /** diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/META-INF/MANIFEST.MF index b14b31f7f..b5afde739 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/META-INF/MANIFEST.MF @@ -10,7 +10,7 @@ Require-Bundle: org.eclipse.core.runtime, Bundle-RequiredExecutionEnvironment: J2SE-1.4 Eclipse-LazyStart: true Export-Package: org.eclipse.compare.internal.core, - org.eclipse.compare.internal.patch, + org.eclipse.compare.internal.core.patch, org.eclipse.compare.patch Import-Package: com.ibm.icu.text;version="3.6.1", com.ibm.icu.util;version="3.6.1" diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/DiffProject.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/DiffProject.java new file mode 100644 index 000000000..807c875da --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/DiffProject.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; + +/** + * A diff project represents a project that was read from a workspace patch. + * It contains the set of file diffs that were associated with the project + * in the patch file. + */ +public class DiffProject { + + private IProject fProject; + private Set fDiffs= new HashSet(); + + /** + * Create a diff project for the given workspace project. + * @param project a workspace project + */ + public DiffProject(IProject project) { + this.fProject= project; + } + + /** + * Add the file diff to this project. + * @param diff the file diff. + */ + public void add(FileDiff diff) { + fDiffs.add(diff); + if (diff.getProject() != this) + diff.setProject(this); + } + + + /** + * Return the workspace project associated with this diff project. + * @return the workspace project associated with this project + */ + public IProject getProject() { + return this.fProject; + } + + /** + * Return the name of this project. + * @return the name of this project + */ + public String getName() { + return fProject.getName(); + } + + /** + * Return the file at the given path relative to this project. + * @param path the relative path + * @return the file at the given path relative to this project + */ + public IFile getFile(IPath path) { + return fProject.getFile(path); + } + + /** + * Remove the file diff from this project. + * @param diff the diff to be removed + */ + public void remove(FileDiff diff) { + fDiffs.remove(diff); + } + + /** + * Return whether this project contains the given diff. + * @param diff a file diff + * @return whether this project contains the given diff + */ + public boolean contains(FileDiff diff) { + return fDiffs.contains(diff); + } + + /** + * Return the file diffs associated with this project. + * @return the file diffs associated with this project + */ + public FileDiff[] getFileDiffs() { + return (FileDiff[]) fDiffs.toArray(new FileDiff[fDiffs.size()]); + } +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiff.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiff.java new file mode 100644 index 000000000..1c7f5afd6 --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiff.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.compare.patch.IFilePatch; +import org.eclipse.compare.patch.IFilePatchResult; +import org.eclipse.compare.patch.PatchConfiguration; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; + +/** + * A file diff represents a set of hunks that were associated with the + * same path in a patch file. + */ +public class FileDiff implements IFilePatch { + + /** + * Difference constant (value 1) indicating one side was added. + */ + public static final int ADDITION= 1; + /** + * Difference constant (value 2) indicating one side was removed. + */ + public static final int DELETION= 2; + /** + * Difference constant (value 3) indicating side changed. + */ + public static final int CHANGE= 3; + + private IPath fOldPath, fNewPath; + private long oldDate, newDate; + private List fHunks= new ArrayList(); + private DiffProject fProject; //the project that contains this diff + private String header; + private int addedLines, removedLines; + + /** + * Create a file diff for the given path and date information. + * @param oldPath the path of the before state of the file + * @param oldDate the timestamp of the before state + * @param newPath the path of the after state + * @param newDate the timestamp of the after state + */ + public FileDiff(IPath oldPath, long oldDate, IPath newPath, long newDate) { + fOldPath= oldPath; + this.oldDate = oldDate; + fNewPath= newPath; + this.newDate = newDate; + } + + /** + * Return the parent project or null if there isn't one. + * @return the parent project or null + */ + public DiffProject getProject() { + return fProject; + } + + /** + * Set the project of this diff to the given project. + * This method should only be called from + * {@link DiffProject#add(FileDiff)} + * @param diffProject the parent project + */ + void setProject(DiffProject diffProject) { + if (fProject == diffProject) + return; + if (fProject != null) + fProject.remove(this); + this.fProject= diffProject; + } + + /** + * Get the path of the file diff. + * @param reverse whether the path of the before state or after state + * should be used + * @return the path of the file diff + */ + public IPath getPath(boolean reverse) { + if (getDiffType(reverse) == ADDITION) { + if (reverse) + return fOldPath; + return fNewPath; + } + if (reverse && fNewPath != null) + return fNewPath; + if (fOldPath != null) + return fOldPath; + return fNewPath; + } + + /** + * Add the hunk to this file diff. + * @param hunk the hunk + */ + public void add(Hunk hunk) { + fHunks.add(hunk); + hunk.setParent(this); + } + + /** + * Remove the hunk from this file diff + * @param hunk the hunk + */ + protected void remove(Hunk hunk) { + fHunks.remove(hunk); + } + + /** + * Return the hunks associated with this file diff. + * @return the hunks associated with this file diff + */ + public Hunk[] getHunks() { + return (Hunk[]) fHunks.toArray(new Hunk[fHunks.size()]); + } + + /** + * Return the number of hunks associated with this file diff. + * @return the number of hunks associated with this file diff + */ + public int getHunkCount() { + return fHunks.size(); + } + + /** + * Return the difference type of this file diff. + * @param reverse whether the patch is being reversed + * @return the type of this file diff + */ + public int getDiffType(boolean reverse) { + if (fHunks.size() == 1) { + boolean add = false; + boolean delete = false; + Iterator iter = fHunks.iterator(); + while (iter.hasNext()){ + Hunk hunk = (Hunk) iter.next(); + int type =hunk.getHunkType(reverse); + if (type == ADDITION){ + add = true; + } else if (type == DELETION ){ + delete = true; + } + } + if (add && !delete){ + return ADDITION; + } else if (!add && delete){ + return DELETION; + } + } + return CHANGE; + } + + /** + * Return the path of this file diff with the specified number + * of leading segments striped. + * @param strip the number of leading segments to strip from the path + * @param reverse whether the patch is being reversed + * @return the path of this file diff with the specified number + * of leading segments striped + */ + public IPath getStrippedPath(int strip, boolean reverse) { + IPath path= getPath(reverse); + if (strip > 0 && strip < path.segmentCount()) + path= path.removeFirstSegments(strip); + return path; + } + + /** + * Return the segment count of the path of this file diff. + * @return the segment count of the path of this file diff + */ + public int segmentCount() { + //Update prefix count - go through all of the diffs and find the smallest + //path segment contained in all diffs. + int length= 99; + if (fOldPath != null) + length= Math.min(length, fOldPath.segmentCount()); + if (fNewPath != null) + length= Math.min(length, fNewPath.segmentCount()); + return length; + } + + public IFilePatchResult apply(IStorage contents, + PatchConfiguration configuration, IProgressMonitor monitor) { + FileDiffResult result = new FileDiffResult(this, configuration); + result.refresh(contents, monitor); + return result; + } + + public IPath getTargetPath(PatchConfiguration configuration) { + return getStrippedPath(configuration.getPrefixSegmentStripCount(), configuration.isReversed()); + } + + public FileDiff asRelativeDiff() { + if (fProject == null) + return this; + IPath adjustedOldPath = null; + if (fOldPath != null) { + adjustedOldPath = new Path(null, fProject.getName()).append(fOldPath); + } + IPath adjustedNewPath = null; + if (fNewPath != null) { + adjustedNewPath = new Path(null, fProject.getName()).append(fNewPath); + } + FileDiff diff = new FileDiff(adjustedOldPath, 0, adjustedNewPath, 0); + for (Iterator iterator = fHunks.iterator(); iterator.hasNext();) { + Hunk hunk = (Hunk) iterator.next(); + // Creating the hunk adds it to the parent diff + new Hunk(diff, hunk); + } + return diff; + } + + public void setHeader(String header) { + this.header = header; + } + + public String getHeader() { + return header; + } + + public long getBeforeDate() { + return oldDate; + } + + public long getAfterDate() { + return newDate; + } + + public void setAddedLines(int addedLines) { + this.addedLines = addedLines; + } + + public void setRemovedLines(int removedLines) { + this.removedLines = removedLines; + } + + public int getAddedLines() { + return addedLines; + } + + public int getRemovedLines() { + return removedLines; + } + +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiffResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiffResult.java new file mode 100644 index 000000000..e3a9ad164 --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/FileDiffResult.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * Copyright (c) 2006, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.compare.internal.core.Activator; +import org.eclipse.compare.internal.core.Messages; +import org.eclipse.compare.patch.IFilePatchResult; +import org.eclipse.compare.patch.IHunk; +import org.eclipse.compare.patch.PatchConfiguration; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.osgi.util.NLS; + +public class FileDiffResult implements IFilePatchResult { + + private FileDiff fDiff; + private boolean fMatches= false; + private boolean fDiffProblem; + private String fErrorMessage; + private Map fHunkResults = new HashMap(); + private List fBeforeLines, fAfterLines; + private final PatchConfiguration configuration; + private String charset; + + public FileDiffResult(FileDiff diff, PatchConfiguration configuration) { + super(); + fDiff = diff; + this.configuration = configuration; + } + + public PatchConfiguration getConfiguration() { + return configuration; + } + + public boolean canApplyHunk(Hunk hunk) { + HunkResult result = getHunkResult(hunk); + return result.isOK() && !fDiffProblem; + } + + /** + * Refreshes the state of the diff to {no matches, no problems} and checks to see what hunks contained + * by this Diff can actually be applied. + * + * Checks to see: + * 1) if the target file specified in fNewPath exists and is patchable + * 2) which hunks contained by this diff can actually be applied to the file + * @param storage the contents being patched or null for an addition + * @param monitor a progress monitor or null if no progress monitoring is desired + */ + public void refresh(IStorage storage, IProgressMonitor monitor) { + fMatches= false; + fDiffProblem= false; + boolean create= false; + charset = Utilities.getCharset(storage); + //If this diff is an addition, make sure that it doesn't already exist + boolean exists = targetExists(storage); + if (fDiff.getDiffType(getConfiguration().isReversed()) == FileDiff.ADDITION) { + if ((!exists || isEmpty(storage)) && canCreateTarget(storage)) { + fMatches= true; + } else { + // file already exists + fDiffProblem= true; + fErrorMessage= Messages.FileDiffResult_0; + } + create= true; + } else { //This diff is not an addition, try to find a match for it + //Ensure that the file described by the path exists and is modifiable + if (exists) { + fMatches= true; + } else { + // file doesn't exist + fDiffProblem= true; + fErrorMessage= Messages.FileDiffResult_1; + } + } + + if (fDiffProblem) { + // We couldn't find the target file or the patch is trying to add a + // file that already exists but we need to initialize the hunk + // results for display + fBeforeLines = new ArrayList(getLines(storage, false)); + fAfterLines = fMatches ? new ArrayList() : fBeforeLines; + Hunk[] hunks = fDiff.getHunks(); + for (int i = 0; i < hunks.length; i++) { + Hunk hunk = hunks[i]; + HunkResult result = getHunkResult(hunk); + result.setMatches(false); + } + } else { + // If this diff has no problems discovered so far, try applying the patch + patch(getLines(storage, create), monitor); + } + + if (containsProblems()) { + if (fMatches) { + // Check to see if we have at least one hunk that matches + fMatches = false; + Hunk[] hunks = fDiff.getHunks(); + for (int i = 0; i < hunks.length; i++) { + Hunk hunk = hunks[i]; + HunkResult result = getHunkResult(hunk); + if (result.isOK()) { + fMatches = true; + break; + } + } + } + } + } + + protected boolean canCreateTarget(IStorage storage) { + return true; + } + + protected boolean targetExists(IStorage storage) { + return storage != null; + } + + protected List getLines(IStorage storage, boolean create) { + List lines = LineReader.load(storage, create); + return lines; + } + + protected boolean isEmpty(IStorage storage) { + if (storage == null) + return true; + return LineReader.load(storage, false).isEmpty(); + } + + /* + * Tries to patch the given lines with the specified Diff. + * Any hunk that couldn't be applied is returned in the list failedHunks. + */ + public void patch(List lines, IProgressMonitor monitor) { + fBeforeLines = new ArrayList(); + fBeforeLines.addAll(lines); + if (getConfiguration().getFuzz() != 0) { + calculateFuzz(fBeforeLines, monitor); + } + int shift= 0; + Hunk[] hunks = fDiff.getHunks(); + for (int i = 0; i < hunks.length; i++) { + Hunk hunk = hunks[i]; + HunkResult result = getHunkResult(hunk); + result.setShift(shift); + if (result.patch(lines)) { + shift = result.getShift(); + } + } + fAfterLines = lines; + } + + public boolean getDiffProblem() { + return fDiffProblem; + } + + /** + * Returns whether this Diff has any problems + * @return true if this Diff or any of its children Hunks have a problem, false if it doesn't + */ + public boolean containsProblems() { + if (fDiffProblem) + return true; + for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { + HunkResult result = (HunkResult) iterator.next(); + if (!result.isOK()) + return true; + } + return false; + } + + public String getLabel() { + String label= getTargetPath().toString(); + if (this.fDiffProblem) + return NLS.bind(Messages.FileDiffResult_2, new String[] {label, fErrorMessage}); + return label; + } + + public boolean hasMatches() { + return fMatches; + } + + /** + * Return the lines of the target file with all matched hunks applied. + * @return the lines of the target file with all matched hunks applied + */ + public List getLines() { + return fAfterLines; + } + + /** + * Calculate the fuzz factor that will allow the most hunks to be matched. + * @param lines the lines of the target file + * @param monitor a progress monitor + * @return the fuzz factor or -1 if no hunks could be matched + */ + public int calculateFuzz(List lines, IProgressMonitor monitor) { + if (monitor == null) + monitor = new NullProgressMonitor(); + fBeforeLines = new ArrayList(lines); + // TODO: What about deletions? + if (fDiff.getDiffType(getConfiguration().isReversed()) == FileDiff.ADDITION) { + // Additions don't need to adjust the fuzz factor + // TODO: What about the after lines? + return -1; + } + int shift= 0; + int highestFuzz = -1; // the maximum fuzz factor for all hunks + String name = getTargetPath() != null ? getTargetPath().lastSegment() : ""; //$NON-NLS-1$ + Hunk[] hunks = fDiff.getHunks(); + for (int j = 0; j < hunks.length; j++) { + Hunk h = hunks[j]; + monitor.subTask(NLS.bind(Messages.FileDiffResult_3, new String[] {name, Integer.toString(j + 1)})); + HunkResult result = getHunkResult(h); + result.setShift(shift); + int fuzz = result.calculateFuzz(lines, monitor); + shift = result.getShift(); + if (fuzz > highestFuzz) + highestFuzz = fuzz; + monitor.worked(1); + } + fAfterLines = lines; + return highestFuzz; + } + + public IPath getTargetPath() { + return fDiff.getStrippedPath(getConfiguration().getPrefixSegmentStripCount(), getConfiguration().isReversed()); + } + + private HunkResult getHunkResult(Hunk hunk) { + HunkResult result = (HunkResult)fHunkResults.get(hunk); + if (result == null) { + result = new HunkResult(this, hunk); + fHunkResults .put(hunk, result); + } + return result; + } + + public List getFailedHunks() { + List failedHunks = new ArrayList(); + for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { + HunkResult result = (HunkResult) iterator.next(); + if (!result.isOK()) + failedHunks.add(result.getHunk()); + } + return failedHunks; + } + + private HunkResult[] getFailedHunkResults() { + List failedHunks = new ArrayList(); + for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { + HunkResult result = (HunkResult) iterator.next(); + if (!result.isOK()) + failedHunks.add(result); + } + return (HunkResult[]) failedHunks.toArray(new HunkResult[failedHunks.size()]); + } + + public FileDiff getDiff() { + return fDiff; + } + + public List getBeforeLines() { + return fBeforeLines; + } + + public List getAfterLines() { + return fAfterLines; + } + + public HunkResult[] getHunkResults() { + return (HunkResult[]) fHunkResults.values().toArray(new HunkResult[fHunkResults.size()]); + } + + public InputStream getOriginalContents() { + String contents = LineReader.createString(isPreserveLineDelimeters(), getBeforeLines()); + return asInputStream(contents, getCharset()); + } + + public InputStream getPatchedContents() { + String contents = LineReader.createString(isPreserveLineDelimeters(), getLines()); + return asInputStream(contents, getCharset()); + } + + public String getCharset() { + return charset; + } + + public boolean isPreserveLineDelimeters() { + return false; + } + + public IHunk[] getRejects() { + return getFailedHunkResults(); + } + + public boolean hasRejects() { + return getFailedHunkResults().length > 0; + } + + public static InputStream asInputStream(String contents, String charSet) { + byte[] bytes = null; + if (charSet != null) { + try { + bytes = contents.getBytes(charSet); + } catch (UnsupportedEncodingException e) { + Activator.log(e); + } + } + if (bytes == null) { + bytes = contents.getBytes(); + } + return new ByteArrayInputStream(bytes); + } + +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Hunk.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Hunk.java new file mode 100644 index 000000000..78ea9df6c --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Hunk.java @@ -0,0 +1,446 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.compare.patch.PatchConfiguration; +import org.eclipse.core.runtime.Assert; + +/** + * A Hunk describes a range of changed lines and some context lines. + */ +public class Hunk { + + private FileDiff fParent; + private int fOldStart, fOldLength; + private int fNewStart, fNewLength; + private String[] fLines; + private int hunkType; + + public static Hunk createHunk(FileDiff parent, int[] oldRange, int[] newRange, List lines, boolean hasLineAdditions, boolean hasLineDeletions, boolean hasContextLines) { + int oldStart = 0; + int oldLength = 0; + int newStart = 0; + int newLength = 0; + if (oldRange[0] > 0) + oldStart= oldRange[0]-1; // line number start at 0! + else + oldStart= 0; + oldLength= oldRange[1]; + if (newRange[0] > 0) + newStart= newRange[0]-1; // line number start at 0! + else + newStart= 0; + newLength= newRange[1]; + int hunkType = FileDiff.CHANGE; + if (!hasContextLines) { + if (hasLineAdditions && !hasLineDeletions) { + hunkType = FileDiff.ADDITION; + } else if (!hasLineAdditions && hasLineDeletions) { + hunkType = FileDiff.DELETION; + } + } + return new Hunk(parent, hunkType, oldStart, oldLength, newStart, newLength, (String[]) lines.toArray(new String[lines.size()])); + } + + public Hunk(FileDiff parent, int hunkType, int oldStart, int oldLength, + int newStart, int newLength, String[] lines) { + fParent = parent; + if (fParent != null) { + fParent.add(this); + } + this.hunkType = hunkType; + fOldLength = oldLength; + fOldStart = oldStart; + fNewLength = newLength; + fNewStart = newStart; + fLines = lines; + } + + public Hunk(FileDiff parent, Hunk toCopy) { + this(parent, toCopy.hunkType, toCopy.fOldStart, toCopy.fOldLength, toCopy.fNewStart, toCopy.fNewLength, toCopy.fLines); + } + + /* + * Returns the contents of this hunk. + * Each line starts with a control character. Their meaning is as follows: + * + */ + public String getContent() { + StringBuffer sb= new StringBuffer(); + for (int i= 0; i < fLines.length; i++) { + String line= fLines[i]; + sb.append(line.substring(0, LineReader.length(line))); + sb.append('\n'); + } + return sb.toString(); + } + + /* + * Returns a descriptive String for this hunk. + * It is in the form old_start,old_length -> new_start,new_length. + */ + String getDescription() { + StringBuffer sb= new StringBuffer(); + sb.append(Integer.toString(fOldStart)); + sb.append(','); + sb.append(Integer.toString(fOldLength)); + sb.append(" -> "); //$NON-NLS-1$ + sb.append(Integer.toString(fNewStart)); + sb.append(','); + sb.append(Integer.toString(fNewLength)); + return sb.toString(); + } + + public String getRejectedDescription() { + StringBuffer sb= new StringBuffer(); + sb.append("@@ -"); //$NON-NLS-1$ + sb.append(Integer.toString(fOldStart)); + sb.append(','); + sb.append(Integer.toString(fOldLength)); + sb.append(" +"); //$NON-NLS-1$ + sb.append(Integer.toString(fNewStart)); + sb.append(','); + sb.append(Integer.toString(fNewLength)); + sb.append(" @@"); //$NON-NLS-1$ + return sb.toString(); + } + + int getHunkType(boolean reverse) { + if (reverse) { + if (hunkType == FileDiff.ADDITION) + return FileDiff.DELETION; + if (hunkType == FileDiff.DELETION) + return FileDiff.ADDITION; + } + return hunkType; + } + + void setHunkType(int hunkType) { + this.hunkType = hunkType; + } + + public String[] getLines() { + return fLines; + } + + /** + * Set the parent of this hunk. This method + * should only be invoked from {@link FileDiff#add(Hunk)} + * @param diff the parent of this hunk + */ + void setParent(FileDiff diff) { + if (fParent == diff) + return; + if (fParent != null) + fParent.remove(this); + fParent = diff; + } + + public FileDiff getParent() { + return fParent; + } + + /* + * Tries to apply the given hunk on the specified lines. + * The parameter shift is added to the line numbers given + * in the hunk. + */ + public boolean tryPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { + boolean reverse = configuration.isReversed(); + int pos = getStart(reverse) + shift; + int deleteMatches = 0; + List contextLines = new ArrayList(); + boolean contextLinesMatched = true; + boolean precedingLinesChecked = false; + for (int i= 0; i < fLines.length; i++) { + String s = fLines[i]; + Assert.isTrue(s.length() > 0); + String line = s.substring(1); + char controlChar = s.charAt(0); + + if (controlChar == ' ') { // context lines + + if (pos < 0 || pos >= lines.size()) + return false; + contextLines.add(line); + if (linesMatch(configuration, line, (String) lines.get(pos))) { + pos++; + continue; + } else if (fuzz > 0) { + // doesn't match, use the fuzz factor + contextLinesMatched = false; + pos++; + continue; + } + return false; + } else if (isDeletedDelimeter(controlChar, reverse)) { + // deleted lines + + if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) + // context lines inside hunk don't match + return false; + + // check following context lines if exist + // use the fuzz factor if needed + if (!precedingLinesChecked + && !contextLinesMatched + && contextLines.size() >= fuzz + && !checkPrecedingContextLines(configuration, lines, + fuzz, pos, contextLines)) + return false; + // else if there is less or equal context line to the fuzz + // factor we ignore them all and treat as matching + + precedingLinesChecked = true; + contextLines.clear(); + contextLinesMatched = true; + + if (pos < 0 || pos >= lines.size()) // out of the file + return false; + if (linesMatch(configuration, line, (String) lines.get(pos))) { + deleteMatches++; + pos++; + continue; // line matched, continue with the next one + } + + // We must remove all lines at once, return false if this + // fails. In other words, all lines considered for deletion + // must be found one by one. + + // if (deleteMatches <= 0) + return false; + // pos++; + } else if (isAddedDelimeter(controlChar, reverse)) { + + if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) + return false; + + if (!precedingLinesChecked + && !contextLinesMatched + && contextLines.size() >= fuzz + && !checkPrecedingContextLines(configuration, lines, + fuzz, pos, contextLines)) + return false; + + precedingLinesChecked = true; + contextLines.clear(); + contextLinesMatched = true; + + // we don't have to do anything more for a 'try' + } else + Assert.isTrue(false, "tryPatch: unknown control character: " + controlChar); //$NON-NLS-1$ + } + + // check following context lines if exist + if (!contextLinesMatched + && fuzz > 0 + && contextLines.size() > fuzz + && !checkFollowingContextLines(configuration, lines, fuzz, pos, + contextLines)) + return false; + + return true; + } + + private boolean checkPrecedingContextLines( + PatchConfiguration configuration, List lines, int fuzz, int pos, + List contextLines) { + + // ignore from the beginning + for (int j = fuzz; j < contextLines.size(); j++) { + if (!linesMatch(configuration, (String) contextLines.get(j), + (String) lines.get(pos - contextLines.size() + j))) + return false; + } + return true; + } + + private boolean checkFollowingContextLines( + PatchConfiguration configuration, List lines, int fuzz, int pos, + List contextLines) { + if (!contextLines.isEmpty()) { + // ignore from the end + for (int j = 0; j < contextLines.size() - fuzz; j++) { + if (!linesMatch(configuration, (String) contextLines.get(j), + (String) lines.get(pos - contextLines.size() + j))) + return false; + } + } + return true; + } + + int getStart(boolean reverse) { + if (reverse) { + return fNewStart; + } + return fOldStart; + } + + private int getLength(boolean reverse) { + if (reverse) { + return fNewLength; + } + return fOldLength; + } + + private int getShift(boolean reverse) { + if (reverse) { + return fOldLength - fNewLength; + } + return fNewLength - fOldLength; + } + + int doPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { + boolean reverse = configuration.isReversed(); + int pos = getStart(reverse) + shift; + List contextLines = new ArrayList(); + boolean contextLinesMatched = true; + boolean precedingLinesChecked = false; + for (int i= 0; i < fLines.length; i++) { + String s= fLines[i]; + Assert.isTrue(s.length() > 0); + String line= s.substring(1); + char controlChar= s.charAt(0); + if (controlChar == ' ') { + // context lines + Assert.isTrue(pos < lines.size(), "doPatch: inconsistency in context"); //$NON-NLS-1$ + contextLines.add(line); + if (linesMatch(configuration, line, (String) lines.get(pos))) { + pos++; + continue; + } else if (fuzz > 0) { + // doesn't match, use the fuzz factor + contextLinesMatched = false; + pos++; + continue; + } + Assert.isTrue(false, "doPatch: context doesn't match"); //$NON-NLS-1$ +// pos++; + } else if (isDeletedDelimeter(controlChar, reverse)) { + // deleted lines + if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) + // context lines inside hunk don't match + Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ + + // check following context lines if exist + // use the fuzz factor if needed + if (!precedingLinesChecked + && !contextLinesMatched + && contextLines.size() >= fuzz + && !checkPrecedingContextLines(configuration, lines, + fuzz, pos, contextLines)) + Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; + // else if there is less or equal context line to the fuzz + // factor we ignore them all and treat as matching + + precedingLinesChecked = true; + contextLines.clear(); + contextLinesMatched = true; + + lines.remove(pos); + } else if (isAddedDelimeter(controlChar, reverse)) { + // added lines + if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) + Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ + + if (!precedingLinesChecked + && !contextLinesMatched + && contextLines.size() >= fuzz + && !checkPrecedingContextLines(configuration, lines, + fuzz, pos, contextLines)) + Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; + + precedingLinesChecked = true; + contextLines.clear(); + contextLinesMatched = true; + + if (getLength(reverse) == 0 && pos+1 < lines.size()) + lines.add(pos+1, line); + else + lines.add(pos, line); + pos++; + } else + Assert.isTrue(false, "doPatch: unknown control character: " + controlChar); //$NON-NLS-1$ + } + return getShift(reverse); + } + + private boolean isDeletedDelimeter(char controlChar, boolean reverse) { + return (!reverse && controlChar == '-') || (reverse && controlChar == '+'); + } + + private boolean isAddedDelimeter(char controlChar, boolean reverse) { + return (reverse && controlChar == '-') || (!reverse && controlChar == '+'); + } + + /* + * Compares two strings. + * If fIgnoreWhitespace is true whitespace is ignored. + */ + private boolean linesMatch(PatchConfiguration configuration, String line1, String line2) { + if (configuration.isIgnoreWhitespace()) + return stripWhiteSpace(line1).equals(stripWhiteSpace(line2)); + if (isIgnoreLineDelimiter()) { + int l1= LineReader.length(line1); + int l2= LineReader.length(line2); + if (l1 != l2) + return false; + return line1.regionMatches(0, line2, 0, l1); + } + return line1.equals(line2); + } + + private boolean isIgnoreLineDelimiter() { + return true; + } + + /* + * Returns the given string with all whitespace characters removed. + * Whitespace is defined by Character.isWhitespace(...). + */ + private String stripWhiteSpace(String s) { + StringBuffer sb= new StringBuffer(); + int l= s.length(); + for (int i= 0; i < l; i++) { + char c= s.charAt(i); + if (!Character.isWhitespace(c)) + sb.append(c); + } + return sb.toString(); + } + + public String getContents(boolean isAfterState, boolean reverse) { + StringBuffer result= new StringBuffer(); + for (int i= 0; i - Bug 181919 LineReader creating unneeded garbage + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.io.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.compare.internal.core.Activator; +import org.eclipse.core.resources.IEncodedStorage; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; + +public class LineReader { + + public static BufferedReader createReader(IStorage storage) throws CoreException { + String charset = null; + if (storage instanceof IEncodedStorage) { + IEncodedStorage es = (IEncodedStorage) storage; + charset = es.getCharset(); + } + InputStreamReader in = null; + if (charset != null) { + InputStream contents = storage.getContents(); + try { + in = new InputStreamReader(contents, charset); + } catch (UnsupportedEncodingException e) { + Activator.log(e); + try { + contents.close(); + } catch (IOException e1) { + // Ignore + } + } + } + if (in == null) { + in = new InputStreamReader(storage.getContents()); + } + return new BufferedReader(in); + } + + /* + * Reads the contents from the given file and returns them as + * a List of lines. + */ + public static List load(IStorage file, boolean create) { + List lines= null; + if (!create && file != null && exists(file)) { + // read current contents + String charset = Utilities.getCharset(file); + InputStream is= null; + try { + is= file.getContents(); + + Reader streamReader= null; + try { + streamReader= new InputStreamReader(is, charset); + } catch (UnsupportedEncodingException x) { + // use default encoding + streamReader= new InputStreamReader(is); + } + + BufferedReader reader= new BufferedReader(streamReader); + lines = readLines(reader); + } catch(CoreException ex) { + // TODO + Activator.log(ex); + } finally { + if (is != null) + try { + is.close(); + } catch(IOException ex) { + // silently ignored + } + } + } + + if (lines == null) + lines= new ArrayList(); + return lines; + } + + private static boolean exists(IStorage file) { + if (file instanceof IFile) { + return ((IFile) file).exists(); + } + return true; + } + + public static List readLines(BufferedReader reader) { + List lines; + LineReader lr= new LineReader(reader); + lr.ignoreSingleCR(); // Don't treat single CRs as line feeds to be consistent with command line patch + lines= lr.readLines(); + return lines; + } + + /* + * Concatenates all strings found in the given List. + */ + public static String createString(boolean preserveLineDelimeters, List lines) { + StringBuffer sb= new StringBuffer(); + Iterator iter= lines.iterator(); + if (preserveLineDelimeters) { + while (iter.hasNext()) + sb.append((String)iter.next()); + } else { + String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ + while (iter.hasNext()) { + String line= (String)iter.next(); + int l= length(line); + if (l < line.length()) { // line has delimiter + sb.append(line.substring(0, l)); + sb.append(lineSeparator); + } else { + sb.append(line); + } + } + } + return sb.toString(); + } + + /* + * Returns the length (excluding a line delimiter CR, LF, CR/LF) + * of the given string. + */ + /* package */ static int length(String s) { + int l= s.length(); + if (l > 0) { + char c= s.charAt(l-1); + if (c == '\r') + return l-1; + if (c == '\n') { + if (l > 1 && s.charAt(l-2) == '\r') + return l-2; + return l-1; + } + } + return l; + } + + private boolean fHaveChar= false; + private int fLastChar; + private boolean fSawEOF= false; + private BufferedReader fReader; + private boolean fIgnoreSingleCR= false; + private StringBuffer fBuffer= new StringBuffer(); + + public LineReader(BufferedReader reader) { + fReader= reader; + Assert.isNotNull(reader); + } + + public void ignoreSingleCR() { + fIgnoreSingleCR= true; + } + + /** + * Reads a line of text. A line is considered to be terminated by any one + * of a line feed ('\n'), a carriage return ('\r'), or a carriage return + * followed immediately by a line-feed. + * @return A string containing the contents of the line including + * the line-termination characters, or null if the end of the + * stream has been reached + * @exception IOException If an I/O error occurs + */ + /* package */ String readLine() throws IOException { + try { + while (!fSawEOF) { + int c= readChar(); + if (c == -1) { + fSawEOF= true; + break; + } + fBuffer.append((char)c); + if (c == '\n') + break; + if (c == '\r') { + c= readChar(); + if (c == -1) { + fSawEOF= true; + break; // EOF + } + if (c != '\n') { + if (fIgnoreSingleCR) { + fBuffer.append((char)c); + continue; + } + fHaveChar= true; + fLastChar= c; + } else + fBuffer.append((char)c); + break; + } + } + + if (fBuffer.length() != 0) { + return fBuffer.toString(); + } + return null; + } finally { + fBuffer.setLength(0); + } + } + + /* package */ void close() { + try { + fReader.close(); + } catch (IOException ex) { + // silently ignored + } + } + + public List readLines() { + try { + List lines= new ArrayList(); + String line; + while ((line= readLine()) != null) + lines.add(line); + return lines; + } catch (IOException ex) { + // NeedWork + //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); + } finally { + close(); + } + return null; + } + + /* + * Returns the number of characters in the given string without + * counting a trailing line separator. + */ + /* package */ int lineContentLength(String line) { + if (line == null) + return 0; + int length= line.length(); + for (int i= length-1; i >= 0; i--) { + char c= line.charAt(i); + if (c =='\n' || c == '\r') + length--; + else + break; + } + return length; + } + + //---- private + + private int readChar() throws IOException { + if (fHaveChar) { + fHaveChar= false; + return fLastChar; + } + return fReader.read(); + } +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/PatchReader.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/PatchReader.java new file mode 100644 index 000000000..666fb9f46 --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/PatchReader.java @@ -0,0 +1,669 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import java.io.BufferedReader; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.eclipse.compare.patch.IFilePatch; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import com.ibm.icu.text.DateFormat; +import com.ibm.icu.text.SimpleDateFormat; + +public class PatchReader { + + private static final boolean DEBUG= false; + + private static final String DEV_NULL= "/dev/null"; //$NON-NLS-1$ + + protected static final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; //$NON-NLS-1$ + + // diff formats + // private static final int CONTEXT= 0; + // private static final int ED= 1; + // private static final int NORMAL= 2; + // private static final int UNIFIED= 3; + + // we recognize the following date/time formats + private DateFormat[] fDateFormats= new DateFormat[] { + new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy"), //$NON-NLS-1$ + new SimpleDateFormat("yyyy/MM/dd kk:mm:ss"), //$NON-NLS-1$ + new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy", Locale.US) //$NON-NLS-1$ + }; + + private boolean fIsWorkspacePatch; + private DiffProject[] fDiffProjects; + private FileDiff[] fDiffs; + + // API for writing new multi-project patch format + public static final String MULTIPROJECTPATCH_HEADER= "### Eclipse Workspace Patch"; //$NON-NLS-1$ + + public static final String MULTIPROJECTPATCH_VERSION= "1.0"; //$NON-NLS-1$ + + public static final String MULTIPROJECTPATCH_PROJECT= "#P"; //$NON-NLS-1$ + + /** + * Create a patch reader for the default date formats. + */ + public PatchReader() { + // nothing here + } + + /** + * Create a patch reader for the given date formats. + * + * @param dateFormats + * Array of DateFormats to be used when + * extracting dates from the patch. + */ + public PatchReader(DateFormat[] dateFormats) { + this(); + fDateFormats = dateFormats; + } + + public void parse(BufferedReader reader) throws IOException { + List diffs= new ArrayList(); + HashMap diffProjects= new HashMap(4); + String line= null; + boolean reread= false; + String diffArgs= null; + String fileName= null; + // no project means this is a single patch,create a placeholder project for now + // which will be replaced by the target selected by the user in the preview pane + String project= ""; //$NON-NLS-1$ + fIsWorkspacePatch= false; + + LineReader lr= new LineReader(reader); + lr.ignoreSingleCR(); // Don't treat single CRs as line feeds to be consistent with command line patch + + // Test for our format + line= lr.readLine(); + if (line != null && line.startsWith(PatchReader.MULTIPROJECTPATCH_HEADER)) { + fIsWorkspacePatch= true; + } else { + parse(lr, line); + return; + } + + // read leading garbage + while (true) { + if (!reread) + line= lr.readLine(); + reread= false; + if (line == null) + break; + if (line.length() < 4) + continue; // too short + + if (line.startsWith(PatchReader.MULTIPROJECTPATCH_PROJECT)) { + project= line.substring(2).trim(); + continue; + } + + if (line.startsWith("Index: ")) { //$NON-NLS-1$ + fileName= line.substring(7).trim(); + continue; + } + if (line.startsWith("diff")) { //$NON-NLS-1$ + diffArgs= line.substring(4).trim(); + continue; + } + + if (line.startsWith("--- ")) { //$NON-NLS-1$ + // if there is no current project or + // the current project doesn't equal the newly parsed project + // reset the current project to the newly parsed one, create a new DiffProject + // and add it to the array + DiffProject diffProject; + if (!diffProjects.containsKey(project)) { + IProject iproject= ResourcesPlugin.getWorkspace().getRoot().getProject(project); + diffProject= new DiffProject(iproject); + diffProjects.put(project, diffProject); + } else { + diffProject= (DiffProject) diffProjects.get(project); + } + + line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName, diffProject); + diffArgs= fileName= null; + reread= true; + } + } + + lr.close(); + + fDiffProjects= (DiffProject[]) diffProjects.values().toArray(new DiffProject[diffProjects.size()]); + fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); + } + + private String readUnifiedDiff(List diffs, LineReader lr, String line, String diffArgs, String fileName, DiffProject diffProject) throws IOException { + List newDiffs= new ArrayList(); + String nextLine= readUnifiedDiff(newDiffs, lr, line, diffArgs, fileName); + for (Iterator iter= newDiffs.iterator(); iter.hasNext();) { + FileDiff diff= (FileDiff) iter.next(); + diffProject.add(diff); + diffs.add(diff); + } + return nextLine; + } + + public void parse(LineReader lr, String line) throws IOException { + List diffs= new ArrayList(); + boolean reread= false; + String diffArgs= null; + String fileName= null; + List headerLines = new ArrayList(); + + // read leading garbage + reread= line!=null; + while (true) { + if (!reread) + line= lr.readLine(); + reread= false; + if (line == null) + break; + + // remember some infos + if (line.startsWith("Index: ")) { //$NON-NLS-1$ + fileName= line.substring(7).trim(); + } else if (line.startsWith("diff")) { //$NON-NLS-1$ + diffArgs= line.substring(4).trim(); + } else if (line.startsWith("--- ")) { //$NON-NLS-1$ + line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName); + if (!headerLines.isEmpty()) + setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); + diffArgs= fileName= null; + reread= true; + } else if (line.startsWith("*** ")) { //$NON-NLS-1$ + line= readContextDiff(diffs, lr, line, diffArgs, fileName); + if (!headerLines.isEmpty()) + setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); + diffArgs= fileName= null; + reread= true; + } + + // Any lines we read here are header lines. + // However, if reread is set, we will add them to the header on the next pass through + if (!reread) { + headerLines.add(line); + } + } + + lr.close(); + + fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); + } + + private void setHeader(FileDiff diff, List headerLines) { + String header = LineReader.createString(false, headerLines); + diff.setHeader(header); + headerLines.clear(); + } + + /* + * Returns the next line that does not belong to this diff + */ + protected String readUnifiedDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { + + String[] oldArgs= split(line.substring(4)); + + // read info about new file + line= reader.readLine(); + if (line == null || !line.startsWith("+++ ")) //$NON-NLS-1$ + return line; + + String[] newArgs= split(line.substring(4)); + + FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), + extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); + diffs.add(diff); + + int[] oldRange= new int[2]; + int[] newRange= new int[2]; + List lines= new ArrayList(); + + boolean encounteredPlus = false; + boolean encounteredMinus = false; + boolean encounteredSpace = false; + + try { + // read lines of hunk + while (true) { + + line= reader.readLine(); + if (line == null) + return null; + + if (reader.lineContentLength(line) == 0) { + //System.out.println("Warning: found empty line in hunk; ignored"); + //lines.add(' ' + line); + continue; + } + + char c= line.charAt(0); + switch (c) { + case '@': + if (line.startsWith("@@ ")) { //$NON-NLS-1$ + // flush old hunk + if (lines.size() > 0) { + Hunk.createHunk(diff, oldRange, newRange, lines,encounteredPlus, encounteredMinus, encounteredSpace); + lines.clear(); + } + + // format: @@ -oldStart,oldLength +newStart,newLength @@ + extractPair(line, '-', oldRange); + extractPair(line, '+', newRange); + continue; + } + break; + case ' ': + encounteredSpace = true; + lines.add(line); + continue; + case '+': + encounteredPlus = true; + lines.add(line); + continue; + case '-': + encounteredMinus = true; + lines.add(line); + continue; + case '\\': + if (line.indexOf("newline at end") > 0) { //$NON-NLS-1$ + int lastIndex= lines.size(); + if (lastIndex > 0) { + line= (String) lines.get(lastIndex-1); + int end= line.length()-1; + char lc= line.charAt(end); + if (lc == '\n') { + end--; + if (end > 0 && line.charAt(end) == '\r') + end--; + } else if (lc == '\r') { + end--; + } + line= line.substring(0, end+1); + lines.set(lastIndex-1, line); + } + continue; + } + break; + default: + if (DEBUG) { + int a1= c, a2= 0; + if (line.length() > 1) + a2= line.charAt(1); + System.out.println("char: " + a1 + " " + a2); //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + } + return line; + } + } finally { + if (lines.size() > 0) + Hunk.createHunk(diff, oldRange, newRange, lines, encounteredPlus, encounteredMinus, encounteredSpace); + } + } + + /* + * Returns the next line that does not belong to this diff + */ + private String readContextDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { + + String[] oldArgs= split(line.substring(4)); + + // read info about new file + line= reader.readLine(); + if (line == null || !line.startsWith("--- ")) //$NON-NLS-1$ + return line; + + String[] newArgs= split(line.substring(4)); + + FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), + extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); + diffs.add(diff); + + int[] oldRange= new int[2]; + int[] newRange= new int[2]; + List oldLines= new ArrayList(); + List newLines= new ArrayList(); + List lines= oldLines; + + + boolean encounteredPlus = false; + boolean encounteredMinus = false; + boolean encounteredSpace = false; + + try { + // read lines of hunk + while (true) { + + line= reader.readLine(); + if (line == null) + return line; + + int l= line.length(); + if (l == 0) + continue; + if (l > 1) { + switch (line.charAt(0)) { + case '*': + if (line.startsWith("***************")) { // new hunk //$NON-NLS-1$ + // flush old hunk + if (oldLines.size() > 0 || newLines.size() > 0) { + Hunk.createHunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); + oldLines.clear(); + newLines.clear(); + } + continue; + } + if (line.startsWith("*** ")) { // old range //$NON-NLS-1$ + // format: *** oldStart,oldEnd *** + extractPair(line, ' ', oldRange); + oldRange[1]= oldRange[1]-oldRange[0]+1; + lines= oldLines; + continue; + } + break; + case ' ': // context line + if (line.charAt(1) == ' ') { + lines.add(line); + continue; + } + break; + case '+': // addition + if (line.charAt(1) == ' ') { + encounteredPlus = true; + lines.add(line); + continue; + } + break; + case '!': // change + if (line.charAt(1) == ' ') { + encounteredSpace = true; + lines.add(line); + continue; + } + break; + case '-': + if (line.charAt(1) == ' ') { // deletion + encounteredMinus = true; + lines.add(line); + continue; + } + if (line.startsWith("--- ")) { // new range //$NON-NLS-1$ + // format: *** newStart,newEnd *** + extractPair(line, ' ', newRange); + newRange[1]= newRange[1]-newRange[0]+1; + lines= newLines; + continue; + } + break; + default: + break; + } + } + return line; + } + } finally { + // flush last hunk + if (oldLines.size() > 0 || newLines.size() > 0) + Hunk.createHunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); + } + } + + /* + * Creates a List of lines in the unified format from + * two Lists of lines in the 'classic' format. + */ + private List unifyLines(List oldLines, List newLines) { + List result= new ArrayList(); + + String[] ol= (String[]) oldLines.toArray(new String[oldLines.size()]); + String[] nl= (String[]) newLines.toArray(new String[newLines.size()]); + + int oi= 0, ni= 0; + + while (true) { + + char oc= 0; + String o= null; + if (oi < ol.length) { + o= ol[oi]; + oc= o.charAt(0); + } + + char nc= 0; + String n= null; + if (ni < nl.length) { + n= nl[ni]; + nc= n.charAt(0); + } + + // EOF + if (oc == 0 && nc == 0) + break; + + // deletion in old + if (oc == '-') { + do { + result.add('-' + o.substring(2)); + oi++; + if (oi >= ol.length) + break; + o= ol[oi]; + } while (o.charAt(0) == '-'); + continue; + } + + // addition in new + if (nc == '+') { + do { + result.add('+' + n.substring(2)); + ni++; + if (ni >= nl.length) + break; + n= nl[ni]; + } while (n.charAt(0) == '+'); + continue; + } + + // differing lines on both sides + if (oc == '!' && nc == '!') { + // remove old + do { + result.add('-' + o.substring(2)); + oi++; + if (oi >= ol.length) + break; + o= ol[oi]; + } while (o.charAt(0) == '!'); + + // add new + do { + result.add('+' + n.substring(2)); + ni++; + if (ni >= nl.length) + break; + n= nl[ni]; + } while (n.charAt(0) == '!'); + + continue; + } + + // context lines + if (oc == ' ' && nc == ' ') { + do { + Assert.isTrue(o.equals(n), "non matching context lines"); //$NON-NLS-1$ + result.add(' ' + o.substring(2)); + oi++; + ni++; + if (oi >= ol.length || ni >= nl.length) + break; + o= ol[oi]; + n= nl[ni]; + } while (o.charAt(0) == ' ' && n.charAt(0) == ' '); + continue; + } + + if (oc == ' ') { + do { + result.add(' ' + o.substring(2)); + oi++; + if (oi >= ol.length) + break; + o= ol[oi]; + } while (o.charAt(0) == ' '); + continue; + } + + if (nc == ' ') { + do { + result.add(' ' + n.substring(2)); + ni++; + if (ni >= nl.length) + break; + n= nl[ni]; + } while (n.charAt(0) == ' '); + continue; + } + + Assert.isTrue(false, "unexpected char <" + oc + "> <" + nc + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + return result; + } + + /* + * @return the parsed time/date in milliseconds or IFilePatch.DATE_UNKNOWN + * (0) on error + */ + private long extractDate(String[] args, int n) { + if (n < args.length) { + String line= args[n]; + for (int i= 0; i < fDateFormats.length; i++) { + fDateFormats[i].setLenient(true); + try { + Date date= fDateFormats[i].parse(line); + return date.getTime(); + } catch (ParseException ex) { + // silently ignored + } + } + // System.err.println("can't parse date: <" + line + ">"); + } + return IFilePatch.DATE_UNKNOWN; + } + + /* + * Returns null if file name is "/dev/null". + */ + private IPath extractPath(String[] args, int n, String path2) { + if (n < args.length) { + String path= args[n]; + if (DEV_NULL.equals(path)) + return null; + int pos= path.lastIndexOf(':'); + if (pos >= 0) + path= path.substring(0, pos); + if (path2 != null && !path2.equals(path)) { + if (DEBUG) System.out.println("path mismatch: " + path2); //$NON-NLS-1$ + path= path2; + } + return new Path(path); + } + return null; + } + + /* + * Tries to extract two integers separated by a comma. + * The parsing of the line starts at the position after + * the first occurrence of the given character start an ends + * at the first blank (or the end of the line). + * If only a single number is found this is assumed to be the start of a one line range. + * If an error occurs the range -1,-1 is returned. + */ + private void extractPair(String line, char start, int[] pair) { + pair[0]= pair[1]= -1; + int startPos= line.indexOf(start); + if (startPos < 0) { + if (DEBUG) System.out.println("parsing error in extractPair: couldn't find \'" + start + "\'"); //$NON-NLS-1$ //$NON-NLS-2$ + return; + } + line= line.substring(startPos+1); + int endPos= line.indexOf(' '); + if (endPos < 0) { + if (DEBUG) System.out.println("parsing error in extractPair: couldn't find end blank"); //$NON-NLS-1$ + return; + } + line= line.substring(0, endPos); + int comma= line.indexOf(','); + if (comma >= 0) { + pair[0]= Integer.parseInt(line.substring(0, comma)); + pair[1]= Integer.parseInt(line.substring(comma+1)); + } else { // abbreviated form for one line patch + pair[0]= Integer.parseInt(line); + pair[1]= 1; + } + } + + + /* + * Breaks the given string into tab separated substrings. + * Leading and trailing whitespace is removed from each token. + */ + private String[] split(String line) { + List l= new ArrayList(); + StringTokenizer st= new StringTokenizer(line, "\t"); //$NON-NLS-1$ + while (st.hasMoreElements()) { + String token= st.nextToken().trim(); + if (token.length() > 0) + l.add(token); + } + return (String[]) l.toArray(new String[l.size()]); + } + + public boolean isWorkspacePatch() { + return fIsWorkspacePatch; + } + + public DiffProject[] getDiffProjects() { + return fDiffProjects; + } + + public FileDiff[] getDiffs() { + return fDiffs; + } + + public FileDiff[] getAdjustedDiffs() { + if (!isWorkspacePatch() || fDiffs.length == 0) + return fDiffs; + List result = new ArrayList(); + for (int i = 0; i < fDiffs.length; i++) { + FileDiff diff = fDiffs[i]; + result.add(diff.asRelativeDiff()); + } + return (FileDiff[]) result.toArray(new FileDiff[result.size()]); + } + +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Utilities.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Utilities.java new file mode 100644 index 000000000..5ac7043fc --- /dev/null +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/core/patch/Utilities.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.compare.internal.core.patch; + +import org.eclipse.compare.internal.core.Activator; +import org.eclipse.core.resources.IEncodedStorage; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; + +public class Utilities { + + public static String getCharset(Object resource) { + if (resource instanceof IEncodedStorage) { + try { + return ((IEncodedStorage)resource).getCharset(); + } catch (CoreException ex) { + Activator.log(ex); + } + } + return ResourcesPlugin.getEncoding(); + } + +} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/DiffProject.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/DiffProject.java deleted file mode 100644 index ddb461292..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/DiffProject.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; - -/** - * A diff project represents a project that was read from a workspace patch. - * It contains the set of file diffs that were associated with the project - * in the patch file. - */ -public class DiffProject { - - private IProject fProject; - private Set fDiffs= new HashSet(); - - /** - * Create a diff project for the given workspace project. - * @param project a workspace project - */ - public DiffProject(IProject project) { - this.fProject= project; - } - - /** - * Add the file diff to this project. - * @param diff the file diff. - */ - void add(FileDiff diff) { - fDiffs.add(diff); - if (diff.getProject() != this) - diff.setProject(this); - } - - - /** - * Return the workspace project associated with this diff project. - * @return the workspace project associated with this project - */ - public IProject getProject() { - return this.fProject; - } - - /** - * Return the name of this project. - * @return the name of this project - */ - public String getName() { - return fProject.getName(); - } - - /** - * Return the file at the given path relative to this project. - * @param path the relative path - * @return the file at the given path relative to this project - */ - public IFile getFile(IPath path) { - return fProject.getFile(path); - } - - /** - * Remove the file diff from this project. - * @param diff the diff to be removed - */ - public void remove(FileDiff diff) { - fDiffs.remove(diff); - } - - /** - * Return whether this project contains the given diff. - * @param diff a file diff - * @return whether this project contains the given diff - */ - public boolean contains(FileDiff diff) { - return fDiffs.contains(diff); - } - - /** - * Return the file diffs associated with this project. - * @return the file diffs associated with this project - */ - public FileDiff[] getFileDiffs() { - return (FileDiff[]) fDiffs.toArray(new FileDiff[fDiffs.size()]); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiff.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiff.java deleted file mode 100644 index be69fb4f2..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiff.java +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.compare.patch.IFilePatchResult; -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Path; - -/** - * A file diff represents a set of hunks that were associated with the - * same path in a patch file. - */ -public class FileDiff implements IFilePatch { - - /** - * Difference constant (value 1) indicating one side was added. - */ - public static final int ADDITION= 1; - /** - * Difference constant (value 2) indicating one side was removed. - */ - public static final int DELETION= 2; - /** - * Difference constant (value 3) indicating side changed. - */ - public static final int CHANGE= 3; - - private IPath fOldPath, fNewPath; - private long oldDate, newDate; - private List fHunks= new ArrayList(); - private DiffProject fProject; //the project that contains this diff - private String header; - private int addedLines, removedLines; - - /** - * Create a file diff for the given path and date information. - * @param oldPath the path of the before state of the file - * @param oldDate the timestamp of the before state - * @param newPath the path of the after state - * @param newDate the timestamp of the after state - */ - protected FileDiff(IPath oldPath, long oldDate, IPath newPath, long newDate) { - fOldPath= oldPath; - this.oldDate = oldDate; - fNewPath= newPath; - this.newDate = newDate; - } - - /** - * Return the parent project or null if there isn't one. - * @return the parent project or null - */ - public DiffProject getProject() { - return fProject; - } - - /** - * Set the project of this diff to the given project. - * This method should only be called from - * {@link DiffProject#add(FileDiff)} - * @param diffProject the parent project - */ - void setProject(DiffProject diffProject) { - if (fProject == diffProject) - return; - if (fProject != null) - fProject.remove(this); - this.fProject= diffProject; - } - - /** - * Get the path of the file diff. - * @param reverse whether the path of the before state or after state - * should be used - * @return the path of the file diff - */ - public IPath getPath(boolean reverse) { - if (getDiffType(reverse) == ADDITION) { - if (reverse) - return fOldPath; - return fNewPath; - } - if (reverse && fNewPath != null) - return fNewPath; - if (fOldPath != null) - return fOldPath; - return fNewPath; - } - - /** - * Add the hunk to this file diff. - * @param hunk the hunk - */ - protected void add(Hunk hunk) { - fHunks.add(hunk); - hunk.setParent(this); - } - - /** - * Remove the hunk from this file diff - * @param hunk the hunk - */ - protected void remove(Hunk hunk) { - fHunks.remove(hunk); - } - - /** - * Return the hunks associated with this file diff. - * @return the hunks associated with this file diff - */ - public Hunk[] getHunks() { - return (Hunk[]) fHunks.toArray(new Hunk[fHunks.size()]); - } - - /** - * Return the number of hunks associated with this file diff. - * @return the number of hunks associated with this file diff - */ - public int getHunkCount() { - return fHunks.size(); - } - - /** - * Return the difference type of this file diff. - * @param reverse whether the patch is being reversed - * @return the type of this file diff - */ - public int getDiffType(boolean reverse) { - if (fHunks.size() == 1) { - boolean add = false; - boolean delete = false; - Iterator iter = fHunks.iterator(); - while (iter.hasNext()){ - Hunk hunk = (Hunk) iter.next(); - int type =hunk.getHunkType(reverse); - if (type == ADDITION){ - add = true; - } else if (type == DELETION ){ - delete = true; - } - } - if (add && !delete){ - return ADDITION; - } else if (!add && delete){ - return DELETION; - } - } - return CHANGE; - } - - /** - * Return the path of this file diff with the specified number - * of leading segments striped. - * @param strip the number of leading segments to strip from the path - * @param reverse whether the patch is being reversed - * @return the path of this file diff with the specified number - * of leading segments striped - */ - protected IPath getStrippedPath(int strip, boolean reverse) { - IPath path= getPath(reverse); - if (strip > 0 && strip < path.segmentCount()) - path= path.removeFirstSegments(strip); - return path; - } - - /** - * Return the segment count of the path of this file diff. - * @return the segment count of the path of this file diff - */ - public int segmentCount() { - //Update prefix count - go through all of the diffs and find the smallest - //path segment contained in all diffs. - int length= 99; - if (fOldPath != null) - length= Math.min(length, fOldPath.segmentCount()); - if (fNewPath != null) - length= Math.min(length, fNewPath.segmentCount()); - return length; - } - - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor) { - FileDiffResult result = new FileDiffResult(this, configuration); - result.refresh(contents, monitor); - return result; - } - - public IPath getTargetPath(PatchConfiguration configuration) { - return getStrippedPath(configuration.getPrefixSegmentStripCount(), configuration.isReversed()); - } - - public FileDiff asRelativeDiff() { - if (fProject == null) - return this; - IPath adjustedOldPath = null; - if (fOldPath != null) { - adjustedOldPath = new Path(null, fProject.getName()).append(fOldPath); - } - IPath adjustedNewPath = null; - if (fNewPath != null) { - adjustedNewPath = new Path(null, fProject.getName()).append(fNewPath); - } - FileDiff diff = new FileDiff(adjustedOldPath, 0, adjustedNewPath, 0); - for (Iterator iterator = fHunks.iterator(); iterator.hasNext();) { - Hunk hunk = (Hunk) iterator.next(); - // Creating the hunk adds it to the parent diff - new Hunk(diff, hunk); - } - return diff; - } - - public void setHeader(String header) { - this.header = header; - } - - public String getHeader() { - return header; - } - - public long getBeforeDate() { - return oldDate; - } - - public long getAfterDate() { - return newDate; - } - - public void setAddedLines(int addedLines) { - this.addedLines = addedLines; - } - - public void setRemovedLines(int removedLines) { - this.removedLines = removedLines; - } - - public int getAddedLines() { - return addedLines; - } - - public int getRemovedLines() { - return removedLines; - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiffResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiffResult.java deleted file mode 100644 index 1d3d74d4b..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/FileDiffResult.java +++ /dev/null @@ -1,335 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.compare.internal.core.Activator; -import org.eclipse.compare.internal.core.Messages; -import org.eclipse.compare.patch.IFilePatchResult; -import org.eclipse.compare.patch.IHunk; -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.osgi.util.NLS; - -public class FileDiffResult implements IFilePatchResult { - - private FileDiff fDiff; - private boolean fMatches= false; - private boolean fDiffProblem; - private String fErrorMessage; - private Map fHunkResults = new HashMap(); - private List fBeforeLines, fAfterLines; - private final PatchConfiguration configuration; - private String charset; - - public FileDiffResult(FileDiff diff, PatchConfiguration configuration) { - super(); - fDiff = diff; - this.configuration = configuration; - } - - public PatchConfiguration getConfiguration() { - return configuration; - } - - public boolean canApplyHunk(Hunk hunk) { - HunkResult result = getHunkResult(hunk); - return result.isOK() && !fDiffProblem; - } - - /** - * Refreshes the state of the diff to {no matches, no problems} and checks to see what hunks contained - * by this Diff can actually be applied. - * - * Checks to see: - * 1) if the target file specified in fNewPath exists and is patchable - * 2) which hunks contained by this diff can actually be applied to the file - * @param storage the contents being patched or null for an addition - * @param monitor a progress monitor or null if no progress monitoring is desired - */ - public void refresh(IStorage storage, IProgressMonitor monitor) { - fMatches= false; - fDiffProblem= false; - boolean create= false; - charset = Utilities.getCharset(storage); - //If this diff is an addition, make sure that it doesn't already exist - boolean exists = targetExists(storage); - if (fDiff.getDiffType(getConfiguration().isReversed()) == FileDiff.ADDITION) { - if ((!exists || isEmpty(storage)) && canCreateTarget(storage)) { - fMatches= true; - } else { - // file already exists - fDiffProblem= true; - fErrorMessage= Messages.FileDiffResult_0; - } - create= true; - } else { //This diff is not an addition, try to find a match for it - //Ensure that the file described by the path exists and is modifiable - if (exists) { - fMatches= true; - } else { - // file doesn't exist - fDiffProblem= true; - fErrorMessage= Messages.FileDiffResult_1; - } - } - - if (fDiffProblem) { - // We couldn't find the target file or the patch is trying to add a - // file that already exists but we need to initialize the hunk - // results for display - fBeforeLines = new ArrayList(getLines(storage, false)); - fAfterLines = fMatches ? new ArrayList() : fBeforeLines; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setMatches(false); - } - } else { - // If this diff has no problems discovered so far, try applying the patch - patch(getLines(storage, create), monitor); - } - - if (containsProblems()) { - if (fMatches) { - // Check to see if we have at least one hunk that matches - fMatches = false; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - if (result.isOK()) { - fMatches = true; - break; - } - } - } - } - } - - protected boolean canCreateTarget(IStorage storage) { - return true; - } - - protected boolean targetExists(IStorage storage) { - return storage != null; - } - - protected List getLines(IStorage storage, boolean create) { - List lines = Patcher.load(storage, create); - return lines; - } - - protected boolean isEmpty(IStorage storage) { - if (storage == null) - return true; - return Patcher.load(storage, false).isEmpty(); - } - - /* - * Tries to patch the given lines with the specified Diff. - * Any hunk that couldn't be applied is returned in the list failedHunks. - */ - public void patch(List lines, IProgressMonitor monitor) { - fBeforeLines = new ArrayList(); - fBeforeLines.addAll(lines); - if (getConfiguration().getFuzz() != 0) { - calculateFuzz(fBeforeLines, monitor); - } - int shift= 0; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setShift(shift); - if (result.patch(lines)) { - shift = result.getShift(); - } - } - fAfterLines = lines; - } - - public boolean getDiffProblem() { - return fDiffProblem; - } - - /** - * Returns whether this Diff has any problems - * @return true if this Diff or any of its children Hunks have a problem, false if it doesn't - */ - public boolean containsProblems() { - if (fDiffProblem) - return true; - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - return true; - } - return false; - } - - public String getLabel() { - String label= getTargetPath().toString(); - if (this.fDiffProblem) - return NLS.bind(Messages.FileDiffResult_2, new String[] {label, fErrorMessage}); - return label; - } - - public boolean hasMatches() { - return fMatches; - } - - /** - * Return the lines of the target file with all matched hunks applied. - * @return the lines of the target file with all matched hunks applied - */ - public List getLines() { - return fAfterLines; - } - - /** - * Calculate the fuzz factor that will allow the most hunks to be matched. - * @param lines the lines of the target file - * @param monitor a progress monitor - * @return the fuzz factor or -1 if no hunks could be matched - */ - public int calculateFuzz(List lines, IProgressMonitor monitor) { - if (monitor == null) - monitor = new NullProgressMonitor(); - fBeforeLines = new ArrayList(lines); - // TODO: What about deletions? - if (fDiff.getDiffType(getConfiguration().isReversed()) == FileDiff.ADDITION) { - // Additions don't need to adjust the fuzz factor - // TODO: What about the after lines? - return -1; - } - int shift= 0; - int highestFuzz = -1; // the maximum fuzz factor for all hunks - String name = getTargetPath() != null ? getTargetPath().lastSegment() : ""; //$NON-NLS-1$ - Hunk[] hunks = fDiff.getHunks(); - for (int j = 0; j < hunks.length; j++) { - Hunk h = hunks[j]; - monitor.subTask(NLS.bind(Messages.FileDiffResult_3, new String[] {name, Integer.toString(j + 1)})); - HunkResult result = getHunkResult(h); - result.setShift(shift); - int fuzz = result.calculateFuzz(lines, monitor); - shift = result.getShift(); - if (fuzz > highestFuzz) - highestFuzz = fuzz; - monitor.worked(1); - } - fAfterLines = lines; - return highestFuzz; - } - - public IPath getTargetPath() { - return fDiff.getStrippedPath(getConfiguration().getPrefixSegmentStripCount(), getConfiguration().isReversed()); - } - - private HunkResult getHunkResult(Hunk hunk) { - HunkResult result = (HunkResult)fHunkResults.get(hunk); - if (result == null) { - result = new HunkResult(this, hunk); - fHunkResults .put(hunk, result); - } - return result; - } - - List getFailedHunks() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result.getHunk()); - } - return failedHunks; - } - - private HunkResult[] getFailedHunkResults() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result); - } - return (HunkResult[]) failedHunks.toArray(new HunkResult[failedHunks.size()]); - } - - public FileDiff getDiff() { - return fDiff; - } - - public List getBeforeLines() { - return fBeforeLines; - } - - public List getAfterLines() { - return fAfterLines; - } - - public HunkResult[] getHunkResults() { - return (HunkResult[]) fHunkResults.values().toArray(new HunkResult[fHunkResults.size()]); - } - - public InputStream getOriginalContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getBeforeLines()); - return asInputStream(contents, getCharset()); - } - - public InputStream getPatchedContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getLines()); - return asInputStream(contents, getCharset()); - } - - public String getCharset() { - return charset; - } - - public boolean isPreserveLineDelimeters() { - return false; - } - - public IHunk[] getRejects() { - return getFailedHunkResults(); - } - - public boolean hasRejects() { - return getFailedHunkResults().length > 0; - } - - public static InputStream asInputStream(String contents, String charSet) { - byte[] bytes = null; - if (charSet != null) { - try { - bytes = contents.getBytes(charSet); - } catch (UnsupportedEncodingException e) { - Activator.log(e); - } - } - if (bytes == null) { - bytes = contents.getBytes(); - } - return new ByteArrayInputStream(bytes); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Hunk.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Hunk.java deleted file mode 100644 index 6f2c41504..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Hunk.java +++ /dev/null @@ -1,446 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.runtime.Assert; - -/** - * A Hunk describes a range of changed lines and some context lines. - */ -public class Hunk { - - private FileDiff fParent; - private int fOldStart, fOldLength; - private int fNewStart, fNewLength; - private String[] fLines; - private int hunkType; - - public static Hunk createHunk(FileDiff parent, int[] oldRange, int[] newRange, List lines, boolean hasLineAdditions, boolean hasLineDeletions, boolean hasContextLines) { - int oldStart = 0; - int oldLength = 0; - int newStart = 0; - int newLength = 0; - if (oldRange[0] > 0) - oldStart= oldRange[0]-1; // line number start at 0! - else - oldStart= 0; - oldLength= oldRange[1]; - if (newRange[0] > 0) - newStart= newRange[0]-1; // line number start at 0! - else - newStart= 0; - newLength= newRange[1]; - int hunkType = FileDiff.CHANGE; - if (!hasContextLines) { - if (hasLineAdditions && !hasLineDeletions) { - hunkType = FileDiff.ADDITION; - } else if (!hasLineAdditions && hasLineDeletions) { - hunkType = FileDiff.DELETION; - } - } - return new Hunk(parent, hunkType, oldStart, oldLength, newStart, newLength, (String[]) lines.toArray(new String[lines.size()])); - } - - public Hunk(FileDiff parent, int hunkType, int oldLength, int oldStart, - int newLength, int newStart, String[] lines) { - fParent = parent; - if (fParent != null) { - fParent.add(this); - } - this.hunkType = hunkType; - fOldLength = oldLength; - fOldStart = oldStart; - fNewLength = newLength; - fNewStart = newStart; - fLines = lines; - } - - public Hunk(FileDiff parent, Hunk toCopy) { - this(parent, toCopy.hunkType, toCopy.fOldStart, toCopy.fOldLength, toCopy.fNewStart, toCopy.fNewLength, toCopy.fLines); - } - - /* - * Returns the contents of this hunk. - * Each line starts with a control character. Their meaning is as follows: - * - */ - String getContent() { - StringBuffer sb= new StringBuffer(); - for (int i= 0; i < fLines.length; i++) { - String line= fLines[i]; - sb.append(line.substring(0, Patcher.length(line))); - sb.append('\n'); - } - return sb.toString(); - } - - /* - * Returns a descriptive String for this hunk. - * It is in the form old_start,old_length -> new_start,new_length. - */ - String getDescription() { - StringBuffer sb= new StringBuffer(); - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" -> "); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - return sb.toString(); - } - - String getRejectedDescription() { - StringBuffer sb= new StringBuffer(); - sb.append("@@ -"); //$NON-NLS-1$ - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" +"); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - sb.append(" @@"); //$NON-NLS-1$ - return sb.toString(); - } - - int getHunkType(boolean reverse) { - if (reverse) { - if (hunkType == FileDiff.ADDITION) - return FileDiff.DELETION; - if (hunkType == FileDiff.DELETION) - return FileDiff.ADDITION; - } - return hunkType; - } - - void setHunkType(int hunkType) { - this.hunkType = hunkType; - } - - public String[] getLines() { - return fLines; - } - - /** - * Set the parent of this hunk. This method - * should only be invoked from {@link FileDiff#add(Hunk)} - * @param diff the parent of this hunk - */ - void setParent(FileDiff diff) { - if (fParent == diff) - return; - if (fParent != null) - fParent.remove(this); - fParent = diff; - } - - public FileDiff getParent() { - return fParent; - } - - /* - * Tries to apply the given hunk on the specified lines. - * The parameter shift is added to the line numbers given - * in the hunk. - */ - public boolean tryPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - int deleteMatches = 0; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s = fLines[i]; - Assert.isTrue(s.length() > 0); - String line = s.substring(1); - char controlChar = s.charAt(0); - - if (controlChar == ' ') { // context lines - - if (pos < 0 || pos >= lines.size()) - return false; - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - return false; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - return false; - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (pos < 0 || pos >= lines.size()) // out of the file - return false; - if (linesMatch(configuration, line, (String) lines.get(pos))) { - deleteMatches++; - pos++; - continue; // line matched, continue with the next one - } - - // We must remove all lines at once, return false if this - // fails. In other words, all lines considered for deletion - // must be found one by one. - - // if (deleteMatches <= 0) - return false; - // pos++; - } else if (isAddedDelimeter(controlChar, reverse)) { - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - return false; - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - // we don't have to do anything more for a 'try' - } else - Assert.isTrue(false, "tryPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - - // check following context lines if exist - if (!contextLinesMatched - && fuzz > 0 - && contextLines.size() > fuzz - && !checkFollowingContextLines(configuration, lines, fuzz, pos, - contextLines)) - return false; - - return true; - } - - private boolean checkPrecedingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - - // ignore from the beginning - for (int j = fuzz; j < contextLines.size(); j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - return true; - } - - private boolean checkFollowingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - if (!contextLines.isEmpty()) { - // ignore from the end - for (int j = 0; j < contextLines.size() - fuzz; j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - } - return true; - } - - int getStart(boolean reverse) { - if (reverse) { - return fNewStart; - } - return fOldStart; - } - - private int getLength(boolean reverse) { - if (reverse) { - return fNewLength; - } - return fOldLength; - } - - private int getShift(boolean reverse) { - if (reverse) { - return fOldLength - fNewLength; - } - return fNewLength - fOldLength; - } - - int doPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s= fLines[i]; - Assert.isTrue(s.length() > 0); - String line= s.substring(1); - char controlChar= s.charAt(0); - if (controlChar == ' ') { - // context lines - Assert.isTrue(pos < lines.size(), "doPatch: inconsistency in context"); //$NON-NLS-1$ - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - Assert.isTrue(false, "doPatch: context doesn't match"); //$NON-NLS-1$ -// pos++; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - lines.remove(pos); - } else if (isAddedDelimeter(controlChar, reverse)) { - // added lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (getLength(reverse) == 0 && pos+1 < lines.size()) - lines.add(pos+1, line); - else - lines.add(pos, line); - pos++; - } else - Assert.isTrue(false, "doPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - return getShift(reverse); - } - - private boolean isDeletedDelimeter(char controlChar, boolean reverse) { - return (!reverse && controlChar == '-') || (reverse && controlChar == '+'); - } - - private boolean isAddedDelimeter(char controlChar, boolean reverse) { - return (reverse && controlChar == '-') || (!reverse && controlChar == '+'); - } - - /* - * Compares two strings. - * If fIgnoreWhitespace is true whitespace is ignored. - */ - private boolean linesMatch(PatchConfiguration configuration, String line1, String line2) { - if (configuration.isIgnoreWhitespace()) - return stripWhiteSpace(line1).equals(stripWhiteSpace(line2)); - if (isIgnoreLineDelimiter()) { - int l1= Patcher.length(line1); - int l2= Patcher.length(line2); - if (l1 != l2) - return false; - return line1.regionMatches(0, line2, 0, l1); - } - return line1.equals(line2); - } - - private boolean isIgnoreLineDelimiter() { - return true; - } - - /* - * Returns the given string with all whitespace characters removed. - * Whitespace is defined by Character.isWhitespace(...). - */ - private String stripWhiteSpace(String s) { - StringBuffer sb= new StringBuffer(); - int l= s.length(); - for (int i= 0; i < l; i++) { - char c= s.charAt(i); - if (!Character.isWhitespace(c)) - sb.append(c); - } - return sb.toString(); - } - - public String getContents(boolean isAfterState, boolean reverse) { - StringBuffer result= new StringBuffer(); - for (int i= 0; i - Bug 181919 LineReader creating unneeded garbage - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.runtime.Assert; - -public class LineReader { - - private boolean fHaveChar= false; - private int fLastChar; - private boolean fSawEOF= false; - private BufferedReader fReader; - private boolean fIgnoreSingleCR= false; - private StringBuffer fBuffer= new StringBuffer(); - - public LineReader(BufferedReader reader) { - fReader= reader; - Assert.isNotNull(reader); - } - - void ignoreSingleCR() { - fIgnoreSingleCR= true; - } - - /** - * Reads a line of text. A line is considered to be terminated by any one - * of a line feed ('\n'), a carriage return ('\r'), or a carriage return - * followed immediately by a line-feed. - * @return A string containing the contents of the line including - * the line-termination characters, or null if the end of the - * stream has been reached - * @exception IOException If an I/O error occurs - */ - /* package */ String readLine() throws IOException { - try { - while (!fSawEOF) { - int c= readChar(); - if (c == -1) { - fSawEOF= true; - break; - } - fBuffer.append((char)c); - if (c == '\n') - break; - if (c == '\r') { - c= readChar(); - if (c == -1) { - fSawEOF= true; - break; // EOF - } - if (c != '\n') { - if (fIgnoreSingleCR) { - fBuffer.append((char)c); - continue; - } - fHaveChar= true; - fLastChar= c; - } else - fBuffer.append((char)c); - break; - } - } - - if (fBuffer.length() != 0) { - return fBuffer.toString(); - } - return null; - } finally { - fBuffer.setLength(0); - } - } - - /* package */ void close() { - try { - fReader.close(); - } catch (IOException ex) { - // silently ignored - } - } - - public List readLines() { - try { - List lines= new ArrayList(); - String line; - while ((line= readLine()) != null) - lines.add(line); - return lines; - } catch (IOException ex) { - // NeedWork - //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); - } finally { - close(); - } - return null; - } - - /* - * Returns the number of characters in the given string without - * counting a trailing line separator. - */ - /* package */ int lineContentLength(String line) { - if (line == null) - return 0; - int length= line.length(); - for (int i= length-1; i >= 0; i--) { - char c= line.charAt(i); - if (c =='\n' || c == '\r') - length--; - else - break; - } - return length; - } - - //---- private - - private int readChar() throws IOException { - if (fHaveChar) { - fHaveChar= false; - return fLastChar; - } - return fReader.read(); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/PatchReader.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/PatchReader.java deleted file mode 100644 index a1cb56706..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/PatchReader.java +++ /dev/null @@ -1,669 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; - -import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.SimpleDateFormat; - -public class PatchReader { - - private static final boolean DEBUG= false; - - private static final String DEV_NULL= "/dev/null"; //$NON-NLS-1$ - - protected static final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; //$NON-NLS-1$ - - // diff formats - // private static final int CONTEXT= 0; - // private static final int ED= 1; - // private static final int NORMAL= 2; - // private static final int UNIFIED= 3; - - // we recognize the following date/time formats - private DateFormat[] fDateFormats= new DateFormat[] { - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy"), //$NON-NLS-1$ - new SimpleDateFormat("yyyy/MM/dd kk:mm:ss"), //$NON-NLS-1$ - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy", Locale.US) //$NON-NLS-1$ - }; - - private boolean fIsWorkspacePatch; - private DiffProject[] fDiffProjects; - private FileDiff[] fDiffs; - - // API for writing new multi-project patch format - public static final String MULTIPROJECTPATCH_HEADER= "### Eclipse Workspace Patch"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_VERSION= "1.0"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_PROJECT= "#P"; //$NON-NLS-1$ - - /** - * Create a patch reader for the default date formats. - */ - public PatchReader() { - // nothing here - } - - /** - * Create a patch reader for the given date formats. - * - * @param dateFormats - * Array of DateFormats to be used when - * extracting dates from the patch. - */ - public PatchReader(DateFormat[] dateFormats) { - this(); - fDateFormats = dateFormats; - } - - public void parse(BufferedReader reader) throws IOException { - List diffs= new ArrayList(); - HashMap diffProjects= new HashMap(4); - String line= null; - boolean reread= false; - String diffArgs= null; - String fileName= null; - // no project means this is a single patch,create a placeholder project for now - // which will be replaced by the target selected by the user in the preview pane - String project= ""; //$NON-NLS-1$ - fIsWorkspacePatch= false; - - LineReader lr= new LineReader(reader); - lr.ignoreSingleCR(); // Don't treat single CRs as line feeds to be consistent with command line patch - - // Test for our format - line= lr.readLine(); - if (line != null && line.startsWith(PatchReader.MULTIPROJECTPATCH_HEADER)) { - fIsWorkspacePatch= true; - } else { - parse(lr, line); - return; - } - - // read leading garbage - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - if (line.length() < 4) - continue; // too short - - if (line.startsWith(PatchReader.MULTIPROJECTPATCH_PROJECT)) { - project= line.substring(2).trim(); - continue; - } - - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - continue; - } - if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - continue; - } - - if (line.startsWith("--- ")) { //$NON-NLS-1$ - // if there is no current project or - // the current project doesn't equal the newly parsed project - // reset the current project to the newly parsed one, create a new DiffProject - // and add it to the array - DiffProject diffProject; - if (!diffProjects.containsKey(project)) { - IProject iproject= ResourcesPlugin.getWorkspace().getRoot().getProject(project); - diffProject= new DiffProject(iproject); - diffProjects.put(project, diffProject); - } else { - diffProject= (DiffProject) diffProjects.get(project); - } - - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName, diffProject); - diffArgs= fileName= null; - reread= true; - } - } - - lr.close(); - - fDiffProjects= (DiffProject[]) diffProjects.values().toArray(new DiffProject[diffProjects.size()]); - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private String readUnifiedDiff(List diffs, LineReader lr, String line, String diffArgs, String fileName, DiffProject diffProject) throws IOException { - List newDiffs= new ArrayList(); - String nextLine= readUnifiedDiff(newDiffs, lr, line, diffArgs, fileName); - for (Iterator iter= newDiffs.iterator(); iter.hasNext();) { - FileDiff diff= (FileDiff) iter.next(); - diffProject.add(diff); - diffs.add(diff); - } - return nextLine; - } - - public void parse(LineReader lr, String line) throws IOException { - List diffs= new ArrayList(); - boolean reread= false; - String diffArgs= null; - String fileName= null; - List headerLines = new ArrayList(); - - // read leading garbage - reread= line!=null; - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - - // remember some infos - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - } else if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - } else if (line.startsWith("--- ")) { //$NON-NLS-1$ - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } else if (line.startsWith("*** ")) { //$NON-NLS-1$ - line= readContextDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } - - // Any lines we read here are header lines. - // However, if reread is set, we will add them to the header on the next pass through - if (!reread) { - headerLines.add(line); - } - } - - lr.close(); - - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private void setHeader(FileDiff diff, List headerLines) { - String header = Patcher.createString(false, headerLines); - diff.setHeader(header); - headerLines.clear(); - } - - /* - * Returns the next line that does not belong to this diff - */ - protected String readUnifiedDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("+++ ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List lines= new ArrayList(); - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return null; - - if (reader.lineContentLength(line) == 0) { - //System.out.println("Warning: found empty line in hunk; ignored"); - //lines.add(' ' + line); - continue; - } - - char c= line.charAt(0); - switch (c) { - case '@': - if (line.startsWith("@@ ")) { //$NON-NLS-1$ - // flush old hunk - if (lines.size() > 0) { - Hunk.createHunk(diff, oldRange, newRange, lines,encounteredPlus, encounteredMinus, encounteredSpace); - lines.clear(); - } - - // format: @@ -oldStart,oldLength +newStart,newLength @@ - extractPair(line, '-', oldRange); - extractPair(line, '+', newRange); - continue; - } - break; - case ' ': - encounteredSpace = true; - lines.add(line); - continue; - case '+': - encounteredPlus = true; - lines.add(line); - continue; - case '-': - encounteredMinus = true; - lines.add(line); - continue; - case '\\': - if (line.indexOf("newline at end") > 0) { //$NON-NLS-1$ - int lastIndex= lines.size(); - if (lastIndex > 0) { - line= (String) lines.get(lastIndex-1); - int end= line.length()-1; - char lc= line.charAt(end); - if (lc == '\n') { - end--; - if (end > 0 && line.charAt(end) == '\r') - end--; - } else if (lc == '\r') { - end--; - } - line= line.substring(0, end+1); - lines.set(lastIndex-1, line); - } - continue; - } - break; - default: - if (DEBUG) { - int a1= c, a2= 0; - if (line.length() > 1) - a2= line.charAt(1); - System.out.println("char: " + a1 + " " + a2); //$NON-NLS-1$ //$NON-NLS-2$ - } - break; - } - return line; - } - } finally { - if (lines.size() > 0) - Hunk.createHunk(diff, oldRange, newRange, lines, encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Returns the next line that does not belong to this diff - */ - private String readContextDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("--- ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List oldLines= new ArrayList(); - List newLines= new ArrayList(); - List lines= oldLines; - - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return line; - - int l= line.length(); - if (l == 0) - continue; - if (l > 1) { - switch (line.charAt(0)) { - case '*': - if (line.startsWith("***************")) { // new hunk //$NON-NLS-1$ - // flush old hunk - if (oldLines.size() > 0 || newLines.size() > 0) { - Hunk.createHunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - oldLines.clear(); - newLines.clear(); - } - continue; - } - if (line.startsWith("*** ")) { // old range //$NON-NLS-1$ - // format: *** oldStart,oldEnd *** - extractPair(line, ' ', oldRange); - oldRange[1]= oldRange[1]-oldRange[0]+1; - lines= oldLines; - continue; - } - break; - case ' ': // context line - if (line.charAt(1) == ' ') { - lines.add(line); - continue; - } - break; - case '+': // addition - if (line.charAt(1) == ' ') { - encounteredPlus = true; - lines.add(line); - continue; - } - break; - case '!': // change - if (line.charAt(1) == ' ') { - encounteredSpace = true; - lines.add(line); - continue; - } - break; - case '-': - if (line.charAt(1) == ' ') { // deletion - encounteredMinus = true; - lines.add(line); - continue; - } - if (line.startsWith("--- ")) { // new range //$NON-NLS-1$ - // format: *** newStart,newEnd *** - extractPair(line, ' ', newRange); - newRange[1]= newRange[1]-newRange[0]+1; - lines= newLines; - continue; - } - break; - default: - break; - } - } - return line; - } - } finally { - // flush last hunk - if (oldLines.size() > 0 || newLines.size() > 0) - Hunk.createHunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Creates a List of lines in the unified format from - * two Lists of lines in the 'classic' format. - */ - private List unifyLines(List oldLines, List newLines) { - List result= new ArrayList(); - - String[] ol= (String[]) oldLines.toArray(new String[oldLines.size()]); - String[] nl= (String[]) newLines.toArray(new String[newLines.size()]); - - int oi= 0, ni= 0; - - while (true) { - - char oc= 0; - String o= null; - if (oi < ol.length) { - o= ol[oi]; - oc= o.charAt(0); - } - - char nc= 0; - String n= null; - if (ni < nl.length) { - n= nl[ni]; - nc= n.charAt(0); - } - - // EOF - if (oc == 0 && nc == 0) - break; - - // deletion in old - if (oc == '-') { - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '-'); - continue; - } - - // addition in new - if (nc == '+') { - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '+'); - continue; - } - - // differing lines on both sides - if (oc == '!' && nc == '!') { - // remove old - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '!'); - - // add new - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '!'); - - continue; - } - - // context lines - if (oc == ' ' && nc == ' ') { - do { - Assert.isTrue(o.equals(n), "non matching context lines"); //$NON-NLS-1$ - result.add(' ' + o.substring(2)); - oi++; - ni++; - if (oi >= ol.length || ni >= nl.length) - break; - o= ol[oi]; - n= nl[ni]; - } while (o.charAt(0) == ' ' && n.charAt(0) == ' '); - continue; - } - - if (oc == ' ') { - do { - result.add(' ' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == ' '); - continue; - } - - if (nc == ' ') { - do { - result.add(' ' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == ' '); - continue; - } - - Assert.isTrue(false, "unexpected char <" + oc + "> <" + nc + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - return result; - } - - /* - * @return the parsed time/date in milliseconds or IFilePatch.DATE_UNKNOWN - * (0) on error - */ - private long extractDate(String[] args, int n) { - if (n < args.length) { - String line= args[n]; - for (int i= 0; i < fDateFormats.length; i++) { - fDateFormats[i].setLenient(true); - try { - Date date= fDateFormats[i].parse(line); - return date.getTime(); - } catch (ParseException ex) { - // silently ignored - } - } - // System.err.println("can't parse date: <" + line + ">"); - } - return IFilePatch.DATE_UNKNOWN; - } - - /* - * Returns null if file name is "/dev/null". - */ - private IPath extractPath(String[] args, int n, String path2) { - if (n < args.length) { - String path= args[n]; - if (DEV_NULL.equals(path)) - return null; - int pos= path.lastIndexOf(':'); - if (pos >= 0) - path= path.substring(0, pos); - if (path2 != null && !path2.equals(path)) { - if (DEBUG) System.out.println("path mismatch: " + path2); //$NON-NLS-1$ - path= path2; - } - return new Path(path); - } - return null; - } - - /* - * Tries to extract two integers separated by a comma. - * The parsing of the line starts at the position after - * the first occurrence of the given character start an ends - * at the first blank (or the end of the line). - * If only a single number is found this is assumed to be the start of a one line range. - * If an error occurs the range -1,-1 is returned. - */ - private void extractPair(String line, char start, int[] pair) { - pair[0]= pair[1]= -1; - int startPos= line.indexOf(start); - if (startPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find \'" + start + "\'"); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - line= line.substring(startPos+1); - int endPos= line.indexOf(' '); - if (endPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find end blank"); //$NON-NLS-1$ - return; - } - line= line.substring(0, endPos); - int comma= line.indexOf(','); - if (comma >= 0) { - pair[0]= Integer.parseInt(line.substring(0, comma)); - pair[1]= Integer.parseInt(line.substring(comma+1)); - } else { // abbreviated form for one line patch - pair[0]= Integer.parseInt(line); - pair[1]= 1; - } - } - - - /* - * Breaks the given string into tab separated substrings. - * Leading and trailing whitespace is removed from each token. - */ - private String[] split(String line) { - List l= new ArrayList(); - StringTokenizer st= new StringTokenizer(line, "\t"); //$NON-NLS-1$ - while (st.hasMoreElements()) { - String token= st.nextToken().trim(); - if (token.length() > 0) - l.add(token); - } - return (String[]) l.toArray(new String[l.size()]); - } - - public boolean isWorkspacePatch() { - return fIsWorkspacePatch; - } - - public DiffProject[] getDiffProjects() { - return fDiffProjects; - } - - public FileDiff[] getDiffs() { - return fDiffs; - } - - public FileDiff[] getAdjustedDiffs() { - if (!isWorkspacePatch() || fDiffs.length == 0) - return fDiffs; - List result = new ArrayList(); - for (int i = 0; i < fDiffs.length; i++) { - FileDiff diff = fDiffs[i]; - result.add(diff.asRelativeDiff()); - } - return (FileDiff[]) result.toArray(new FileDiff[result.size()]); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Patcher.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Patcher.java deleted file mode 100644 index caf2dcafc..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Patcher.java +++ /dev/null @@ -1,877 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Martin Burger patch for #93810 and #93901 - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.compare.internal.core.Activator; -import org.eclipse.compare.internal.core.Messages; -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.SubProgressMonitor; - -/** - * A Patcher - * - knows how to parse various patch file formats into some in-memory structure, - * - holds onto the parsed data and the options to use when applying the patches, - * - knows how to apply the patches to files and folders. - */ -public class Patcher { - - static protected final String REJECT_FILE_EXTENSION= ".rej"; //$NON-NLS-1$ - - static protected final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; //$NON-NLS-1$ - - /** - * Property used to associate a patcher with a {@link PatchConfiguration} - */ - public static final String PROP_PATCHER = "org.eclipse.compare.patcher"; //$NON-NLS-1$ - - public interface IFileValidator { - boolean validateResources(IFile[] array); - } - - // diff formats - // private static final int CONTEXT= 0; - // private static final int ED= 1; - // private static final int NORMAL= 2; - // private static final int UNIFIED= 3; - - private FileDiff[] fDiffs; - private IResource fTarget; - // patch options - private Set disabledElements = new HashSet(); - private Map diffResults = new HashMap(); - private final Map contentCache = new HashMap(); - private Set mergedHunks = new HashSet(); - - private final PatchConfiguration configuration; - private boolean fGenerateRejectFile = false; - - public Patcher() { - configuration = new PatchConfiguration(); - configuration.setProperty(PROP_PATCHER, this); - } - - /* - * Returns an array of Diffs after a sucessfull call to parse. - * If parse hasn't been called returns null. - */ - public FileDiff[] getDiffs() { - if (fDiffs == null) - return new FileDiff[0]; - return fDiffs; - } - - public IPath getPath(FileDiff diff) { - return diff.getStrippedPath(getStripPrefixSegments(), isReversed()); - } - - /* - * Returns true if new value differs from old. - */ - public boolean setStripPrefixSegments(int strip) { - if (strip != getConfiguration().getPrefixSegmentStripCount()) { - getConfiguration().setPrefixSegmentStripCount(strip); - return true; - } - return false; - } - - int getStripPrefixSegments() { - return getConfiguration().getPrefixSegmentStripCount(); - } - - /* - * Returns true if new value differs from old. - */ - public boolean setFuzz(int fuzz) { - if (fuzz != getConfiguration().getFuzz()) { - getConfiguration().setFuzz(fuzz); - return true; - } - return false; - } - - public int getFuzz(){ - return getConfiguration().getFuzz(); - } - - /* - * Returns true if new value differs from old. - */ - public boolean setIgnoreWhitespace(boolean ignoreWhitespace) { - if (ignoreWhitespace != getConfiguration().isIgnoreWhitespace()) { - getConfiguration().setIgnoreWhitespace(ignoreWhitespace); - return true; - } - return false; - } - - public boolean isIgnoreWhitespace() { - return getConfiguration().isIgnoreWhitespace(); - } - - public boolean isGenerateRejectFile() { - return fGenerateRejectFile; - } - - public void setGenerateRejectFile(boolean generateRejectFile) { - fGenerateRejectFile = generateRejectFile; - } - - //---- parsing patch files - - public void parse(IStorage storage) throws IOException, CoreException { - BufferedReader reader = createReader(storage); - try { - parse(reader); - } finally { - try { - reader.close(); - } catch (IOException e) { //ignored - } - } - } - - public static BufferedReader createReader(IStorage storage) throws CoreException { - String charset = null; - if (storage instanceof IEncodedStorage) { - IEncodedStorage es = (IEncodedStorage) storage; - charset = es.getCharset(); - } - InputStreamReader in = null; - if (charset != null) { - InputStream contents = storage.getContents(); - try { - in = new InputStreamReader(contents, charset); - } catch (UnsupportedEncodingException e) { - Activator.log(e); - try { - contents.close(); - } catch (IOException e1) { - // Ignore - } - } - } - if (in == null) { - in = new InputStreamReader(storage.getContents()); - } - return new BufferedReader(in); - } - - public void parse(BufferedReader reader) throws IOException { - PatchReader patchReader= new PatchReader(); - patchReader.parse(reader); - patchParsed(patchReader); - } - - protected void patchParsed(PatchReader patchReader) { - fDiffs = patchReader.getDiffs(); - } - - public void countLines() { - FileDiff[] fileDiffs = getDiffs(); - for (int i = 0; i < fileDiffs.length; i++) { - int addedLines = 0; - int removedLines = 0; - FileDiff fileDiff = fileDiffs[i]; - for (int j = 0; j < fileDiff.getHunkCount(); j++) { - Hunk hunk = fileDiff.getHunks()[j]; - String[] lines = hunk.getLines(); - for (int k = 0; k < lines.length; k++) { - char c = lines[k].charAt(0); - switch (c) { - case '+': - addedLines++; - continue; - case '-': - removedLines++; - continue; - } - } - } - fileDiff.setAddedLines(addedLines); - fileDiff.setRemovedLines(removedLines); - } - } - - //---- applying a patch file - - public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { - - int i; - - IFile singleFile= null; // file to be patched - IContainer container= null; - if (fTarget instanceof IContainer) - container= (IContainer) fTarget; - else if (fTarget instanceof IFile) { - singleFile= (IFile) fTarget; - container= singleFile.getParent(); - } else { - Assert.isTrue(false); - } - - // get all files to be modified in order to call validateEdit - List list= new ArrayList(); - if (singleFile != null) - list.add(singleFile); - else { - for (i= 0; i < fDiffs.length; i++) { - FileDiff diff= fDiffs[i]; - if (isEnabled(diff)) { - switch (diff.getDiffType(isReversed())) { - case FileDiff.CHANGE: - list.add(createPath(container, getPath(diff))); - break; - } - } - } - } - if (! validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { - return; - } - - final int WORK_UNIT= 10; - if (pm != null) { - String message= Messages.Patcher_0; - pm.beginTask(message, fDiffs.length*WORK_UNIT); - } - - for (i= 0; i < fDiffs.length; i++) { - - int workTicks= WORK_UNIT; - - FileDiff diff= fDiffs[i]; - if (isEnabled(diff)) { - - IPath path= getPath(diff); - if (pm != null) - pm.subTask(path.toString()); - - IFile file= singleFile != null - ? singleFile - : createPath(container, path); - - List failed= new ArrayList(); - - int type= diff.getDiffType(isReversed()); - switch (type) { - case FileDiff.ADDITION: - // patch it and collect rejected hunks - List result= apply(diff, file, true, failed); - if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); - workTicks-= WORK_UNIT; - break; - case FileDiff.DELETION: - file.delete(true, true, new SubProgressMonitor(pm, workTicks)); - workTicks-= WORK_UNIT; - break; - case FileDiff.CHANGE: - // patch it and collect rejected hunks - result= apply(diff, file, false, failed); - if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); - workTicks-= WORK_UNIT; - break; - } - - if (isGenerateRejectFile() && failed.size() > 0) { - IPath pp = getRejectFilePath(path); - file= createPath(container, pp); - if (file != null) { - store(getRejected(failed), file, pm); - try { - IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, Messages.Patcher_1); - marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); - } catch (CoreException ex) { - // NeedWork - } - } - } - } - - if (pm != null) { - if (pm.isCanceled()) - break; - if (workTicks > 0) - pm.worked(workTicks); - } - } - } - - private IPath getRejectFilePath(IPath path) { - IPath pp= null; - if (path.segmentCount() > 1) { - pp= path.removeLastSegments(1); - pp= pp.append(path.lastSegment() + REJECT_FILE_EXTENSION); - } else - pp= new Path(path.lastSegment() + REJECT_FILE_EXTENSION); - return pp; - } - - /* - * Reads the contents from the given file and returns them as - * a List of lines. - */ - public static List load(IStorage file, boolean create) { - List lines= null; - if (!create && file != null && exists(file)) { - // read current contents - String charset = Utilities.getCharset(file); - InputStream is= null; - try { - is= file.getContents(); - - Reader streamReader= null; - try { - streamReader= new InputStreamReader(is, charset); - } catch (UnsupportedEncodingException x) { - // use default encoding - streamReader= new InputStreamReader(is); - } - - BufferedReader reader= new BufferedReader(streamReader); - lines = readLines(reader); - } catch(CoreException ex) { - // TODO - Activator.log(ex); - } finally { - if (is != null) - try { - is.close(); - } catch(IOException ex) { - // silently ignored - } - } - } - - if (lines == null) - lines= new ArrayList(); - return lines; - } - - private static boolean exists(IStorage file) { - if (file instanceof IFile) { - return ((IFile) file).exists(); - } - return true; - } - - private static List readLines(BufferedReader reader) { - List lines; - LineReader lr= new LineReader(reader); - lr.ignoreSingleCR(); // Don't treat single CRs as line feeds to be consistent with command line patch - lines= lr.readLines(); - return lines; - } - - List apply(FileDiff diff, IFile file, boolean create, List failedHunks) { - FileDiffResult result = getDiffResult(diff); - List lines = Patcher.load(file, create); - result.patch(lines, null); - failedHunks.addAll(result.getFailedHunks()); - if (hasCachedContents(diff)) { - // Used the cached contents since they would have been provided by the user - return getCachedLines(diff); - } else if (!result.hasMatches()) { - // Return null if there were no matches - return null; - } - return result.getLines(); - } - - /* - * Converts the string into bytes and stores them in the given file. - */ - protected void store(String contents, IFile file, IProgressMonitor pm) throws CoreException { - - byte[] bytes; - try { - bytes= contents.getBytes(Utilities.getCharset(file)); - } catch (UnsupportedEncodingException x) { - // uses default encoding - bytes= contents.getBytes(); - } - - store(bytes,file, pm); - } - - protected void store(byte[] bytes, IFile file, IProgressMonitor pm) throws CoreException { - InputStream is= new ByteArrayInputStream(bytes); - try { - if (file.exists()) { - file.setContents(is, false, true, pm); - } else { - file.create(is, false, pm); - } - } finally { - if (is != null) - try { - is.close(); - } catch(IOException ex) { - // silently ignored - } - } - } - - - - /* - * Concatenates all strings found in the given List. - */ - public static String createString(boolean preserveLineDelimeters, List lines) { - StringBuffer sb= new StringBuffer(); - Iterator iter= lines.iterator(); - if (preserveLineDelimeters) { - while (iter.hasNext()) - sb.append((String)iter.next()); - } else { - String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ - while (iter.hasNext()) { - String line= (String)iter.next(); - int l= length(line); - if (l < line.length()) { // line has delimiter - sb.append(line.substring(0, l)); - sb.append(lineSeparator); - } else { - sb.append(line); - } - } - } - return sb.toString(); - } - - public boolean isPreserveLineDelimeters() { - return false; - } - - public static String getRejected(List failedHunks) { - if (failedHunks.size() <= 0) - return null; - - String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ - StringBuffer sb= new StringBuffer(); - Iterator iter= failedHunks.iterator(); - while (iter.hasNext()) { - Hunk hunk= (Hunk) iter.next(); - sb.append(hunk.getRejectedDescription()); - sb.append(lineSeparator); - sb.append(hunk.getContent()); - } - return sb.toString(); - } - - /* - * Ensures that a file with the given path exists in - * the given container. Folder are created as necessary. - */ - protected IFile createPath(IContainer container, IPath path) throws CoreException { - if (path.segmentCount() > 1) { - IContainer childContainer; - if (container instanceof IWorkspaceRoot) { - IProject project = ((IWorkspaceRoot)container).getProject(path.segment(0)); - if (!project.exists()) - project.create(null); - if (!project.isOpen()) - project.open(null); - childContainer = project; - } else { - IFolder f= container.getFolder(path.uptoSegment(1)); - if (!f.exists()) - f.create(false, true, null); - childContainer = f; - } - return createPath(childContainer, path.removeFirstSegments(1)); - } - // a leaf - return container.getFile(path); - } - - /* - * Returns the length (excluding a line delimiter CR, LF, CR/LF) - * of the given string. - */ - /* package */ static int length(String s) { - int l= s.length(); - if (l > 0) { - char c= s.charAt(l-1); - if (c == '\r') - return l-1; - if (c == '\n') { - if (l > 1 && s.charAt(l-2) == '\r') - return l-2; - return l-1; - } - } - return l; - } - - public IResource getTarget() { - return fTarget; - } - - public void setTarget(IResource target) { - fTarget= target; - } - - - public IFile getTargetFile(FileDiff diff) { - IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); - return existsInTarget(path); - } - - /** - * Iterates through all of the resources contained in the Patch Wizard target - * and looks to for a match to the passed in file - * @param path - * @return IFile which matches the passed in path or null if none found - */ - public IFile existsInTarget(IPath path) { - if (fTarget instanceof IFile) { // special case - IFile file= (IFile) fTarget; - if (matches(file.getFullPath(), path)) - return file; - } else if (fTarget instanceof IContainer) { - IContainer c= (IContainer) fTarget; - if (c.exists(path)) - return c.getFile(path); - } - return null; - } - - /** - * Returns true if path completely matches the end of fullpath - * @param fullpath - * @param path - * @return true if path matches, false otherwise - */ - private boolean matches(IPath fullpath, IPath path) { - for (IPath p= fullpath; path.segmentCount()<=p.segmentCount(); p= p.removeFirstSegments(1)) { - if (p.equals(path)) - return true; - } - return false; - } - - public int calculatePrefixSegmentCount() { - //Update prefix count - go through all of the diffs and find the smallest - //path segment contained in all diffs. - int length= 99; - if (fDiffs!=null) - for (int i= 0; i-1 if no hunks could be matched - */ - public int guessFuzzFactor(IProgressMonitor monitor) { - try { - monitor.beginTask(Messages.Patcher_2, IProgressMonitor.UNKNOWN); - FileDiff[] diffs= getDiffs(); - if (diffs==null||diffs.length<=0) - return -1; - int fuzz= -1; - for (int i= 0; i fuzz) - fuzz = f; - } - } - return fuzz; - } finally { - monitor.done(); - } - } - - public void refresh() { - diffResults.clear(); - refresh(getDiffs()); - } - - protected void refresh(FileDiff[] diffs) { - for (int i = 0; i < diffs.length; i++) { - FileDiff diff = diffs[i]; - FileDiffResult result = getDiffResult(diff); - ((WorkspaceFileDiffResult)result).refresh(); - } - } - - public FileDiffResult getDiffResult(FileDiff diff) { - FileDiffResult result = (FileDiffResult)diffResults.get(diff); - if (result == null) { - result = new WorkspaceFileDiffResult(diff, getConfiguration()); - diffResults.put(diff, result); - } - return result; - } - - public PatchConfiguration getConfiguration() { - return configuration; - } - - /** - * Return the project that contains this diff or null - * if the patch is not a workspace patch. - * @param diff the diff - * @return the project that contains the diff - */ - public DiffProject getProject(FileDiff diff) { - return diff.getProject(); - } - - /* - * Returns true if new value differs from old. - */ - public boolean setReversed(boolean reverse) { - if (getConfiguration().isReversed() != reverse) { - getConfiguration().setReversed(reverse); - refresh(); - return true; - } - return false; - } - - public boolean isReversed() { - return getConfiguration().isReversed(); - } - - /** - * Cache the contents for the given file diff. These contents - * will be used for the diff when the patch is applied. When the - * patch is applied, it is assumed that the provided contents - * already have all relevant hunks applied. - * @param diff the file diff - * @param contents the contents for the file diff - */ - public void cacheContents(FileDiff diff, byte[] contents) { - contentCache.put(diff, contents); - } - - /** - * Return whether contents have been cached for the - * given file diff. - * @param diff the file diff - * @return whether contents have been cached for the file diff - * @see #cacheContents(FileDiff, byte[]) - */ - public boolean hasCachedContents(FileDiff diff) { - return contentCache.containsKey(diff); - } - - /** - * Return the content lines that are cached for the given - * file diff. - * @param diff the file diff - * @return the content lines that are cached for the file diff - */ - public List getCachedLines(FileDiff diff) { - byte[] contents = (byte[])contentCache.get(diff); - if (contents != null) { - BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contents))); - return readLines(reader); - } - return null; - } - - /** - * Return the contents that are cached for the given diff or - * null if there is no contents cached. - * @param diff the diff - * @return the contents that are cached for the given diff or - * null - */ - public byte[] getCachedContents(FileDiff diff) { - return (byte[])contentCache.get(diff); - } - - /** - * Return whether the patcher has any cached contents. - * @return whether the patcher has any cached contents - */ - public boolean hasCachedContents() { - return !contentCache.isEmpty(); - } - - /** - * Clear any cached contents. - */ - public void clearCachedContents() { - contentCache.clear(); - mergedHunks.clear(); - } - - public void setProperty(String key, Object value) { - getConfiguration().setProperty(key, value); - } - - public Object getProperty(String key) { - return getConfiguration().getProperty(key); - } - - public boolean isManuallyMerged(Hunk hunk) { - return mergedHunks.contains(hunk); - } - - public void setManuallyMerged(Hunk hunk, boolean merged) { - if (merged) - mergedHunks.add(hunk); - else - mergedHunks.remove(hunk); - } - - public IProject getTargetProject(FileDiff diff) { - DiffProject dp = getProject(diff); - if (dp != null) - return dp.getProject(); - IResource tr = getTarget(); - if (tr instanceof IWorkspaceRoot) { - IWorkspaceRoot root = (IWorkspaceRoot) tr; - return root.getProject(diff.getPath(isReversed()).segment(0)); - } - return tr.getProject(); - } - - public static Patcher getPatcher(PatchConfiguration configuration) { - return (Patcher)configuration.getProperty(PROP_PATCHER); - } - - public boolean hasRejects() { - for (Iterator iterator = diffResults.values().iterator(); iterator.hasNext();) { - FileDiffResult result = (FileDiffResult) iterator.next(); - if (result.hasRejects()) - return true; - } - return false; - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Utilities.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Utilities.java deleted file mode 100644 index 291fcfea9..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/Utilities.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import org.eclipse.compare.internal.core.Activator; -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; - -public class Utilities { - - public static String getCharset(Object resource) { - if (resource instanceof IEncodedStorage) { - try { - return ((IEncodedStorage)resource).getCharset(); - } catch (CoreException ex) { - Activator.log(ex); - } - } - return ResourcesPlugin.getEncoding(); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java deleted file mode 100644 index c0690416a..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.List; - -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.*; - -public class WorkspaceFileDiffResult extends FileDiffResult { - - public WorkspaceFileDiffResult(FileDiff diff, - PatchConfiguration configuration) { - super(diff, configuration); - } - - protected boolean canCreateTarget(IStorage storage) { - IProject project = getPatcher().getTargetProject(getDiff()); - return project != null && project.isAccessible(); - } - - protected boolean targetExists(IStorage storage) { - IFile file= (IFile)storage; - return file != null && file.isAccessible(); - } - - protected List getLines(IStorage storage, boolean create) { - IFile file= getTargetFile(); - List lines = Patcher.load(file, create); - return lines; - } - - protected Patcher getPatcher() { - return Patcher.getPatcher(getConfiguration()); - } - - public IFile getTargetFile() { - return getPatcher().getTargetFile(getDiff()); - } - - public void refresh() { - refresh(getTargetFile(), null); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspacePatcher.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspacePatcher.java deleted file mode 100644 index 331e30023..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/internal/patch/WorkspacePatcher.java +++ /dev/null @@ -1,377 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.compare.internal.core.Messages; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceRuleFactory; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.runtime.jobs.MultiRule; - -/** - * A Patcher - * - knows how to parse various patch file formats into some in-memory structure, - * - holds onto the parsed data and the options to use when applying the patches, - * - knows how to apply the patches to files and folders. - */ -public class WorkspacePatcher extends Patcher { - - private DiffProject[] fDiffProjects; - private boolean fIsWorkspacePatch= false; - private final Map retargetedDiffs = new HashMap(); - - public WorkspacePatcher() { - // nothing to do - } - - public WorkspacePatcher(IResource target) { - setTarget(target); - } - - protected void patchParsed(PatchReader patchReader) { - super.patchParsed(patchReader); - fDiffProjects = patchReader.getDiffProjects(); - fIsWorkspacePatch = patchReader.isWorkspacePatch(); - } - - public DiffProject[] getDiffProjects() { - return fDiffProjects; - } - - public boolean isWorkspacePatch() { - return fIsWorkspacePatch; - } - - //---- parsing patch files - - public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { - if (!fIsWorkspacePatch) { - super.applyAll(pm, validator); - } else { - final int WORK_UNIT= 10; - - // get all files to be modified in order to call validateEdit - List list= new ArrayList(); - for (int j= 0; j < fDiffProjects.length; j++) { - DiffProject diffProject= fDiffProjects[j]; - if (diffProject.getProject().isAccessible()) - list.addAll(Arrays.asList(getTargetFiles(diffProject))); - } - // validate the files for editing - if (!validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { - return; - } - - FileDiff[] diffs = getDiffs(); - if (pm != null) { - String message= Messages.WorkspacePatcher_0; - pm.beginTask(message, diffs.length * WORK_UNIT); - } - - for (int i= 0; i < diffs.length; i++) { - - int workTicks= WORK_UNIT; - - FileDiff diff= diffs[i]; - if (isAccessible(diff)) { - IFile file= getTargetFile(diff); - IPath path= file.getProjectRelativePath(); - if (pm != null) - pm.subTask(path.toString()); - createPath(file.getProject(), path); - - List failed= new ArrayList(); - - int type= diff.getDiffType(isReversed()); - switch (type) { - case FileDiff.ADDITION : - // patch it and collect rejected hunks - List result= apply(diff, file, true, failed); - if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); - workTicks -= WORK_UNIT; - break; - case FileDiff.DELETION : - file.delete(true, true, new SubProgressMonitor(pm, workTicks)); - workTicks -= WORK_UNIT; - break; - case FileDiff.CHANGE : - // patch it and collect rejected hunks - result= apply(diff, file, false, failed); - if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); - workTicks -= WORK_UNIT; - break; - } - - if (isGenerateRejectFile() && failed.size() > 0) { - IPath pp= null; - if (path.segmentCount() > 1) { - pp= path.removeLastSegments(1); - pp= pp.append(path.lastSegment() + REJECT_FILE_EXTENSION); - } else - pp= new Path(path.lastSegment() + REJECT_FILE_EXTENSION); - file= createPath(file.getProject(), pp); - if (file != null) { - store(getRejected(failed), file, pm); - try { - IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, Messages.WorkspacePatcher_1); - marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); - } catch (CoreException ex) { - // NeedWork - } - } - } - } - - if (pm != null) { - if (pm.isCanceled()) - break; - if (workTicks > 0) - pm.worked(workTicks); - } - } - } - } - - private boolean isAccessible(FileDiff diff) { - return isEnabled(diff) && diff.getProject().getProject().isAccessible(); - } - - /** - * Returns the target files of all the Diffs contained by this - * DiffProject. - * @param project - * @return An array of IFiles that are targeted by the Diffs - */ - public IFile[] getTargetFiles(DiffProject project) { - List files= new ArrayList(); - FileDiff[] diffs = project.getFileDiffs(); - for (int i = 0; i < diffs.length; i++) { - FileDiff diff = diffs[i]; - if (isEnabled(diff)) { - files.add(getTargetFile(diff)); - } - } - return (IFile[]) files.toArray(new IFile[files.size()]); - } - - public IFile getTargetFile(FileDiff diff) { - IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); - DiffProject project = getProject(diff); - if (project != null) - return project.getFile(path); - return super.getTargetFile(diff); - } - - private IPath getFullPath(FileDiff diff) { - IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); - DiffProject project = getProject(diff); - if (project != null) - return project.getFile(path).getFullPath(); - return getTarget().getFullPath().append(path); - } - - public ISchedulingRule[] getTargetProjects() { - List projects= new ArrayList(); - IResourceRuleFactory ruleFactory= ResourcesPlugin.getWorkspace().getRuleFactory(); - // Determine the appropriate scheduling rules - for (int i= 0; i < fDiffProjects.length; i++) { - IProject tempProject= fDiffProjects[i].getProject(); - // The goal here is to lock as little of the workspace as necessary - // but still allow the patcher to obtain the locks it needs. - // As such, we need to get the modify rules from the rule factory for the .project file. A pessimistic - // rule factory will return the root, while others might return just the project. Combining - // this rule with the project will result in the smallest possible locking set. - ISchedulingRule scheduleRule= ruleFactory.modifyRule(tempProject.getFile(IProjectDescription.DESCRIPTION_FILE_NAME)); - MultiRule multiRule= new MultiRule(new ISchedulingRule[] { scheduleRule, tempProject } ); - projects.add(multiRule); - } - - return (ISchedulingRule[]) projects.toArray(new ISchedulingRule[projects.size()]); - } - - public void setDiffProjects(DiffProject[] newProjectArray) { - fDiffProjects = new DiffProject[newProjectArray.length]; - System.arraycopy(newProjectArray,0, fDiffProjects, 0, newProjectArray.length); - } - - public void removeProject(DiffProject project) { - DiffProject[] temp = new DiffProject[fDiffProjects.length - 1]; - int counter = 0; - for (int i = 0; i < fDiffProjects.length; i++) { - if (fDiffProjects[i] != project){ - temp[counter++] = fDiffProjects[i]; - } - } - fDiffProjects = temp; - } - - protected Object getElementParent(Object element) { - if (element instanceof FileDiff && fDiffProjects != null) { - FileDiff diff = (FileDiff) element; - for (int i = 0; i < fDiffProjects.length; i++) { - DiffProject project = fDiffProjects[i]; - if (project.contains(diff)) - return project; - } - } - return null; - } - - public boolean isRetargeted(Object object) { - return retargetedDiffs.containsKey(object); - } - - public IPath getOriginalPath(Object object) { - return (IPath)retargetedDiffs.get(object); - } - - public void retargetDiff(FileDiff diff, IFile file) { - retargetedDiffs.put(diff, diff.getPath(false)); - Hunk[] hunks = diff.getHunks(); - - if (isWorkspacePatch()){ - //since the diff has no more hunks to apply, remove it from the parent and the patcher - diff.getProject().remove(diff); - } - removeDiff(diff); - FileDiff newDiff = getDiffForFile(file); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - newDiff.add(hunk); - } - } - - private FileDiff getDiffForFile(IFile file) { - DiffProject diffProject = null; - FileDiff[] diffsToCheck; - if (isWorkspacePatch()){ - // Check if the diff project already exists for the file - IProject project = file.getProject(); - DiffProject[] diffProjects = getDiffProjects(); - for (int i = 0; i < diffProjects.length; i++) { - if (diffProjects[i].getProject().equals(project)){ - diffProject = diffProjects[i]; - break; - } - } - // If the project doesn't exist yet, create it and add it to the project list - if (diffProject == null){ - diffProject = addDiffProjectForProject(project); - } - diffsToCheck = diffProject.getFileDiffs(); - } else { - diffsToCheck = getDiffs(); - } - // Check to see if a diff already exists for the file - for (int i = 0; i < diffsToCheck.length; i++) { - FileDiff fileDiff = diffsToCheck[i]; - if (isDiffForFile(fileDiff, file)) { - return fileDiff; - } - } - - // Create a new diff for the file - IPath path = getDiffPath(file); - FileDiff newDiff = new FileDiff(path, 0, path, 0); - if (diffProject != null){ - diffProject.add(newDiff); - } - addDiff(newDiff); - return newDiff; - } - - private IPath getDiffPath(IFile file) { - DiffProject project = getDiffProject(file.getProject()); - if (project != null) { - return file.getProjectRelativePath(); - } - return file.getFullPath().removeFirstSegments(getTarget().getFullPath().segmentCount()); - } - - private boolean isDiffForFile(FileDiff fileDiff, IFile file) { - return getFullPath(fileDiff).equals(file.getFullPath()); - } - - private DiffProject addDiffProjectForProject(IProject project) { - DiffProject[] diffProjects = getDiffProjects(); - DiffProject diffProject = new DiffProject(project); - DiffProject[] newProjectArray = new DiffProject[diffProjects.length + 1]; - System.arraycopy(diffProjects, 0, newProjectArray, 0, diffProjects.length); - newProjectArray[diffProjects.length] = diffProject; - setDiffProjects(newProjectArray); - return diffProject; - } - - public void retargetHunk(Hunk hunk, IFile file) { - FileDiff newDiff = getDiffForFile(file); - newDiff.add(hunk); - } - - public void retargetProject(DiffProject project, IProject targetProject) { - retargetedDiffs.put(project, project.getProject().getFullPath()); - FileDiff[] diffs = project.getFileDiffs(); - DiffProject selectedProject = getDiffProject(targetProject); - if (selectedProject == null) - selectedProject = addDiffProjectForProject(targetProject); - // Copy over the diffs to the new project - for (int i = 0; i < diffs.length; i++) { - selectedProject.add(diffs[i]); - } - // Since the project has been retargeted, remove it from the patcher - removeProject(project); - } - - /** - * Return the diff project for the given project - * or null if the diff project doesn't exist - * or if the patch is not a workspace patch. - * @param project the project - * @return the diff project for the given project - * or null - */ - private DiffProject getDiffProject(IProject project) { - if (!isWorkspacePatch()) - return null; - DiffProject[] projects = getDiffProjects(); - for (int i = 0; i < projects.length; i++) { - if (projects[i].getProject().equals(project)) - return projects[i]; - } - return null; - } - - public int getStripPrefixSegments() { - // Segments are never stripped from a workspace patch - if (isWorkspacePatch()) - return 0; - return super.getStripPrefixSegments(); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/patch/PatchParser.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/patch/PatchParser.java index f734a957a..c0c0a75a1 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/patch/PatchParser.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare.core/src/org/eclipse/compare/patch/PatchParser.java @@ -14,8 +14,8 @@ import java.io.BufferedReader; import java.io.IOException; import org.eclipse.compare.internal.core.Activator; -import org.eclipse.compare.internal.patch.PatchReader; -import org.eclipse.compare.internal.patch.Patcher; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.compare.internal.core.patch.PatchReader; import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; @@ -23,18 +23,10 @@ import org.eclipse.core.runtime.Status; /** * Helper class for parsing patches. + * + * @since 3.4.100 */ public class PatchParser { - - /** - * Return whether the given storage contains a patch. - * @param storage the storage - * @return whether the given storage contains a patch - * @throws CoreException if an error occurs reading the contents from the storage - */ - public static boolean isPatch(IStorage storage) throws CoreException { - return parsePatch(storage).length > 0; - } /** * Parse the given patch and return the set of file patches that it contains. @@ -43,7 +35,7 @@ public class PatchParser { * @throws CoreException if an error occurs reading the contents from the storage */ public static IFilePatch[] parsePatch(IStorage storage) throws CoreException { - BufferedReader reader = Patcher.createReader(storage); + BufferedReader reader = LineReader.createReader(storage); try { PatchReader patchReader= new PatchReader(); patchReader.parse(reader); diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/META-INF/MANIFEST.MF b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/META-INF/MANIFEST.MF index 773eb2378..c2120a365 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.compare; singleton:=true -Bundle-Version: 3.4.0.qualifier +Bundle-Version: 3.4.100.qualifier Bundle-Activator: org.eclipse.compare.internal.CompareUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -23,7 +23,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="[3.3.0,4.0.0)", org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)", org.eclipse.ui.editors;bundle-version="[3.3.0,4.0.0)", - org.eclipse.ui.forms;bundle-version="[3.2.0,4.0.0)" + org.eclipse.ui.forms;bundle-version="[3.2.0,4.0.0)", + org.eclipse.compare.core;bundle-version="[3.4.100,4.0.0)";visibility:=reexport Bundle-ActivationPolicy: lazy Import-Package: com.ibm.icu.util, com.ibm.icu.text diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java index dbc7d67f8..0ef89503f 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/Utilities.java @@ -16,7 +16,7 @@ import java.util.List; import org.eclipse.compare.*; import org.eclipse.compare.contentmergeviewer.IDocumentRange; -import org.eclipse.compare.internal.patch.HunkResult; +import org.eclipse.compare.internal.core.patch.HunkResult; import org.eclipse.compare.patch.IHunk; import org.eclipse.compare.structuremergeviewer.DiffNode; import org.eclipse.compare.structuremergeviewer.ICompareInput; diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Attic/LineReader.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Attic/LineReader.java deleted file mode 100644 index a218ed5a1..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Attic/LineReader.java +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Brock Janiczak - Bug 181919 LineReader creating unneeded garbage - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.runtime.Assert; - -public class LineReader { - - private boolean fHaveChar= false; - private int fLastChar; - private boolean fSawEOF= false; - private BufferedReader fReader; - private boolean fIgnoreSingleCR= false; - private StringBuffer fBuffer= new StringBuffer(); - - public LineReader(BufferedReader reader) { - fReader= reader; - Assert.isNotNull(reader); - } - - void ignoreSingleCR() { - fIgnoreSingleCR= true; - } - - /** - * Reads a line of text. A line is considered to be terminated by any one - * of a line feed ('\n'), a carriage return ('\r'), or a carriage return - * followed immediately by a line-feed. - * @return A string containing the contents of the line including - * the line-termination characters, or null if the end of the - * stream has been reached - * @exception IOException If an I/O error occurs - */ - /* package */ String readLine() throws IOException { - try { - while (!fSawEOF) { - int c= readChar(); - if (c == -1) { - fSawEOF= true; - break; - } - fBuffer.append((char)c); - if (c == '\n') - break; - if (c == '\r') { - c= readChar(); - if (c == -1) { - fSawEOF= true; - break; // EOF - } - if (c != '\n') { - if (fIgnoreSingleCR) { - fBuffer.append((char)c); - continue; - } - fHaveChar= true; - fLastChar= c; - } else - fBuffer.append((char)c); - break; - } - } - - if (fBuffer.length() != 0) { - return fBuffer.toString(); - } - return null; - } finally { - fBuffer.setLength(0); - } - } - - /* package */ void close() { - try { - fReader.close(); - } catch (IOException ex) { - // silently ignored - } - } - - public List readLines() { - try { - List lines= new ArrayList(); - String line; - while ((line= readLine()) != null) - lines.add(line); - return lines; - } catch (IOException ex) { - // NeedWork - //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); - } finally { - close(); - } - return null; - } - - /* - * Returns the number of characters in the given string without - * counting a trailing line separator. - */ - /* package */ int lineContentLength(String line) { - if (line == null) - return 0; - int length= line.length(); - for (int i= length-1; i >= 0; i--) { - char c= line.charAt(i); - if (c =='\n' || c == '\r') - length--; - else - break; - } - return length; - } - - //---- private - - private int readChar() throws IOException { - if (fHaveChar) { - fHaveChar= false; - return fLastChar; - } - return fReader.read(); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java deleted file mode 100644 index f5469efb4..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/DiffProject.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.*; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.model.IWorkbenchAdapter; - -/** - * A diff project represents a project that was read from a workspace patch. - * It contains the set of file diffs that were associated with the project - * in the patch file. - */ -public class DiffProject { - - private IProject fProject; - private Set fDiffs= new HashSet(); - - /** - * Create a diff project for the given workspace project. - * @param project a workspace project - */ - public DiffProject(IProject project) { - this.fProject= project; - } - - /** - * Add the file diff to this project. - * @param diff the file diff. - */ - void add(FileDiff diff) { - fDiffs.add(diff); - if (diff.getProject() != this) - diff.setProject(this); - } - - - /** - * Return the workspace project associated with this diff project. - * @return the workspace project associated with this project - */ - public IProject getProject() { - return this.fProject; - } - - /** - * Return the name of this project. - * @return the name of this project - */ - public String getName() { - return fProject.getName(); - } - - /** - * Return the file at the given path relative to this project. - * @param path the relative path - * @return the file at the given path relative to this project - */ - public IFile getFile(IPath path) { - return fProject.getFile(path); - } - - public ImageDescriptor getImageDescriptor() { - Object o= fProject.getAdapter(IWorkbenchAdapter.class); - if (o instanceof IWorkbenchAdapter) { - ImageDescriptor id= ((IWorkbenchAdapter) o).getImageDescriptor(fProject); - return id; - } - return null; - } - - /** - * Remove the file diff from this project. - * @param diff the diff to be removed - */ - public void remove(FileDiff diff) { - fDiffs.remove(diff); - } - - /** - * Return whether this project contains the given diff. - * @param diff a file diff - * @return whether this project contains the given diff - */ - public boolean contains(FileDiff diff) { - return fDiffs.contains(diff); - } - - /** - * Return the file diffs associated with this project. - * @return the file diffs associated with this project - */ - public FileDiff[] getFileDiffs() { - return (FileDiff[]) fDiffs.toArray(new FileDiff[fDiffs.size()]); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java deleted file mode 100644 index 701f5b14a..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiff.java +++ /dev/null @@ -1,248 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.compare.patch.IFilePatchResult; -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Path; - -/** - * A file diff represents a set of hunks that were associated with the - * same path in a patch file. - */ -public class FileDiff implements IFilePatch { - - private IPath fOldPath, fNewPath; - private long oldDate, newDate; - private List fHunks= new ArrayList(); - private DiffProject fProject; //the project that contains this diff - private String header; - private int addedLines, removedLines; - - /** - * Create a file diff for the given path and date information. - * @param oldPath the path of the before state of the file - * @param oldDate the timestamp of the before state - * @param newPath the path of the after state - * @param newDate the timestamp of the after state - */ - protected FileDiff(IPath oldPath, long oldDate, IPath newPath, long newDate) { - fOldPath= oldPath; - this.oldDate = oldDate; - fNewPath= newPath; - this.newDate = newDate; - } - - /** - * Return the parent project or null if there isn't one. - * @return the parent project or null - */ - public DiffProject getProject() { - return fProject; - } - - /** - * Set the project of this diff to the given project. - * This method should only be called from - * {@link DiffProject#add(FileDiff)} - * @param diffProject the parent project - */ - void setProject(DiffProject diffProject) { - if (fProject == diffProject) - return; - if (fProject != null) - fProject.remove(this); - this.fProject= diffProject; - } - - /** - * Get the path of the file diff. - * @param reverse whether the path of the before state or after state - * should be used - * @return the path of the file diff - */ - protected IPath getPath(boolean reverse) { - if (getDiffType(reverse) == Differencer.ADDITION) { - if (reverse) - return fOldPath; - return fNewPath; - } - if (reverse && fNewPath != null) - return fNewPath; - if (fOldPath != null) - return fOldPath; - return fNewPath; - } - - /** - * Add the hunk to this file diff. - * @param hunk the hunk - */ - protected void add(Hunk hunk) { - fHunks.add(hunk); - hunk.setParent(this); - } - - /** - * Remove the hunk from this file diff - * @param hunk the hunk - */ - protected void remove(Hunk hunk) { - fHunks.remove(hunk); - } - - /** - * Return the hunks associated with this file diff. - * @return the hunks associated with this file diff - */ - public Hunk[] getHunks() { - return (Hunk[]) fHunks.toArray(new Hunk[fHunks.size()]); - } - - /** - * Return the number of hunks associated with this file diff. - * @return the number of hunks associated with this file diff - */ - public int getHunkCount() { - return fHunks.size(); - } - - /** - * Return the difference type of this file diff. - * @param reverse whether the patch is being reversed - * @return the type of this file diff - */ - public int getDiffType(boolean reverse) { - if (fHunks.size() == 1) { - boolean add = false; - boolean delete = false; - Iterator iter = fHunks.iterator(); - while (iter.hasNext()){ - Hunk hunk = (Hunk) iter.next(); - int type =hunk.getHunkType(reverse); - if (type == Hunk.ADDED){ - add = true; - } else if (type == Hunk.DELETED ){ - delete = true; - } - } - if (add && !delete){ - return Differencer.ADDITION; - } else if (!add && delete){ - return Differencer.DELETION; - } - } - return Differencer.CHANGE; - } - - /** - * Return the path of this file diff with the specified number - * of leading segments striped. - * @param strip the number of leading segments to strip from the path - * @param reverse whether the patch is being reversed - * @return the path of this file diff with the specified number - * of leading segments striped - */ - protected IPath getStrippedPath(int strip, boolean reverse) { - IPath path= getPath(reverse); - if (strip > 0 && strip < path.segmentCount()) - path= path.removeFirstSegments(strip); - return path; - } - - /** - * Return the segment count of the path of this file diff. - * @return the segment count of the path of this file diff - */ - public int segmentCount() { - //Update prefix count - go through all of the diffs and find the smallest - //path segment contained in all diffs. - int length= 99; - if (fOldPath != null) - length= Math.min(length, fOldPath.segmentCount()); - if (fNewPath != null) - length= Math.min(length, fNewPath.segmentCount()); - return length; - } - - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor) { - FileDiffResult result = new FileDiffResult(this, configuration); - result.refresh(contents, monitor); - return result; - } - - public IPath getTargetPath(PatchConfiguration configuration) { - return getStrippedPath(configuration.getPrefixSegmentStripCount(), configuration.isReversed()); - } - - public FileDiff asRelativeDiff() { - if (fProject == null) - return this; - IPath adjustedOldPath = null; - if (fOldPath != null) { - adjustedOldPath = new Path(null, fProject.getName()).append(fOldPath); - } - IPath adjustedNewPath = null; - if (fNewPath != null) { - adjustedNewPath = new Path(null, fProject.getName()).append(fNewPath); - } - FileDiff diff = new FileDiff(adjustedOldPath, 0, adjustedNewPath, 0); - for (Iterator iterator = fHunks.iterator(); iterator.hasNext();) { - Hunk hunk = (Hunk) iterator.next(); - // Creating the hunk adds it to the parent diff - new Hunk(diff, hunk); - } - return diff; - } - - public void setHeader(String header) { - this.header = header; - } - - public String getHeader() { - return header; - } - - public long getBeforeDate() { - return oldDate; - } - - public long getAfterDate() { - return newDate; - } - - public void setAddedLines(int addedLines) { - this.addedLines = addedLines; - } - - public void setRemovedLines(int removedLines) { - this.removedLines = removedLines; - } - - public int getAddedLines() { - return addedLines; - } - - public int getRemovedLines() { - return removedLines; - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java deleted file mode 100644 index 84ca27166..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/FileDiffResult.java +++ /dev/null @@ -1,326 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.*; - -import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.patch.*; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; -import org.eclipse.osgi.util.NLS; - -public class FileDiffResult implements IFilePatchResult { - - private FileDiff fDiff; - private boolean fMatches= false; - private boolean fDiffProblem; - private String fErrorMessage; - private Map fHunkResults = new HashMap(); - private List fBeforeLines, fAfterLines; - private final PatchConfiguration configuration; - private String charset; - - public FileDiffResult(FileDiff diff, PatchConfiguration configuration) { - super(); - fDiff = diff; - this.configuration = configuration; - } - - public PatchConfiguration getConfiguration() { - return configuration; - } - - public boolean canApplyHunk(Hunk hunk) { - HunkResult result = getHunkResult(hunk); - return result.isOK() && !fDiffProblem; - } - - /** - * Refreshes the state of the diff to {no matches, no problems} and checks to see what hunks contained - * by this Diff can actually be applied. - * - * Checks to see: - * 1) if the target file specified in fNewPath exists and is patchable - * 2) which hunks contained by this diff can actually be applied to the file - * @param storage the contents being patched or null for an addition - * @param monitor a progress monitor or null if no progress monitoring is desired - */ - public void refresh(IStorage storage, IProgressMonitor monitor) { - fMatches= false; - fDiffProblem= false; - boolean create= false; - charset = Utilities.getCharset(storage); - //If this diff is an addition, make sure that it doesn't already exist - boolean exists = targetExists(storage); - if (fDiff.getDiffType(getConfiguration().isReversed()) == Differencer.ADDITION) { - if ((!exists || isEmpty(storage)) && canCreateTarget(storage)) { - fMatches= true; - } else { - // file already exists - fDiffProblem= true; - fErrorMessage= PatchMessages.PreviewPatchPage_FileExists_error; - } - create= true; - } else { //This diff is not an addition, try to find a match for it - //Ensure that the file described by the path exists and is modifiable - if (exists) { - fMatches= true; - } else { - // file doesn't exist - fDiffProblem= true; - fErrorMessage= PatchMessages.PreviewPatchPage_FileDoesNotExist_error; - } - } - - if (fDiffProblem) { - // We couldn't find the target file or the patch is trying to add a - // file that already exists but we need to initialize the hunk - // results for display - fBeforeLines = new ArrayList(getLines(storage, false)); - fAfterLines = fMatches ? new ArrayList() : fBeforeLines; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setMatches(false); - } - } else { - // If this diff has no problems discovered so far, try applying the patch - patch(getLines(storage, create), monitor); - } - - if (containsProblems()) { - if (fMatches) { - // Check to see if we have at least one hunk that matches - fMatches = false; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - if (result.isOK()) { - fMatches = true; - break; - } - } - } - } - } - - protected boolean canCreateTarget(IStorage storage) { - return true; - } - - protected boolean targetExists(IStorage storage) { - return storage != null; - } - - protected List getLines(IStorage storage, boolean create) { - List lines = Patcher.load(storage, create); - return lines; - } - - protected boolean isEmpty(IStorage storage) { - if (storage == null) - return true; - return Patcher.load(storage, false).isEmpty(); - } - - /* - * Tries to patch the given lines with the specified Diff. - * Any hunk that couldn't be applied is returned in the list failedHunks. - */ - public void patch(List lines, IProgressMonitor monitor) { - fBeforeLines = new ArrayList(); - fBeforeLines.addAll(lines); - if (getConfiguration().getFuzz() != 0) { - calculateFuzz(fBeforeLines, monitor); - } - int shift= 0; - Hunk[] hunks = fDiff.getHunks(); - for (int i = 0; i < hunks.length; i++) { - Hunk hunk = hunks[i]; - HunkResult result = getHunkResult(hunk); - result.setShift(shift); - if (result.patch(lines)) { - shift = result.getShift(); - } - } - fAfterLines = lines; - } - - protected boolean getDiffProblem() { - return fDiffProblem; - } - - /** - * Returns whether this Diff has any problems - * @return true if this Diff or any of its children Hunks have a problem, false if it doesn't - */ - protected boolean containsProblems() { - if (fDiffProblem) - return true; - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - return true; - } - return false; - } - - public String getLabel() { - String label= getTargetPath().toString(); - if (this.fDiffProblem) - return NLS.bind(PatchMessages.Diff_2Args, new String[] {label, fErrorMessage}); - return label; - } - - public boolean hasMatches() { - return fMatches; - } - - /** - * Return the lines of the target file with all matched hunks applied. - * @return the lines of the target file with all matched hunks applied - */ - public List getLines() { - return fAfterLines; - } - - /** - * Calculate the fuzz factor that will allow the most hunks to be matched. - * @param lines the lines of the target file - * @param monitor a progress monitor - * @return the fuzz factor or -1 if no hunks could be matched - */ - public int calculateFuzz(List lines, IProgressMonitor monitor) { - if (monitor == null) - monitor = new NullProgressMonitor(); - fBeforeLines = new ArrayList(lines); - // TODO: What about deletions? - if (fDiff.getDiffType(getConfiguration().isReversed()) == Differencer.ADDITION) { - // Additions don't need to adjust the fuzz factor - // TODO: What about the after lines? - return -1; - } - int shift= 0; - int highestFuzz = -1; // the maximum fuzz factor for all hunks - String name = getTargetPath() != null ? getTargetPath().lastSegment() : ""; //$NON-NLS-1$ - Hunk[] hunks = fDiff.getHunks(); - for (int j = 0; j < hunks.length; j++) { - Hunk h = hunks[j]; - monitor.subTask(NLS.bind(PatchMessages.PreviewPatchPage_GuessFuzzProgress_format, new String[] {name, Integer.toString(j + 1)})); - HunkResult result = getHunkResult(h); - result.setShift(shift); - int fuzz = result.calculateFuzz(lines, monitor); - shift = result.getShift(); - if (fuzz > highestFuzz) - highestFuzz = fuzz; - monitor.worked(1); - } - fAfterLines = lines; - return highestFuzz; - } - - public IPath getTargetPath() { - return fDiff.getStrippedPath(getConfiguration().getPrefixSegmentStripCount(), getConfiguration().isReversed()); - } - - private HunkResult getHunkResult(Hunk hunk) { - HunkResult result = (HunkResult)fHunkResults.get(hunk); - if (result == null) { - result = new HunkResult(this, hunk); - fHunkResults .put(hunk, result); - } - return result; - } - - List getFailedHunks() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result.getHunk()); - } - return failedHunks; - } - - private HunkResult[] getFailedHunkResults() { - List failedHunks = new ArrayList(); - for (Iterator iterator = fHunkResults.values().iterator(); iterator.hasNext();) { - HunkResult result = (HunkResult) iterator.next(); - if (!result.isOK()) - failedHunks.add(result); - } - return (HunkResult[]) failedHunks.toArray(new HunkResult[failedHunks.size()]); - } - - public FileDiff getDiff() { - return fDiff; - } - - List getBeforeLines() { - return fBeforeLines; - } - - List getAfterLines() { - return fAfterLines; - } - - public HunkResult[] getHunkResults() { - return (HunkResult[]) fHunkResults.values().toArray(new HunkResult[fHunkResults.size()]); - } - - public InputStream getOriginalContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getBeforeLines()); - return asInputStream(contents, getCharset()); - } - - public InputStream getPatchedContents() { - String contents = Patcher.createString(isPreserveLineDelimeters(), getLines()); - return asInputStream(contents, getCharset()); - } - - public String getCharset() { - return charset; - } - - protected boolean isPreserveLineDelimeters() { - return false; - } - - public IHunk[] getRejects() { - return getFailedHunkResults(); - } - - public boolean hasRejects() { - return getFailedHunkResults().length > 0; - } - - public static InputStream asInputStream(String contents, String charSet) { - byte[] bytes = null; - if (charSet != null) { - try { - bytes = contents.getBytes(charSet); - } catch (UnsupportedEncodingException e) { - CompareUIPlugin.log(e); - } - } - if (bytes == null) { - bytes = contents.getBytes(); - } - return new ByteArrayInputStream(bytes); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java deleted file mode 100644 index 9469fcb11..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Hunk.java +++ /dev/null @@ -1,451 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.runtime.Assert; - -/** - * A Hunk describes a range of changed lines and some context lines. - */ -public class Hunk { - - public static final int ADDED = 0x1; - public static final int DELETED = 0x2; - public static final int CHANGED = 0x4; - public static final int UNKNOWN = 0x8; - - private FileDiff fParent; - private int fOldStart, fOldLength; - private int fNewStart, fNewLength; - private String[] fLines; - private int hunkType; - - public Hunk(FileDiff parent, Hunk toCopy) { - fParent = parent; - if (fParent != null) { - fParent.add(this); - } - - fOldStart = toCopy.fOldStart; - fOldLength = toCopy.fOldLength; - fNewStart = toCopy.fNewStart; - fNewLength = toCopy.fOldLength; - fLines = toCopy.fLines; - hunkType = toCopy.hunkType; - } - - public Hunk(FileDiff parent, int[] oldRange, int[] newRange, List lines, boolean encounteredPlus, boolean encounteredMinus, boolean encounteredSpace) { - - fParent= parent; - if (fParent != null) - fParent.add(this); - - if (oldRange[0] > 0) - fOldStart= oldRange[0]-1; // line number start at 0! - else - fOldStart= 0; - fOldLength= oldRange[1]; - if (newRange[0] > 0) - fNewStart= newRange[0]-1; // line number start at 0! - else - fNewStart= 0; - fNewLength= newRange[1]; - - fLines= (String[]) lines.toArray(new String[lines.size()]); - - if (encounteredSpace && (encounteredPlus || encounteredMinus)){ - hunkType = CHANGED; - } else if (encounteredPlus && !encounteredMinus && !encounteredSpace){ - hunkType = ADDED; - } else if (!encounteredPlus && encounteredMinus && !encounteredSpace) { - hunkType = DELETED; - } else { - hunkType = UNKNOWN; - } - } - - /* - * Returns the contents of this hunk. - * Each line starts with a control character. Their meaning is as follows: - *
    - *
  • - * '+': add the line - *
  • - * '-': delete the line - *
  • - * ' ': no change, context line - *
- */ - String getContent() { - StringBuffer sb= new StringBuffer(); - for (int i= 0; i < fLines.length; i++) { - String line= fLines[i]; - sb.append(line.substring(0, Patcher.length(line))); - sb.append('\n'); - } - return sb.toString(); - } - - /* - * Returns a descriptive String for this hunk. - * It is in the form old_start,old_length -> new_start,new_length. - */ - String getDescription() { - StringBuffer sb= new StringBuffer(); - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" -> "); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - return sb.toString(); - } - - String getRejectedDescription() { - StringBuffer sb= new StringBuffer(); - sb.append("@@ -"); //$NON-NLS-1$ - sb.append(Integer.toString(fOldStart)); - sb.append(','); - sb.append(Integer.toString(fOldLength)); - sb.append(" +"); //$NON-NLS-1$ - sb.append(Integer.toString(fNewStart)); - sb.append(','); - sb.append(Integer.toString(fNewLength)); - sb.append(" @@"); //$NON-NLS-1$ - return sb.toString(); - } - - int getHunkType(boolean reverse) { - if (reverse) { - if (hunkType == ADDED) - return DELETED; - if (hunkType == DELETED) - return ADDED; - } - return hunkType; - } - - void setHunkType(int hunkType) { - this.hunkType = hunkType; - } - - public String[] getLines() { - return fLines; - } - - /** - * Set the parent of this hunk. This method - * should only be invoked from {@link FileDiff#add(Hunk)} - * @param diff the parent of this hunk - */ - void setParent(FileDiff diff) { - if (fParent == diff) - return; - if (fParent != null) - fParent.remove(this); - fParent = diff; - } - - public FileDiff getParent() { - return fParent; - } - - /* - * Tries to apply the given hunk on the specified lines. - * The parameter shift is added to the line numbers given - * in the hunk. - */ - public boolean tryPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - int deleteMatches = 0; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s = fLines[i]; - Assert.isTrue(s.length() > 0); - String line = s.substring(1); - char controlChar = s.charAt(0); - - if (controlChar == ' ') { // context lines - - if (pos < 0 || pos >= lines.size()) - return false; - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - return false; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - return false; - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (pos < 0 || pos >= lines.size()) // out of the file - return false; - if (linesMatch(configuration, line, (String) lines.get(pos))) { - deleteMatches++; - pos++; - continue; // line matched, continue with the next one - } - - // We must remove all lines at once, return false if this - // fails. In other words, all lines considered for deletion - // must be found one by one. - - // if (deleteMatches <= 0) - return false; - // pos++; - } else if (isAddedDelimeter(controlChar, reverse)) { - - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - return false; - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - return false; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - // we don't have to do anything more for a 'try' - } else - Assert.isTrue(false, "tryPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - - // check following context lines if exist - if (!contextLinesMatched - && fuzz > 0 - && contextLines.size() > fuzz - && !checkFollowingContextLines(configuration, lines, fuzz, pos, - contextLines)) - return false; - - return true; - } - - private boolean checkPrecedingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - - // ignore from the beginning - for (int j = fuzz; j < contextLines.size(); j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - return true; - } - - private boolean checkFollowingContextLines( - PatchConfiguration configuration, List lines, int fuzz, int pos, - List contextLines) { - if (!contextLines.isEmpty()) { - // ignore from the end - for (int j = 0; j < contextLines.size() - fuzz; j++) { - if (!linesMatch(configuration, (String) contextLines.get(j), - (String) lines.get(pos - contextLines.size() + j))) - return false; - } - } - return true; - } - - int getStart(boolean reverse) { - if (reverse) { - return fNewStart; - } - return fOldStart; - } - - private int getLength(boolean reverse) { - if (reverse) { - return fNewLength; - } - return fOldLength; - } - - private int getShift(boolean reverse) { - if (reverse) { - return fOldLength - fNewLength; - } - return fNewLength - fOldLength; - } - - int doPatch(PatchConfiguration configuration, List lines, int shift, int fuzz) { - boolean reverse = configuration.isReversed(); - int pos = getStart(reverse) + shift; - List contextLines = new ArrayList(); - boolean contextLinesMatched = true; - boolean precedingLinesChecked = false; - for (int i= 0; i < fLines.length; i++) { - String s= fLines[i]; - Assert.isTrue(s.length() > 0); - String line= s.substring(1); - char controlChar= s.charAt(0); - if (controlChar == ' ') { - // context lines - Assert.isTrue(pos < lines.size(), "doPatch: inconsistency in context"); //$NON-NLS-1$ - contextLines.add(line); - if (linesMatch(configuration, line, (String) lines.get(pos))) { - pos++; - continue; - } else if (fuzz > 0) { - // doesn't match, use the fuzz factor - contextLinesMatched = false; - pos++; - continue; - } - Assert.isTrue(false, "doPatch: context doesn't match"); //$NON-NLS-1$ -// pos++; - } else if (isDeletedDelimeter(controlChar, reverse)) { - // deleted lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - // context lines inside hunk don't match - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - // check following context lines if exist - // use the fuzz factor if needed - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - // else if there is less or equal context line to the fuzz - // factor we ignore them all and treat as matching - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - lines.remove(pos); - } else if (isAddedDelimeter(controlChar, reverse)) { - // added lines - if (precedingLinesChecked && !contextLinesMatched && contextLines.size() > 0) - Assert.isTrue(false, "doPatch: context lines inside hunk don't match"); //$NON-NLS-1$ - - if (!precedingLinesChecked - && !contextLinesMatched - && contextLines.size() >= fuzz - && !checkPrecedingContextLines(configuration, lines, - fuzz, pos, contextLines)) - Assert.isTrue(false, "doPatch: preceding context lines don't match, even though fuzz factor has been used"); //$NON-NLS-1$; - - precedingLinesChecked = true; - contextLines.clear(); - contextLinesMatched = true; - - if (getLength(reverse) == 0 && pos+1 < lines.size()) - lines.add(pos+1, line); - else - lines.add(pos, line); - pos++; - } else - Assert.isTrue(false, "doPatch: unknown control character: " + controlChar); //$NON-NLS-1$ - } - return getShift(reverse); - } - - private boolean isDeletedDelimeter(char controlChar, boolean reverse) { - return (!reverse && controlChar == '-') || (reverse && controlChar == '+'); - } - - private boolean isAddedDelimeter(char controlChar, boolean reverse) { - return (reverse && controlChar == '-') || (!reverse && controlChar == '+'); - } - - /* - * Compares two strings. - * If fIgnoreWhitespace is true whitespace is ignored. - */ - private boolean linesMatch(PatchConfiguration configuration, String line1, String line2) { - if (configuration.isIgnoreWhitespace()) - return stripWhiteSpace(line1).equals(stripWhiteSpace(line2)); - if (isIgnoreLineDelimiter()) { - int l1= Patcher.length(line1); - int l2= Patcher.length(line2); - if (l1 != l2) - return false; - return line1.regionMatches(0, line2, 0, l1); - } - return line1.equals(line2); - } - - private boolean isIgnoreLineDelimiter() { - return true; - } - - /* - * Returns the given string with all whitespace characters removed. - * Whitespace is defined by Character.isWhitespace(...). - */ - private String stripWhiteSpace(String s) { - StringBuffer sb= new StringBuffer(); - int l= s.length(); - for (int i= 0; i < l; i++) { - char c= s.charAt(i); - if (!Character.isWhitespace(c)) - sb.append(c); - } - return sb.toString(); - } - - public String getContents(boolean isAfterState, boolean reverse) { - StringBuffer result= new StringBuffer(); - for (int i= 0; i - Bug 181919 LineReader creating unneeded garbage - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.runtime.Assert; - -public class LineReader { - - private boolean fHaveChar= false; - private int fLastChar; - private boolean fSawEOF= false; - private BufferedReader fReader; - private boolean fIgnoreSingleCR= false; - private StringBuffer fBuffer= new StringBuffer(); - - public LineReader(BufferedReader reader) { - fReader= reader; - Assert.isNotNull(reader); - } - - void ignoreSingleCR() { - fIgnoreSingleCR= true; - } - - /** - * Reads a line of text. A line is considered to be terminated by any one - * of a line feed ('\n'), a carriage return ('\r'), or a carriage return - * followed immediately by a line-feed. - * @return A string containing the contents of the line including - * the line-termination characters, or null if the end of the - * stream has been reached - * @exception IOException If an I/O error occurs - */ - /* package */ String readLine() throws IOException { - try { - while (!fSawEOF) { - int c= readChar(); - if (c == -1) { - fSawEOF= true; - break; - } - fBuffer.append((char)c); - if (c == '\n') - break; - if (c == '\r') { - c= readChar(); - if (c == -1) { - fSawEOF= true; - break; // EOF - } - if (c != '\n') { - if (fIgnoreSingleCR) { - fBuffer.append((char)c); - continue; - } - fHaveChar= true; - fLastChar= c; - } else - fBuffer.append((char)c); - break; - } - } - - if (fBuffer.length() != 0) { - return fBuffer.toString(); - } - return null; - } finally { - fBuffer.setLength(0); - } - } - - /* package */ void close() { - try { - fReader.close(); - } catch (IOException ex) { - // silently ignored - } - } - - public List readLines() { - try { - List lines= new ArrayList(); - String line; - while ((line= readLine()) != null) - lines.add(line); - return lines; - } catch (IOException ex) { - // NeedWork - //System.out.println("error while reading file: " + fileName + "(" + ex + ")"); - } finally { - close(); - } - return null; - } - - /* - * Returns the number of characters in the given string without - * counting a trailing line separator. - */ - /* package */ int lineContentLength(String line) { - if (line == null) - return 0; - int length= line.length(); - for (int i= length-1; i >= 0; i--) { - char c= line.charAt(i); - if (c =='\n' || c == '\r') - length--; - else - break; - } - return length; - } - - //---- private - - private int readChar() throws IOException { - if (fHaveChar) { - fHaveChar= false; - return fLastChar; - } - return fReader.read(); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java index c80ef9436..278296a00 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchCompareEditorInput.java @@ -14,6 +14,10 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.*; import org.eclipse.compare.internal.*; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.HunkResult; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.runtime.Assert; @@ -391,7 +395,7 @@ public abstract class PatchCompareEditorInput extends CompareEditorInput { public Viewer findStructureViewer(Viewer oldViewer, ICompareInput input, Composite parent) { - if (Utilities.isHunk(input)) + if (org.eclipse.compare.internal.Utilities.isHunk(input)) return null; return super.findStructureViewer(oldViewer, input, parent); } diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java index 5bc0e31e2..15cfa5a22 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileDiffNode.java @@ -11,6 +11,8 @@ package org.eclipse.compare.internal.patch; import org.eclipse.compare.*; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.core.resources.IFile; @@ -26,7 +28,28 @@ public class PatchFileDiffNode extends PatchDiffNode implements IContentChangeLi private static int getKind(FileDiffResult result) { if (!result.hasMatches()) return Differencer.NO_CHANGE; - return result.getDiff().getDiffType(result.getConfiguration().isReversed()) | Differencer.RIGHT; + int fileDiffKind = result.getDiff().getDiffType(result.getConfiguration().isReversed()); + int kind = convertFileDiffTypeToDifferencerType(fileDiffKind); + return kind | Differencer.RIGHT; + } + + private static int convertFileDiffTypeToDifferencerType(int fileDiffKind) { + int kind; + switch (fileDiffKind) { + case FileDiff.ADDITION: + kind = Differencer.ADDITION; + break; + case FileDiff.DELETION: + kind = Differencer.DELETION; + break; + case FileDiff.CHANGE: + kind = Differencer.CHANGE; + break; + default: + kind = Differencer.CHANGE; + break; + } + return kind; } private static ITypedElement getRightElement(FileDiffResult result) { diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java index 04c519f2f..6f99a65bc 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchFileTypedElement.java @@ -10,12 +10,21 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.List; -import org.eclipse.compare.*; +import org.eclipse.compare.CompareUI; +import org.eclipse.compare.IEncodedStreamContentAccessor; +import org.eclipse.compare.ITypedElement; import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.core.resources.*; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.swt.graphics.Image; @@ -88,7 +97,7 @@ public class PatchFileTypedElement implements ITypedElement, IEncodedStreamConte } else { lines = result.getBeforeLines(); } - String contents = Patcher.createString(getPatcher().isPreserveLineDelimeters(), lines); + String contents = LineReader.createString(getPatcher().isPreserveLineDelimeters(), lines); String charSet = getCharset(); byte[] bytes = null; if (charSet != null) { diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java index a2f101730..1a92a7463 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.java @@ -14,7 +14,7 @@ import org.eclipse.osgi.util.NLS; public final class PatchMessages extends NLS { - private static final String BUNDLE_NAME = "org.eclipse.compare.internal.patch.PatchMessages";//$NON-NLS-1$ + private static final String BUNDLE_NAME = "org.eclipse.compare.internal.ui.patch.PatchMessages";//$NON-NLS-1$ private PatchMessages() { // Do not instantiate @@ -66,15 +66,9 @@ public final class PatchMessages extends NLS { public static String PreviewPatchPage_ReversePatch_text; public static String PreviewPatchPage_FuzzFactor_text; public static String PreviewPatchPage_FuzzFactor_tooltip; - public static String PreviewPatchPage_FileExists_error; - public static String PreviewPatchPage_FileDoesNotExist_error; public static String PreviewPatchPage_GuessFuzz_text; - public static String PreviewPatchPage_GuessFuzzProgress_text; - public static String PreviewPatchPage_GuessFuzzProgress_format; public static String PreviewPatchPage_FuzzUsed; public static String PreviewPatchPage_AllContextIgnored; - public static String Patcher_Marker_message; - public static String Patcher_Task_message; static { NLS.initializeMessages(BUNDLE_NAME, PatchMessages.class); diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties index 4e442b412..29224b777 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchMessages.properties @@ -88,17 +88,13 @@ PreviewPatchPage2_OrphanedHunk=Unmatched Patch Segment PreviewPatchPage2_MatchedHunk=Matched Hunk PreviewPatchPage2_IgnoreWSAction=Ignore whitespace PreviewPatchPage_FuzzFactor_tooltip=Allow this number of context lines to be ignored -PreviewPatchPage_FileExists_error=(file already exists) PreviewPatchPage2_IgnoreWSTooltip=Ignore whitespace PreviewPatchPage2_IgnoreWhitespace=Ignore whitespace PreviewPatchPage2_PatchedLocalFile=Patched Local File PreviewPatchPage2_CalculateReverse=Calculating reverse -PreviewPatchPage_FileDoesNotExist_error=(file does not exist) PreviewPatchPage_RetargetPatch=Retarget Patch PreviewPatchPage_SelectProject=Select the new target project for the portion of the patch targeted to project ''{0}'': PreviewPatchPage_GuessFuzz_text= &Guess -PreviewPatchPage_GuessFuzzProgress_text= Guessing Fuzz Factor... -PreviewPatchPage_GuessFuzzProgress_format= {0} (hunk #{1}) PreviewPatchPage_FuzzUsed=(fuzz factor used: {0}) PreviewPatchPage_AllContextIgnored=(fuzz factor used: {0}, all context lines ignored) PreviewPatchPage2_ShowMatched=Show &matched hunks @@ -108,8 +104,6 @@ PreviewPatchLabelDecorator_ProjectDoesNotExist=(Project does not exist in worksp # # Patcher # -Patcher_Marker_message=Rejected patch -Patcher_Task_message=Patching Diff_2Args={0} {1} HunkMergePage_Merged=(merged) HunkMergePage_GenerateRejectFile=G&enerate a .rej file for unmerged hunks diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java index 8b71f761a..4c6834f5f 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchProjectDiffNode.java @@ -12,6 +12,7 @@ package org.eclipse.compare.internal.patch; import org.eclipse.compare.CompareUI; import org.eclipse.compare.ITypedElement; +import org.eclipse.compare.internal.core.patch.DiffProject; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.compare.structuremergeviewer.*; import org.eclipse.jface.resource.LocalResourceManager; diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java deleted file mode 100644 index 7d0fa5af7..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchReader.java +++ /dev/null @@ -1,663 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.internal.patch; - -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; -import java.util.*; - -import org.eclipse.compare.patch.IFilePatch; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.*; -import org.eclipse.swt.SWT; - -import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.SimpleDateFormat; - -public class PatchReader { - - private static final boolean DEBUG= false; - - private static final String DEV_NULL= "/dev/null"; //$NON-NLS-1$ - - protected static final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; //$NON-NLS-1$ - - // diff formats - // private static final int CONTEXT= 0; - // private static final int ED= 1; - // private static final int NORMAL= 2; - // private static final int UNIFIED= 3; - - // we recognize the following date/time formats - private DateFormat[] fDateFormats= new DateFormat[] { - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy"), //$NON-NLS-1$ - new SimpleDateFormat("yyyy/MM/dd kk:mm:ss"), //$NON-NLS-1$ - new SimpleDateFormat("EEE MMM dd kk:mm:ss yyyy", Locale.US) //$NON-NLS-1$ - }; - - private boolean fIsWorkspacePatch; - private DiffProject[] fDiffProjects; - private FileDiff[] fDiffs; - - // API for writing new multi-project patch format - public static final String MULTIPROJECTPATCH_HEADER= "### Eclipse Workspace Patch"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_VERSION= "1.0"; //$NON-NLS-1$ - - public static final String MULTIPROJECTPATCH_PROJECT= "#P"; //$NON-NLS-1$ - - /** - * Create a patch reader for the default date formats. - */ - public PatchReader() { - // nothing here - } - - /** - * Create a patch reader for the given date formats. - * - * @param dateFormats - * Array of DateFormats to be used when - * extracting dates from the patch. - */ - public PatchReader(DateFormat[] dateFormats) { - this(); - fDateFormats = dateFormats; - } - - public void parse(BufferedReader reader) throws IOException { - List diffs= new ArrayList(); - HashMap diffProjects= new HashMap(4); - String line= null; - boolean reread= false; - String diffArgs= null; - String fileName= null; - // no project means this is a single patch,create a placeholder project for now - // which will be replaced by the target selected by the user in the preview pane - String project= ""; //$NON-NLS-1$ - fIsWorkspacePatch= false; - - LineReader lr= new LineReader(reader); - if (!"carbon".equals(SWT.getPlatform())) //$NON-NLS-1$ - lr.ignoreSingleCR(); - - // Test for our format - line= lr.readLine(); - if (line != null && line.startsWith(PatchReader.MULTIPROJECTPATCH_HEADER)) { - fIsWorkspacePatch= true; - } else { - parse(lr, line); - return; - } - - // read leading garbage - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - if (line.length() < 4) - continue; // too short - - if (line.startsWith(PatchReader.MULTIPROJECTPATCH_PROJECT)) { - project= line.substring(2).trim(); - continue; - } - - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - continue; - } - if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - continue; - } - - if (line.startsWith("--- ")) { //$NON-NLS-1$ - // if there is no current project or - // the current project doesn't equal the newly parsed project - // reset the current project to the newly parsed one, create a new DiffProject - // and add it to the array - DiffProject diffProject; - if (!diffProjects.containsKey(project)) { - IProject iproject= ResourcesPlugin.getWorkspace().getRoot().getProject(project); - diffProject= new DiffProject(iproject); - diffProjects.put(project, diffProject); - } else { - diffProject= (DiffProject) diffProjects.get(project); - } - - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName, diffProject); - diffArgs= fileName= null; - reread= true; - } - } - - lr.close(); - - fDiffProjects= (DiffProject[]) diffProjects.values().toArray(new DiffProject[diffProjects.size()]); - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private String readUnifiedDiff(List diffs, LineReader lr, String line, String diffArgs, String fileName, DiffProject diffProject) throws IOException { - List newDiffs= new ArrayList(); - String nextLine= readUnifiedDiff(newDiffs, lr, line, diffArgs, fileName); - for (Iterator iter= newDiffs.iterator(); iter.hasNext();) { - FileDiff diff= (FileDiff) iter.next(); - diffProject.add(diff); - diffs.add(diff); - } - return nextLine; - } - - public void parse(LineReader lr, String line) throws IOException { - List diffs= new ArrayList(); - boolean reread= false; - String diffArgs= null; - String fileName= null; - List headerLines = new ArrayList(); - - // read leading garbage - reread= line!=null; - while (true) { - if (!reread) - line= lr.readLine(); - reread= false; - if (line == null) - break; - - // remember some infos - if (line.startsWith("Index: ")) { //$NON-NLS-1$ - fileName= line.substring(7).trim(); - } else if (line.startsWith("diff")) { //$NON-NLS-1$ - diffArgs= line.substring(4).trim(); - } else if (line.startsWith("--- ")) { //$NON-NLS-1$ - line= readUnifiedDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } else if (line.startsWith("*** ")) { //$NON-NLS-1$ - line= readContextDiff(diffs, lr, line, diffArgs, fileName); - if (!headerLines.isEmpty()) - setHeader((FileDiff)diffs.get(diffs.size() - 1), headerLines); - diffArgs= fileName= null; - reread= true; - } - - // Any lines we read here are header lines. - // However, if reread is set, we will add them to the header on the next pass through - if (!reread) { - headerLines.add(line); - } - } - - lr.close(); - - fDiffs = (FileDiff[]) diffs.toArray(new FileDiff[diffs.size()]); - } - - private void setHeader(FileDiff diff, List headerLines) { - String header = Patcher.createString(false, headerLines); - diff.setHeader(header); - headerLines.clear(); - } - - /* - * Returns the next line that does not belong to this diff - */ - protected String readUnifiedDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("+++ ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List lines= new ArrayList(); - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return null; - - if (reader.lineContentLength(line) == 0) { - //System.out.println("Warning: found empty line in hunk; ignored"); - //lines.add(' ' + line); - continue; - } - - char c= line.charAt(0); - switch (c) { - case '@': - if (line.startsWith("@@ ")) { //$NON-NLS-1$ - // flush old hunk - if (lines.size() > 0) { - new Hunk(diff, oldRange, newRange, lines,encounteredPlus, encounteredMinus, encounteredSpace); - lines.clear(); - } - - // format: @@ -oldStart,oldLength +newStart,newLength @@ - extractPair(line, '-', oldRange); - extractPair(line, '+', newRange); - continue; - } - break; - case ' ': - encounteredSpace = true; - lines.add(line); - continue; - case '+': - encounteredPlus = true; - lines.add(line); - continue; - case '-': - encounteredMinus = true; - lines.add(line); - continue; - case '\\': - if (line.indexOf("newline at end") > 0) { //$NON-NLS-1$ - int lastIndex= lines.size(); - if (lastIndex > 0) { - line= (String) lines.get(lastIndex-1); - int end= line.length()-1; - char lc= line.charAt(end); - if (lc == '\n') { - end--; - if (end > 0 && line.charAt(end) == '\r') - end--; - } else if (lc == '\r') { - end--; - } - line= line.substring(0, end+1); - lines.set(lastIndex-1, line); - } - continue; - } - break; - default: - if (DEBUG) { - int a1= c, a2= 0; - if (line.length() > 1) - a2= line.charAt(1); - System.out.println("char: " + a1 + " " + a2); //$NON-NLS-1$ //$NON-NLS-2$ - } - break; - } - return line; - } - } finally { - if (lines.size() > 0) - new Hunk(diff, oldRange, newRange, lines, encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Returns the next line that does not belong to this diff - */ - private String readContextDiff(List diffs, LineReader reader, String line, String args, String fileName) throws IOException { - - String[] oldArgs= split(line.substring(4)); - - // read info about new file - line= reader.readLine(); - if (line == null || !line.startsWith("--- ")) //$NON-NLS-1$ - return line; - - String[] newArgs= split(line.substring(4)); - - FileDiff diff= new FileDiff(extractPath(oldArgs, 0, fileName), extractDate(oldArgs, 1), - extractPath(newArgs, 0, fileName), extractDate(newArgs, 1)); - diffs.add(diff); - - int[] oldRange= new int[2]; - int[] newRange= new int[2]; - List oldLines= new ArrayList(); - List newLines= new ArrayList(); - List lines= oldLines; - - - boolean encounteredPlus = false; - boolean encounteredMinus = false; - boolean encounteredSpace = false; - - try { - // read lines of hunk - while (true) { - - line= reader.readLine(); - if (line == null) - return line; - - int l= line.length(); - if (l == 0) - continue; - if (l > 1) { - switch (line.charAt(0)) { - case '*': - if (line.startsWith("***************")) { // new hunk //$NON-NLS-1$ - // flush old hunk - if (oldLines.size() > 0 || newLines.size() > 0) { - new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - oldLines.clear(); - newLines.clear(); - } - continue; - } - if (line.startsWith("*** ")) { // old range //$NON-NLS-1$ - // format: *** oldStart,oldEnd *** - extractPair(line, ' ', oldRange); - oldRange[1]= oldRange[1]-oldRange[0]+1; - lines= oldLines; - continue; - } - break; - case ' ': // context line - if (line.charAt(1) == ' ') { - lines.add(line); - continue; - } - break; - case '+': // addition - if (line.charAt(1) == ' ') { - encounteredPlus = true; - lines.add(line); - continue; - } - break; - case '!': // change - if (line.charAt(1) == ' ') { - encounteredSpace = true; - lines.add(line); - continue; - } - break; - case '-': - if (line.charAt(1) == ' ') { // deletion - encounteredMinus = true; - lines.add(line); - continue; - } - if (line.startsWith("--- ")) { // new range //$NON-NLS-1$ - // format: *** newStart,newEnd *** - extractPair(line, ' ', newRange); - newRange[1]= newRange[1]-newRange[0]+1; - lines= newLines; - continue; - } - break; - default: - break; - } - } - return line; - } - } finally { - // flush last hunk - if (oldLines.size() > 0 || newLines.size() > 0) - new Hunk(diff, oldRange, newRange, unifyLines(oldLines, newLines), encounteredPlus, encounteredMinus, encounteredSpace); - } - } - - /* - * Creates a List of lines in the unified format from - * two Lists of lines in the 'classic' format. - */ - private List unifyLines(List oldLines, List newLines) { - List result= new ArrayList(); - - String[] ol= (String[]) oldLines.toArray(new String[oldLines.size()]); - String[] nl= (String[]) newLines.toArray(new String[newLines.size()]); - - int oi= 0, ni= 0; - - while (true) { - - char oc= 0; - String o= null; - if (oi < ol.length) { - o= ol[oi]; - oc= o.charAt(0); - } - - char nc= 0; - String n= null; - if (ni < nl.length) { - n= nl[ni]; - nc= n.charAt(0); - } - - // EOF - if (oc == 0 && nc == 0) - break; - - // deletion in old - if (oc == '-') { - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '-'); - continue; - } - - // addition in new - if (nc == '+') { - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '+'); - continue; - } - - // differing lines on both sides - if (oc == '!' && nc == '!') { - // remove old - do { - result.add('-' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == '!'); - - // add new - do { - result.add('+' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == '!'); - - continue; - } - - // context lines - if (oc == ' ' && nc == ' ') { - do { - Assert.isTrue(o.equals(n), "non matching context lines"); //$NON-NLS-1$ - result.add(' ' + o.substring(2)); - oi++; - ni++; - if (oi >= ol.length || ni >= nl.length) - break; - o= ol[oi]; - n= nl[ni]; - } while (o.charAt(0) == ' ' && n.charAt(0) == ' '); - continue; - } - - if (oc == ' ') { - do { - result.add(' ' + o.substring(2)); - oi++; - if (oi >= ol.length) - break; - o= ol[oi]; - } while (o.charAt(0) == ' '); - continue; - } - - if (nc == ' ') { - do { - result.add(' ' + n.substring(2)); - ni++; - if (ni >= nl.length) - break; - n= nl[ni]; - } while (n.charAt(0) == ' '); - continue; - } - - Assert.isTrue(false, "unexpected char <" + oc + "> <" + nc + ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - return result; - } - - /* - * @return the parsed time/date in milliseconds or IFilePatch.DATE_UNKNOWN - * (0) on error - */ - private long extractDate(String[] args, int n) { - if (n < args.length) { - String line= args[n]; - for (int i= 0; i < fDateFormats.length; i++) { - fDateFormats[i].setLenient(true); - try { - Date date= fDateFormats[i].parse(line); - return date.getTime(); - } catch (ParseException ex) { - // silently ignored - } - } - // System.err.println("can't parse date: <" + line + ">"); - } - return IFilePatch.DATE_UNKNOWN; - } - - /* - * Returns null if file name is "/dev/null". - */ - private IPath extractPath(String[] args, int n, String path2) { - if (n < args.length) { - String path= args[n]; - if (DEV_NULL.equals(path)) - return null; - int pos= path.lastIndexOf(':'); - if (pos >= 0) - path= path.substring(0, pos); - if (path2 != null && !path2.equals(path)) { - if (DEBUG) System.out.println("path mismatch: " + path2); //$NON-NLS-1$ - path= path2; - } - return new Path(path); - } - return null; - } - - /* - * Tries to extract two integers separated by a comma. - * The parsing of the line starts at the position after - * the first occurrence of the given character start an ends - * at the first blank (or the end of the line). - * If only a single number is found this is assumed to be the start of a one line range. - * If an error occurs the range -1,-1 is returned. - */ - private void extractPair(String line, char start, int[] pair) { - pair[0]= pair[1]= -1; - int startPos= line.indexOf(start); - if (startPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find \'" + start + "\'"); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - line= line.substring(startPos+1); - int endPos= line.indexOf(' '); - if (endPos < 0) { - if (DEBUG) System.out.println("parsing error in extractPair: couldn't find end blank"); //$NON-NLS-1$ - return; - } - line= line.substring(0, endPos); - int comma= line.indexOf(','); - if (comma >= 0) { - pair[0]= Integer.parseInt(line.substring(0, comma)); - pair[1]= Integer.parseInt(line.substring(comma+1)); - } else { // abbreviated form for one line patch - pair[0]= Integer.parseInt(line); - pair[1]= 1; - } - } - - - /* - * Breaks the given string into tab separated substrings. - * Leading and trailing whitespace is removed from each token. - */ - private String[] split(String line) { - List l= new ArrayList(); - StringTokenizer st= new StringTokenizer(line, "\t"); //$NON-NLS-1$ - while (st.hasMoreElements()) { - String token= st.nextToken().trim(); - if (token.length() > 0) - l.add(token); - } - return (String[]) l.toArray(new String[l.size()]); - } - - public boolean isWorkspacePatch() { - return fIsWorkspacePatch; - } - - public DiffProject[] getDiffProjects() { - return fDiffProjects; - } - - public FileDiff[] getDiffs() { - return fDiffs; - } - - public FileDiff[] getAdjustedDiffs() { - if (!isWorkspacePatch() || fDiffs.length == 0) - return fDiffs; - List result = new ArrayList(); - for (int i = 0; i < fDiffs.length; i++) { - FileDiff diff = fDiffs[i]; - result.add(diff.asRelativeDiff()); - } - return (FileDiff[]) result.toArray(new FileDiff[result.size()]); - } - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java index 2ff465773..4ddf19677 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PatchWizard.java @@ -16,6 +16,7 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ExceptionHandler; +import org.eclipse.compare.internal.Utilities; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.ISchedulingRule; @@ -150,7 +151,11 @@ public class PatchWizard extends Wizard { WorkspaceModifyOperation op = new WorkspaceModifyOperation(scheduleRule) { protected void execute(IProgressMonitor monitor) throws InvocationTargetException { try { - fPatcher.applyAll(monitor, getShell(), PatchMessages.PatchWizard_title); + fPatcher.applyAll(monitor, new Patcher.IFileValidator() { + public boolean validateResources(IFile[] resoures) { + return Utilities.validateResources(resoures, getShell(), PatchMessages.PatchWizard_title); + } + }); } catch (CoreException e) { throw new InvocationTargetException(e); } diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java index 9b8bea9b3..1590dc864 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/Patcher.java @@ -16,7 +16,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.Reader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; @@ -27,12 +26,17 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.eclipse.compare.internal.CompareUIPlugin; -import org.eclipse.compare.internal.Utilities; +import org.eclipse.compare.internal.core.Messages; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.Hunk; +import org.eclipse.compare.internal.core.patch.IHunkFilter; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.compare.internal.core.patch.PatchReader; +import org.eclipse.compare.internal.core.patch.Utilities; import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IEncodedStorage; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; @@ -46,8 +50,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Shell; /** * A Patcher @@ -55,7 +57,7 @@ import org.eclipse.swt.widgets.Shell; * - holds onto the parsed data and the options to use when applying the patches, * - knows how to apply the patches to files and folders. */ -public class Patcher { +public class Patcher implements IHunkFilter { static protected final String REJECT_FILE_EXTENSION= ".rej"; //$NON-NLS-1$ @@ -65,6 +67,10 @@ public class Patcher { * Property used to associate a patcher with a {@link PatchConfiguration} */ public static final String PROP_PATCHER = "org.eclipse.compare.patcher"; //$NON-NLS-1$ + + public interface IFileValidator { + boolean validateResources(IFile[] array); + } // diff formats // private static final int CONTEXT= 0; @@ -86,6 +92,7 @@ public class Patcher { public Patcher() { configuration = new PatchConfiguration(); configuration.setProperty(PROP_PATCHER, this); + configuration.setProperty(IHunkFilter.HUNK_FILTER_PROPERTY, this); } /* @@ -105,7 +112,7 @@ public class Patcher { /* * Returns true if new value differs from old. */ - boolean setStripPrefixSegments(int strip) { + public boolean setStripPrefixSegments(int strip) { if (strip != getConfiguration().getPrefixSegmentStripCount()) { getConfiguration().setPrefixSegmentStripCount(strip); return true; @@ -120,7 +127,7 @@ public class Patcher { /* * Returns true if new value differs from old. */ - boolean setFuzz(int fuzz) { + public boolean setFuzz(int fuzz) { if (fuzz != getConfiguration().getFuzz()) { getConfiguration().setFuzz(fuzz); return true; @@ -128,14 +135,14 @@ public class Patcher { return false; } - int getFuzz(){ + public int getFuzz(){ return getConfiguration().getFuzz(); } /* * Returns true if new value differs from old. */ - boolean setIgnoreWhitespace(boolean ignoreWhitespace) { + public boolean setIgnoreWhitespace(boolean ignoreWhitespace) { if (ignoreWhitespace != getConfiguration().isIgnoreWhitespace()) { getConfiguration().setIgnoreWhitespace(ignoreWhitespace); return true; @@ -143,7 +150,7 @@ public class Patcher { return false; } - boolean isIgnoreWhitespace() { + public boolean isIgnoreWhitespace() { return getConfiguration().isIgnoreWhitespace(); } @@ -158,7 +165,7 @@ public class Patcher { //---- parsing patch files public void parse(IStorage storage) throws IOException, CoreException { - BufferedReader reader = createReader(storage); + BufferedReader reader = LineReader.createReader(storage); try { parse(reader); } finally { @@ -169,32 +176,6 @@ public class Patcher { } } - public static BufferedReader createReader(IStorage storage) throws CoreException { - String charset = null; - if (storage instanceof IEncodedStorage) { - IEncodedStorage es = (IEncodedStorage) storage; - charset = es.getCharset(); - } - InputStreamReader in = null; - if (charset != null) { - InputStream contents = storage.getContents(); - try { - in = new InputStreamReader(contents, charset); - } catch (UnsupportedEncodingException e) { - CompareUIPlugin.log(e); - try { - contents.close(); - } catch (IOException e1) { - // Ignore - } - } - } - if (in == null) { - in = new InputStreamReader(storage.getContents()); - } - return new BufferedReader(in); - } - public void parse(BufferedReader reader) throws IOException { PatchReader patchReader= new PatchReader(); patchReader.parse(reader); @@ -233,9 +214,7 @@ public class Patcher { //---- applying a patch file - public void applyAll(IProgressMonitor pm, Shell shell, String title) throws CoreException { - - final int WORK_UNIT= 10; + public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { int i; @@ -259,18 +238,20 @@ public class Patcher { FileDiff diff= fDiffs[i]; if (isEnabled(diff)) { switch (diff.getDiffType(isReversed())) { - case Differencer.CHANGE: + case FileDiff.CHANGE: list.add(createPath(container, getPath(diff))); break; } } } } - if (! Utilities.validateResources(list, shell, title)) + if (! validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { return; + } + final int WORK_UNIT= 10; if (pm != null) { - String message= PatchMessages.Patcher_Task_message; + String message= Messages.Patcher_0; pm.beginTask(message, fDiffs.length*WORK_UNIT); } @@ -293,22 +274,22 @@ public class Patcher { int type= diff.getDiffType(isReversed()); switch (type) { - case Differencer.ADDITION: + case FileDiff.ADDITION: // patch it and collect rejected hunks List result= apply(diff, file, true, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; - case Differencer.DELETION: + case FileDiff.DELETION: file.delete(true, true, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; - case Differencer.CHANGE: + case FileDiff.CHANGE: // patch it and collect rejected hunks result= apply(diff, file, false, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks-= WORK_UNIT; break; } @@ -320,7 +301,7 @@ public class Patcher { store(getRejected(failed), file, pm); try { IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message); + marker.setAttribute(IMarker.MESSAGE, Messages.Patcher_1); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException ex) { // NeedWork @@ -348,66 +329,9 @@ public class Patcher { return pp; } - /* - * Reads the contents from the given file and returns them as - * a List of lines. - */ - public static List load(IStorage file, boolean create) { - List lines= null; - if (!create && file != null && exists(file)) { - // read current contents - String charset = Utilities.getCharset(file); - InputStream is= null; - try { - is= file.getContents(); - - Reader streamReader= null; - try { - streamReader= new InputStreamReader(is, charset); - } catch (UnsupportedEncodingException x) { - // use default encoding - streamReader= new InputStreamReader(is); - } - - BufferedReader reader= new BufferedReader(streamReader); - lines = readLines(reader); - } catch(CoreException ex) { - // TODO - CompareUIPlugin.log(ex); - } finally { - if (is != null) - try { - is.close(); - } catch(IOException ex) { - // silently ignored - } - } - } - - if (lines == null) - lines= new ArrayList(); - return lines; - } - - private static boolean exists(IStorage file) { - if (file instanceof IFile) { - return ((IFile) file).exists(); - } - return true; - } - - private static List readLines(BufferedReader reader) { - List lines; - LineReader lr= new LineReader(reader); - if (!"carbon".equals(SWT.getPlatform())) //$NON-NLS-1$ - lr.ignoreSingleCR(); - lines= lr.readLines(); - return lines; - } - List apply(FileDiff diff, IFile file, boolean create, List failedHunks) { FileDiffResult result = getDiffResult(diff); - List lines = Patcher.load(file, create); + List lines = LineReader.load(file, create); result.patch(lines, null); failedHunks.addAll(result.getFailedHunks()); if (hasCachedContents(diff)) { @@ -454,34 +378,7 @@ public class Patcher { } } - - - /* - * Concatenates all strings found in the given List. - */ - public static String createString(boolean preserveLineDelimeters, List lines) { - StringBuffer sb= new StringBuffer(); - Iterator iter= lines.iterator(); - if (preserveLineDelimeters) { - while (iter.hasNext()) - sb.append((String)iter.next()); - } else { - String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$ - while (iter.hasNext()) { - String line= (String)iter.next(); - int l= length(line); - if (l < line.length()) { // line has delimiter - sb.append(line.substring(0, l)); - sb.append(lineSeparator); - } else { - sb.append(line); - } - } - } - return sb.toString(); - } - - protected boolean isPreserveLineDelimeters() { + public boolean isPreserveLineDelimeters() { return false; } @@ -526,25 +423,6 @@ public class Patcher { // a leaf return container.getFile(path); } - - /* - * Returns the length (excluding a line delimiter CR, LF, CR/LF) - * of the given string. - */ - /* package */ static int length(String s) { - int l= s.length(); - if (l > 0) { - char c= s.charAt(l-1); - if (c == '\r') - return l-1; - if (c == '\n') { - if (l > 1 && s.charAt(l-2) == '\r') - return l-2; - return l-1; - } - } - return l; - } public IResource getTarget() { return fTarget; @@ -555,7 +433,7 @@ public class Patcher { } - protected IFile getTargetFile(FileDiff diff) { + public IFile getTargetFile(FileDiff diff) { IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); return existsInTarget(path); } @@ -692,7 +570,7 @@ public class Patcher { */ public int guessFuzzFactor(IProgressMonitor monitor) { try { - monitor.beginTask(PatchMessages.PreviewPatchPage_GuessFuzzProgress_text, IProgressMonitor.UNKNOWN); + monitor.beginTask(Messages.Patcher_2, IProgressMonitor.UNKNOWN); FileDiff[] diffs= getDiffs(); if (diffs==null||diffs.length<=0) return -1; @@ -701,7 +579,7 @@ public class Patcher { FileDiff d= diffs[i]; IFile file= getTargetFile(d); if (file != null && file.exists()) { - List lines= load(file, false); + List lines= LineReader.load(file, false); FileDiffResult result = getDiffResult(d); int f = result.calculateFuzz(lines, monitor); if (f > fuzz) @@ -799,7 +677,7 @@ public class Patcher { byte[] contents = (byte[])contentCache.get(diff); if (contents != null) { BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contents))); - return readLines(reader); + return LineReader.readLines(reader); } return null; } @@ -874,4 +752,8 @@ public class Patcher { } return false; } + + public boolean select(Hunk hunk) { + return isEnabled(hunk); + } } diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java index f68bca774..71a0a2bfc 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/PreviewPatchPage2.java @@ -19,6 +19,8 @@ import org.eclipse.compare.CompareUI; import org.eclipse.compare.internal.ComparePreferencePage; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ICompareUIConstants; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java index 0dde4ce09..8ec175c90 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/RetargetPatchElementDialog.java @@ -12,6 +12,9 @@ package org.eclipse.compare.internal.patch; import java.util.ArrayList; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.Dialog; diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java index 1cd0a18ca..1588fb9b3 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/UnmatchedHunkTypedElement.java @@ -10,12 +10,20 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.List; -import org.eclipse.compare.*; +import org.eclipse.compare.IContentChangeListener; +import org.eclipse.compare.IContentChangeNotifier; +import org.eclipse.compare.IEditableContent; +import org.eclipse.compare.ITypedElement; import org.eclipse.compare.internal.CompareUIPlugin; import org.eclipse.compare.internal.ContentChangeNotifier; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.HunkResult; +import org.eclipse.compare.internal.core.patch.LineReader; import org.eclipse.compare.patch.PatchConfiguration; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; @@ -89,7 +97,7 @@ public class UnmatchedHunkTypedElement extends HunkTypedElement implements ICont return new ByteArrayInputStream(getPatcher().getCachedContents(getDiff())); // Otherwise return the after state of the diff result List lines = getHunkResult().getDiffResult().getAfterLines(); - String content = Patcher.createString(getHunkResult().getDiffResult().isPreserveLineDelimeters(), lines); + String content = LineReader.createString(getHunkResult().getDiffResult().isPreserveLineDelimeters(), lines); byte[] bytes = null; if (getCharset() != null) try { diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java index 6a334213c..dd816ae61 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspaceFileDiffResult.java @@ -12,8 +12,13 @@ package org.eclipse.compare.internal.patch; import java.util.List; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.LineReader; import org.eclipse.compare.patch.PatchConfiguration; -import org.eclipse.core.resources.*; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IStorage; public class WorkspaceFileDiffResult extends FileDiffResult { @@ -34,7 +39,7 @@ public class WorkspaceFileDiffResult extends FileDiffResult { protected List getLines(IStorage storage, boolean create) { IFile file= getTargetFile(); - List lines = Patcher.load(file, create); + List lines = LineReader.load(file, create); return lines; } @@ -42,7 +47,7 @@ public class WorkspaceFileDiffResult extends FileDiffResult { return Patcher.getPatcher(getConfiguration()); } - protected IFile getTargetFile() { + public IFile getTargetFile() { return getPatcher().getTargetFile(getDiff()); } diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java index 2ba0e76ec..84ff8deb4 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/internal/patch/WorkspacePatcher.java @@ -10,15 +10,32 @@ *******************************************************************************/ package org.eclipse.compare.internal.patch; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.structuremergeviewer.Differencer; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.compare.internal.core.Messages; +import org.eclipse.compare.internal.core.patch.DiffProject; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.Hunk; +import org.eclipse.compare.internal.core.patch.LineReader; +import org.eclipse.compare.internal.core.patch.PatchReader; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceRuleFactory; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.MultiRule; -import org.eclipse.swt.widgets.Shell; /** * A Patcher @@ -50,15 +67,15 @@ public class WorkspacePatcher extends Patcher { return fDiffProjects; } - boolean isWorkspacePatch() { + public boolean isWorkspacePatch() { return fIsWorkspacePatch; } //---- parsing patch files - public void applyAll(IProgressMonitor pm, Shell shell, String title) throws CoreException { + public void applyAll(IProgressMonitor pm, IFileValidator validator) throws CoreException { if (!fIsWorkspacePatch) { - super.applyAll(pm, shell, title); + super.applyAll(pm, validator); } else { final int WORK_UNIT= 10; @@ -70,12 +87,13 @@ public class WorkspacePatcher extends Patcher { list.addAll(Arrays.asList(getTargetFiles(diffProject))); } // validate the files for editing - if (!Utilities.validateResources(list, shell, title)) + if (!validator.validateResources((IFile[])list.toArray(new IFile[list.size()]))) { return; + } FileDiff[] diffs = getDiffs(); if (pm != null) { - String message= PatchMessages.Patcher_Task_message; + String message= Messages.WorkspacePatcher_0; pm.beginTask(message, diffs.length * WORK_UNIT); } @@ -95,22 +113,22 @@ public class WorkspacePatcher extends Patcher { int type= diff.getDiffType(isReversed()); switch (type) { - case Differencer.ADDITION : + case FileDiff.ADDITION : // patch it and collect rejected hunks List result= apply(diff, file, true, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; - case Differencer.DELETION : + case FileDiff.DELETION : file.delete(true, true, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; - case Differencer.CHANGE : + case FileDiff.CHANGE : // patch it and collect rejected hunks result= apply(diff, file, false, failed); if (result != null) - store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); + store(LineReader.createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); workTicks -= WORK_UNIT; break; } @@ -127,7 +145,7 @@ public class WorkspacePatcher extends Patcher { store(getRejected(failed), file, pm); try { IMarker marker= file.createMarker(MARKER_TYPE); - marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message); + marker.setAttribute(IMarker.MESSAGE, Messages.WorkspacePatcher_1); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException ex) { // NeedWork @@ -168,7 +186,7 @@ public class WorkspacePatcher extends Patcher { return (IFile[]) files.toArray(new IFile[files.size()]); } - protected IFile getTargetFile(FileDiff diff) { + public IFile getTargetFile(FileDiff diff) { IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); DiffProject project = getProject(diff); if (project != null) @@ -354,7 +372,7 @@ public class WorkspacePatcher extends Patcher { return null; } - int getStripPrefixSegments() { + public int getStripPrefixSegments() { // Segments are never stripped from a workspace patch if (isWorkspacePatch()) return 0; diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java index 1e83ca4aa..13447df03 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/ApplyPatchOperation.java @@ -10,14 +10,16 @@ *******************************************************************************/ package org.eclipse.compare.patch; -import java.io.BufferedReader; -import java.io.IOException; - import org.eclipse.compare.CompareConfiguration; -import org.eclipse.compare.internal.*; -import org.eclipse.compare.internal.patch.*; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.compare.internal.ComparePreferencePage; +import org.eclipse.compare.internal.CompareUIPlugin; +import org.eclipse.compare.internal.patch.PatchWizard; +import org.eclipse.compare.internal.patch.PatchWizardDialog; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPart; @@ -74,7 +76,7 @@ public class ApplyPatchOperation implements Runnable { * @throws CoreException if an error occurs reading the contents from the storage */ public static boolean isPatch(IStorage storage) throws CoreException { - return parsePatch(storage).length > 0; + return PatchParser.parsePatch(storage).length > 0; } /** @@ -84,19 +86,7 @@ public class ApplyPatchOperation implements Runnable { * @throws CoreException if an error occurs reading the contents from the storage */ public static IFilePatch[] parsePatch(IStorage storage) throws CoreException { - BufferedReader reader = Patcher.createReader(storage); - try { - PatchReader patchReader= new PatchReader(); - patchReader.parse(reader); - return patchReader.getAdjustedDiffs(); - } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, e.getMessage(), e)); - } finally { - try { - reader.close(); - } catch (IOException e) { //ignored - } - } + return PatchParser.parsePatch(storage); } /** diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/Attic/IFilePatch.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/Attic/IFilePatch.java deleted file mode 100644 index 21646d916..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/Attic/IFilePatch.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; - -/** - * A representation of a file patch that can be applied to an input stream. - *

- * This interface is not intended to be implemented by clients. Clients can - * obtain file patches by calling - * {@link ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage)}. - *

- * - * @see ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage) - * @since 3.3 - * @noimplement - */ -public interface IFilePatch { - - /** - * Special constant that will be returned from get getBeforeDate() or - * getAfterDate() if the date is unknown. Equal to Midnight, Jan 1, 1970 - * GMT. - * - * @since 3.4 - */ - public static long DATE_UNKNOWN = 0; - - /** - * Return the target path for this patch. The target path may differ - * depending on whether the patch is being reversed or not. - * - * @param configuration the patch configuration - * @return the target path for this patch - * @see PatchConfiguration#isReversed() - */ - public IPath getTargetPath(PatchConfiguration configuration); - - /** - * Apply this patch to the given file contents. The result provides the - * original and patch contents and also indicates whether some portions of - * the patch (called hunks) failed to apply. - * - * @param contents the file contents - * @param configuration the patch configuration - * @param monitor a progress monitor - * @return the result of the patch application - */ - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor); - - /** - * Return the header information of the patch or - * null if there was no header text. - * The header may be multi-line. - * @return the header information of the patch or - * null - */ - public String getHeader(); - - /** - * Returns the milliseconds time value of the before date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the before date from the patch - * @since 3.4 - */ - public long getBeforeDate(); - - /** - * Returns the milliseconds time value of the after date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the after date from the patch - * @since 3.4 - */ - public long getAfterDate(); -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java deleted file mode 100644 index 21646d916..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatch.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; - -/** - * A representation of a file patch that can be applied to an input stream. - *

- * This interface is not intended to be implemented by clients. Clients can - * obtain file patches by calling - * {@link ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage)}. - *

- * - * @see ApplyPatchOperation#parsePatch(org.eclipse.core.resources.IStorage) - * @since 3.3 - * @noimplement - */ -public interface IFilePatch { - - /** - * Special constant that will be returned from get getBeforeDate() or - * getAfterDate() if the date is unknown. Equal to Midnight, Jan 1, 1970 - * GMT. - * - * @since 3.4 - */ - public static long DATE_UNKNOWN = 0; - - /** - * Return the target path for this patch. The target path may differ - * depending on whether the patch is being reversed or not. - * - * @param configuration the patch configuration - * @return the target path for this patch - * @see PatchConfiguration#isReversed() - */ - public IPath getTargetPath(PatchConfiguration configuration); - - /** - * Apply this patch to the given file contents. The result provides the - * original and patch contents and also indicates whether some portions of - * the patch (called hunks) failed to apply. - * - * @param contents the file contents - * @param configuration the patch configuration - * @param monitor a progress monitor - * @return the result of the patch application - */ - public IFilePatchResult apply(IStorage contents, - PatchConfiguration configuration, IProgressMonitor monitor); - - /** - * Return the header information of the patch or - * null if there was no header text. - * The header may be multi-line. - * @return the header information of the patch or - * null - */ - public String getHeader(); - - /** - * Returns the milliseconds time value of the before date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the before date from the patch - * @since 3.4 - */ - public long getBeforeDate(); - - /** - * Returns the milliseconds time value of the after date from the patch, or - * DATE_UNKNOWN if the date is unknown. - * - * @return milliseconds time value of the after date from the patch - * @since 3.4 - */ - public long getAfterDate(); -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java deleted file mode 100644 index 4f229c3aa..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IFilePatchResult.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.io.InputStream; - -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.runtime.CoreException; - -/** - * A file patch result provides the results of an attempt to apply an - * {@link IFilePatch} to the contents of a file. * - *

- * This interface is not intended to be implemented by clients. Clients can - * obtain patch results from an {@link IFilePatch}. - *

- * - * @see IFilePatch - * @since 3.3 - */ -public interface IFilePatchResult { - - /** - * Return a stream the contains the original contents of the file before - * any portions of the patch have been applied. - * @return a stream to the original contents of the file before - * any portions of the patch have been applied - * @see #getPatchedContents() - */ - public InputStream getOriginalContents(); - - /** - * Return a stream that contains the file with as much of the patch - * applied as possible. if {@link #hasMatches()} returns false - * then the patched contents will match the original contents. Otherwise, - * at least a portion of the patch could be successfully applied. if - * {@link #hasRejects()} returns false, then the entire patch was - * applied. Otherwise, portions could not be applied. The portions that could - * not be applied can be obtained by calling {@link #getRejects()}. - * - * @return a stream that contains the file with as much of the patch - * applied as possible. - */ - public InputStream getPatchedContents(); - - /** - * Return whether the patch has portions that were successfully applied. - * @return whether the patch has portions that were successfully applied - * @see #getPatchedContents() - */ - public boolean hasMatches(); - - /** - * Return whether the patch has portions that were not successfully applied. - * @return whether the patch has portions that were not successfully applied - * @see #getPatchedContents() - */ - public boolean hasRejects(); - - /** - * Return the portions of the patch (referred to a hunks) that could not - * be applied. - * @return the portions of the patch (referred to a hunks) that could not - * be applied - * @see #getPatchedContents() - */ - public IHunk[] getRejects(); - - /** - * Returns the name of a charset encoding to be used when decoding the contents - * of this result into characters. Returns null if a proper - * encoding cannot be determined. - *

- * Note that this method does not check whether the result is a supported - * charset name. Callers should be prepared to handle - * UnsupportedEncodingException where this charset is used. - *

- * - * @return the name of a charset, or null - * @exception CoreException if an error happens while determining - * the charset. See any refinements for more information. - * @see IEncodedStorage - */ - public String getCharset() throws CoreException; - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java deleted file mode 100644 index 126150c0d..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/IHunk.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.io.InputStream; - -import org.eclipse.core.resources.IEncodedStorage; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; - -/** - * Interface that represents a hunk. A hunk is a portion of a patch. It - * identifies where the hunk is to be located in the target file. One use of - * this interface is a means to communicate to content merge viewers that one of - * the sides of a compare input is a patch hunk. Clients can determine which - * side it is by adapting the side to this interface (see {@link IAdaptable}. - *

- * This interface is not intended to be implemented by clients but can be - * obtained from an {@link IFilePatchResult} - *

- * - * @since 3.3 - * - */ -public interface IHunk { - - /** - * Return a label that can be used to describe the hunk. - * @return a label that can be used to describe the hunk - */ - public String getLabel(); - - /** - * Return the start position of the hunk in the target file. - * - * @return the start position of the hunk in the target file. - */ - public int getStartPosition(); - - /** - * Return the original contents from which the hunk was generated. - * The returned contents usually only represent a portion of the - * file from which the hunk was generated. - * @return the original contents from which the hunk was generated - */ - public InputStream getOriginalContents(); - - /** - * Return the contents that contain the modifications for this hunk. - * The returned contents usually only represent a portion of the - * file that was modified. - * @return the contents that contain the modifications for this hunk - */ - public InputStream getPatchedContents(); - - /** - * Returns the name of a charset encoding to be used when decoding the contents - * of this hunk into characters. Returns null if a proper - * encoding cannot be determined. - *

- * Note that this method does not check whether the result is a supported - * charset name. Callers should be prepared to handle - * UnsupportedEncodingException where this charset is used. - *

- * - * @return the name of a charset, or null - * @exception CoreException if an error happens while determining - * the charset. See any refinements for more information. - * @see IEncodedStorage - */ - public String getCharset() throws CoreException; - - -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java deleted file mode 100644 index 3287a4585..000000000 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/PatchConfiguration.java +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.compare.patch; - -import java.util.HashMap; - -/** - * A patch configuration allows clients to set parameters that control how a patch - * is applied. - *

- * This class may be instantiated by clients but is not intended to be subclassed. - *

- * @see IFilePatch - * @since 3.3 - */ -public class PatchConfiguration { - - private int fStripPrefixSegments; - private int fFuzz; - private boolean fIgnoreWhitespace= false; - private boolean fReverse= false; - private HashMap properties = new HashMap(); - - /** - * Return whether the patch should be reversed when applied. - * @return whether the patch should be reversed when applied - */ - public boolean isReversed() { - return fReverse; - } - - /** - * Set whether the patch should be reversed when applied. - * @param reversed whether the patch should be reversed when applied - */ - public void setReversed(boolean reversed) { - this.fReverse = reversed; - } - - /** - * Return the number of prefix segments to be stripped when attempting - * to apply a patch. - * @return the number of prefix segments to be stripped when attempting - * to apply a patch - */ - public int getPrefixSegmentStripCount() { - return fStripPrefixSegments; - } - - /** - * Set the number of prefix segments to be stripped when attempting - * to apply a patch. - * @param stripCount the number of prefix segments to be stripped when attempting - * to apply a patch. - */ - public void setPrefixSegmentStripCount(int stripCount) { - this.fStripPrefixSegments = stripCount; - } - - /** - * Return the fuzz factor to be used when applying a patch. - * If the fuzz factor is set to -1, then the patcher is to make a best - * effort to apply the patch by adjusting the fuzz factor - * accordingly. - * @return the fuzz factor to be used when applying a patch. - */ - public int getFuzz() { - return fFuzz; - } - - /** - * Set the fuzz factor to be used when applying a patch. - * @param fuzz the fuzz factor to be used when applying a patch. - */ - public void setFuzz(int fuzz) { - fFuzz = fuzz; - } - - /** - * Return whether whitespace should be ignored. - * @return whether whitespace should be ignored - */ - public boolean isIgnoreWhitespace() { - return fIgnoreWhitespace; - } - - /** - * Set whether whitespace should be ignored - * @param ignoreWhitespace whether whitespace should be ignored - */ - public void setIgnoreWhitespace(boolean ignoreWhitespace) { - fIgnoreWhitespace = ignoreWhitespace; - } - - /** - * Return the property associated with the given key or - * null if there is no property for the key. - * @param key the key - * @return the property associated with the given key or - * null - */ - public Object getProperty(String key) { - return properties.get(key); - } - - /** - * Set the property associated with the given key - * @param key the key - * @param value the value to be associated with the key - */ - public void setProperty(String key, Object value) { - properties.put(key, value); - } -} diff --git a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java index 7f44392e0..d19688b08 100644 --- a/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java +++ b/bundles/org.eclipse.compare/plugins/org.eclipse.compare/compare/org/eclipse/compare/patch/WorkspacePatcherUI.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.compare.patch; -import org.eclipse.compare.internal.patch.PatchReader; +import org.eclipse.compare.internal.core.patch.PatchReader; import org.eclipse.core.resources.IProject; /** diff --git a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/FileDiffResultTest.java b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/FileDiffResultTest.java index 39fa625f9..e21c7ec9a 100644 --- a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/FileDiffResultTest.java +++ b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/FileDiffResultTest.java @@ -18,9 +18,9 @@ import java.io.InputStream; import java.util.ArrayList; import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.internal.patch.FileDiff; -import org.eclipse.compare.internal.patch.FileDiffResult; -import org.eclipse.compare.internal.patch.Hunk; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.Hunk; import org.eclipse.compare.internal.patch.Patcher; import org.eclipse.compare.patch.ApplyPatchOperation; import org.eclipse.compare.patch.IFilePatch; @@ -218,7 +218,7 @@ public class FileDiffResultTest extends WorkspaceTest { private class MyFileDiff extends FileDiff { protected MyFileDiff() { super(null, 0, null, 0); - add(new Hunk(this, new int[] { 0, 0 }, new int[] { 0, 0 }, + add(Hunk.createHunk(this, new int[] { 0, 0 }, new int[] { 0, 0 }, new ArrayList(), false, false, false)); } } diff --git a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/LineReaderTest.java b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/LineReaderTest.java index 82e85461c..553ee0075 100644 --- a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/LineReaderTest.java +++ b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/LineReaderTest.java @@ -15,7 +15,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; -import org.eclipse.compare.internal.patch.LineReader; +import org.eclipse.compare.internal.core.patch.LineReader; import junit.framework.Assert; import junit.framework.TestCase; diff --git a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/PatchTest.java b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/PatchTest.java index 93b46521a..3cca6373e 100644 --- a/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/PatchTest.java +++ b/tests/org.eclipse.compare.tests/src/org/eclipse/compare/tests/PatchTest.java @@ -37,10 +37,9 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.eclipse.compare.internal.Utilities; -import org.eclipse.compare.internal.patch.FileDiff; -import org.eclipse.compare.internal.patch.FileDiffResult; -import org.eclipse.compare.internal.patch.LineReader; -import org.eclipse.compare.internal.patch.Patcher; +import org.eclipse.compare.internal.core.patch.FileDiff; +import org.eclipse.compare.internal.core.patch.FileDiffResult; +import org.eclipse.compare.internal.core.patch.LineReader; import org.eclipse.compare.internal.patch.WorkspacePatcher; import org.eclipse.compare.patch.ApplyPatchOperation; import org.eclipse.compare.patch.IFilePatch; @@ -180,7 +179,7 @@ public class PatchTest extends TestCase { List expected = new ArrayList(); expected.add("Index: old.txt\n"); expected.add("UID: 42\n"); - assertEquals(Patcher.createString(false, expected), Patcher.createString(false, lines)); + assertEquals(LineReader.createString(false, expected), LineReader.createString(false, lines)); } public void testDateUnknown() throws CoreException { @@ -504,7 +503,7 @@ public class PatchTest extends TestCase { private void filePatch(final String old, String patch, String expt) throws CoreException, IOException { LineReader lr= new LineReader(getReader(expt)); List inLines= lr.readLines(); - String expected = Patcher.createString(false, inLines); + String expected = LineReader.createString(false, inLines); IStorage oldStorage = new StringStorage(old); IStorage patchStorage = new StringStorage(patch); -- cgit v1.2.3