Java tutorial
/******************************************************************************* * Copyright (c) 2005, 2012 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.team.internal.ccvs.ui.operations; import java.io.*; import java.util.*; import org.eclipse.compare.patch.WorkspacePatcherUI; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.osgi.util.NLS; import org.eclipse.team.internal.ccvs.core.*; import org.eclipse.team.internal.ccvs.core.client.*; import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; import org.eclipse.team.internal.ccvs.core.client.listeners.DiffListener; import org.eclipse.team.internal.ccvs.core.connection.CVSCommunicationException; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.ui.CVSUIMessages; import org.eclipse.team.internal.ccvs.ui.Policy; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.statushandlers.*; public abstract class DiffOperation extends SingleCommandOperation { private static final int UNIFIED_FORMAT = 0; private static final int CONTEXT_FORMAT = 1; private static final int STANDARD_FORMAT = 2; protected boolean isMultiPatch; protected boolean includeFullPathInformation; protected PrintStream stream; protected IPath patchRoot; protected boolean patchHasContents; protected boolean patchHasNewFiles; /* see bug 116427 */ private Object destination = null; /* see bug 159894 */ private class CustomizableEOLPrintStream extends PrintStream { private boolean error = false; private String defaultLineEnding = "\n"; //$NON-NLS-1$ public CustomizableEOLPrintStream(PrintStream openStream) { super(openStream); if (CVSProviderPlugin.getPlugin().isUsePlatformLineend()) { defaultLineEnding = System.getProperty("line.separator"); //$NON-NLS-1$ } } public boolean checkError() { return error || super.checkError(); } public void println() { try { write(defaultLineEnding.getBytes()); } catch (IOException e) { error = true; } } public void println(boolean x) { print(x); println(); } public void println(char x) { print(x); println(); } public void println(char[] x) { print(x); println(); } public void println(double x) { print(x); println(); } public void println(float x) { print(x); println(); } public void println(int x) { print(x); println(); } public void println(long x) { print(x); println(); } public void println(Object x) { print(x); println(); } public void println(String x) { print(x); println(); } } public DiffOperation(IWorkbenchPart part, ResourceMapping[] mappings, LocalOption[] options, boolean isMultiPatch, boolean includeFullPathInformation, IPath patchRoot, Object destination) { super(part, mappings, options); this.isMultiPatch = isMultiPatch; this.includeFullPathInformation = includeFullPathInformation; this.patchRoot = patchRoot; this.patchHasContents = false; this.patchHasNewFiles = false; this.destination = destination; } protected boolean shouldRun() { if (super.shouldRun() == false) { return false; } Job[] jobs = Job.getJobManager().find(destination); if (jobs.length != 0) { MessageDialog question = new MessageDialog(getShell(), CVSUIMessages.DiffOperation_CreatePatchConflictTitle, null, NLS.bind(CVSUIMessages.DiffOperation_CreatePatchConflictMessage, destination.toString()), MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1); if (question.open() == 0) { Job.getJobManager().cancel(destination); } else { return false; } } return true; } public void execute(IProgressMonitor monitor) throws CVSException, InterruptedException { try { stream = new CustomizableEOLPrintStream(openStream()); if (isMultiPatch) { stream.println(WorkspacePatcherUI.getWorkspacePatchHeader()); } super.execute(monitor); } finally { if (stream != null) { stream.close(); } } } /** * Open and return a stream for the diff output. * @return a stream for the diff output */ protected abstract PrintStream openStream() throws CVSException; private static Comparator COMPARATOR = new Comparator() { private int compare(IResource r1, IResource r2) { return r1.getFullPath().toString().compareTo(r2.getFullPath().toString()); } public int compare(Object o1, Object o2) { IResource r1 = null; IResource r2 = null; if (o1 instanceof ICVSResource) { r1 = ((ICVSResource) o1).getIResource(); } else { r1 = (IResource) o1; } if (o2 instanceof ICVSResource) { r2 = ((ICVSResource) o2).getIResource(); } else { r2 = (IResource) o2; } return compare(r1, r2); } }; protected void execute(CVSTeamProvider provider, IResource[] resources, boolean recurse, IProgressMonitor monitor) throws CVSException, InterruptedException { //add this project to the total projects encountered final HashSet newFiles = new HashSet(); //array of ICVSResource - need HashSet to guard for duplicate entries final HashSet existingFiles = new HashSet(); //array of IResource - need HashSet to guard for duplicate entries monitor.beginTask(null, 100); final IProgressMonitor subMonitor = Policy.subMonitorFor(monitor, 10); for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource); cvsResource.accept(new ICVSResourceVisitor() { public void visitFile(ICVSFile file) throws CVSException { if (!(file.isIgnored())) { if (!file.isManaged() || file.getSyncInfo().isAdded()) { //this is a new file if (file.exists()) newFiles.add(file); } else if (file.isModified(subMonitor)) { existingFiles.add(file.getIResource()); } } } public void visitFolder(ICVSFolder folder) throws CVSException { // Even if we are not supposed to recurse we still need to go into // the root directory. if (!folder.exists() || folder.isIgnored()) { return; } folder.acceptChildren(this); } }, recurse); } final SortedSet allFiles = new TreeSet(COMPARATOR); allFiles.addAll(existingFiles); allFiles.addAll(newFiles); subMonitor.done(); //Check options //Append our diff output to the server diff output. // Our diff output includes new files and new files in new directories. int format = STANDARD_FORMAT; LocalOption[] localoptions = getLocalOptions(recurse); for (int i = 0; i < localoptions.length; i++) { LocalOption option = localoptions[i]; if (option.equals(Diff.UNIFIED_FORMAT) || isMultiPatch) { format = UNIFIED_FORMAT; } else if (option.equals(Diff.CONTEXT_FORMAT)) { format = CONTEXT_FORMAT; } } boolean haveAddedProjectHeader = false; if (!existingFiles.isEmpty()) { if (isMultiPatch && !haveAddedProjectHeader) { haveAddedProjectHeader = true; IProject project = resources[0].getProject(); stream.println(WorkspacePatcherUI.getWorkspacePatchProjectHeader(project)); } } if (!newFiles.isEmpty() && Diff.INCLUDE_NEWFILES.isElementOf(localoptions)) { //Set new file to flag to let us know that we have added something to the current patch patchHasNewFiles = true; if (isMultiPatch && !haveAddedProjectHeader) { haveAddedProjectHeader = true; IProject project = resources[0].getProject(); stream.println(WorkspacePatcherUI.getWorkspacePatchProjectHeader(project)); } } List existingFilesSubList = new ArrayList(); for (Iterator iter = allFiles.iterator(); iter.hasNext();) { Object file = iter.next(); if (existingFiles.contains(file)) { existingFilesSubList.add(file); } else if (newFiles.contains(file)) { addExistingFilesSubListToDiff(provider, existingFilesSubList, recurse, monitor, existingFiles.size()); ICVSFile cvsFile = (ICVSFile) file; addFileToDiff(getNewFileRoot(cvsFile), cvsFile, stream, format); } } addExistingFilesSubListToDiff(provider, existingFilesSubList, recurse, monitor, existingFiles.size()); monitor.done(); } private void addExistingFilesSubListToDiff(CVSTeamProvider provider, Collection subList, boolean recurse, IProgressMonitor monitor, int existingFilesTotal) throws InterruptedException { if (!subList.isEmpty()) { int ticks = 90 * subList.size() / existingFilesTotal; try { super.execute(provider, (IResource[]) subList.toArray(new IResource[subList.size()]), recurse, Policy.subMonitorFor(monitor, ticks)); } catch (CVSCommunicationException ex) { // see bug 123430 StatusAdapter adapter = new StatusAdapter(ex.getStatus()); adapter.setProperty(IStatusAdapterConstants.TITLE_PROPERTY, CVSUIMessages.DiffOperation_ErrorsOccurredWhileCreatingThePatch); StatusManager.getManager().handle(adapter, StatusManager.SHOW | StatusManager.NONE); } catch (CVSException ex) { handleCVSException(ex); } subList.clear(); } } /** * Checks if the exception contain a status that has to be shown to the * user. If yes, the method shows the dialog. * * @param ex exception to handle */ private void handleCVSException(CVSException ex) { IStatus status = ex.getStatus(); List toShow = new ArrayList(); IStatus children[] = status.getChildren(); boolean may = true; for (int i = 0; i < children.length; i++) { // ignore all errors except those found by DiffListener if (children[i].getCode() == CVSStatus.BINARY_FILES_DIFFER || children[i].getCode() == CVSStatus.PROTOCOL_ERROR || children[i].getCode() == CVSStatus.ERROR_LINE) { toShow.add(children[i]); if (children[i].getCode() == CVSStatus.BINARY_FILES_DIFFER) // the patch does not contain some changes for sure may = false; } } if (toShow.size() > 0) { String msg = may ? CVSUIMessages.DiffOperation_ThePatchMayNotContainAllTheChanges : CVSUIMessages.DiffOperation_ThePatchDoesNotContainAllTheChanges; StatusAdapter adapter = new StatusAdapter(new MultiStatus(CVSProviderPlugin.ID, CVSStatus.SERVER_ERROR, (IStatus[]) toShow.toArray(new IStatus[toShow.size()]), CVSUIMessages.DiffOperation_ErrorsOccurredWhileCreatingThePatch, null)); adapter.setProperty(IStatusAdapterConstants.TITLE_PROPERTY, msg); StatusManager.getManager().handle(adapter, StatusManager.SHOW | StatusManager.LOG); } } private ICVSFolder getNewFileRoot(ICVSFile cvsFile) { ICVSFolder patchRootFolder = getPatchRootFolder(); if (patchRootFolder != null) return patchRootFolder; return CVSWorkspaceRoot.getCVSFolderFor(cvsFile.getIResource().getProject()); } protected IStatus executeCommand(Session session, CVSTeamProvider provider, ICVSResource[] resources, boolean recurse, IProgressMonitor monitor) throws CVSException, InterruptedException { DiffListener diffListener = new DiffListener(stream); IStatus status = Command.DIFF.execute(session, Command.NO_GLOBAL_OPTIONS, getLocalOptions(recurse), resources, diffListener, monitor); //Once any run of the Diff commands reports that it has written something to the stream, the patch //in its entirety is considered non-empty - until then keep trying to set the flag. if (!patchHasContents) patchHasContents = diffListener.wroteToStream(); return status; } protected String getTaskName(CVSTeamProvider provider) { return NLS.bind(CVSUIMessages.DiffOperation_0, new String[] { provider.getProject().getName() }); } protected String getTaskName() { return CVSUIMessages.DiffOperation_1; } Map getProviderTraversalMapping(IProgressMonitor monitor) throws CoreException { Map providerTraversal = super.getProviderTraversalMapping(monitor); SortedMap result = new TreeMap(new Comparator() { public int compare(Object o1, Object o2) { CVSTeamProvider p1 = (CVSTeamProvider) o1; CVSTeamProvider p2 = (CVSTeamProvider) o2; return COMPARATOR.compare(p1.getProject(), p2.getProject()); } }); result.putAll(providerTraversal); return result; } private void addFileToDiff(ICVSFolder patchRoot, ICVSFile file, PrintStream printStream, int format) throws CVSException { String nullFilePrefix = ""; //$NON-NLS-1$ String newFilePrefix = ""; //$NON-NLS-1$ String positionInfo = ""; //$NON-NLS-1$ String linePrefix = ""; //$NON-NLS-1$ String pathString = ""; //$NON-NLS-1$ //get the path string for this file pathString = file.getRelativePath(patchRoot); int lines = 0; BufferedReader fileReader = new BufferedReader(new InputStreamReader(file.getContents())); try { while (fileReader.readLine() != null) { lines++; } } catch (IOException e) { throw CVSException.wrapException(file.getIResource(), NLS.bind(CVSUIMessages.DiffOperation_ErrorAddingFileToDiff, new String[] { pathString }), e); } finally { try { fileReader.close(); } catch (IOException e1) { //ignore } } // Ignore empty files if (lines == 0) return; switch (format) { case UNIFIED_FORMAT: nullFilePrefix = "--- "; //$NON-NLS-1$ newFilePrefix = "+++ "; //$NON-NLS-1$ positionInfo = "@@ -0,0 +1," + lines + " @@"; //$NON-NLS-1$ //$NON-NLS-2$ linePrefix = "+"; //$NON-NLS-1$ break; case CONTEXT_FORMAT: nullFilePrefix = "*** "; //$NON-NLS-1$ newFilePrefix = "--- "; //$NON-NLS-1$ positionInfo = "--- 1," + lines + " ----"; //$NON-NLS-1$ //$NON-NLS-2$ linePrefix = "+ "; //$NON-NLS-1$ break; default: positionInfo = "0a1," + lines; //$NON-NLS-1$ linePrefix = "> "; //$NON-NLS-1$ break; } fileReader = new BufferedReader(new InputStreamReader(file.getContents())); try { printStream.println("Index: " + pathString); //$NON-NLS-1$ printStream.println("==================================================================="); //$NON-NLS-1$ printStream.println("RCS file: " + pathString); //$NON-NLS-1$ printStream.println("diff -N " + pathString); //$NON-NLS-1$ if (format != STANDARD_FORMAT) { printStream.println(nullFilePrefix + "/dev/null 1 Jan 1970 00:00:00 -0000"); //$NON-NLS-1$ // Technically this date should be the local file date but nobody really cares. printStream.println(newFilePrefix + pathString + " 1 Jan 1970 00:00:00 -0000"); //$NON-NLS-1$ } if (format == CONTEXT_FORMAT) { printStream.println("***************"); //$NON-NLS-1$ printStream.println("*** 0 ****"); //$NON-NLS-1$ } printStream.println(positionInfo); for (int i = 0; i < lines - 1; i++) { printStream.print(linePrefix); printStream.println(fileReader.readLine()); } printStream.print(linePrefix); readLastLine(fileReader, printStream); } catch (IOException e) { throw CVSException.wrapException(file.getIResource(), NLS.bind(CVSUIMessages.DiffOperation_ErrorAddingFileToDiff, new String[] { pathString }), e); } finally { try { fileReader.close(); } catch (IOException e1) { } } } // based on org.eclipse.compare.internal.core.patch.LineReader.readLine() private void readLastLine(BufferedReader reader, PrintStream printStream) throws IOException { boolean sawCRorLF = false; boolean sawEOF = false; // TODO: hardcoded, set to the same value as initially in LineReader boolean ignoreSingleCR = false; while (!sawEOF) { int c = reader.read(); if (c == -1) { sawEOF = true; break; } printStream.print((char) c); if (c == '\n') { sawCRorLF = true; break; } if (c == '\r') { sawCRorLF = true; c = reader.read(); if (c == -1) { sawEOF = true; break; // EOF } if (c != '\n') { if (ignoreSingleCR) { sawCRorLF = false; printStream.print((char) c); continue; } } else { // '\n' printStream.print((char) c); } break; } } if (!sawCRorLF) { printStream.println(); printStream.println("\\ No newline at end of file"); //$NON-NLS-1$ } } public void setStream(PrintStream stream) { this.stream = new CustomizableEOLPrintStream(stream); } protected void reportEmptyDiff() { StatusAdapter adapter = new StatusAdapter( new Status(IStatus.INFO, CVSProviderPlugin.ID, CVSUIMessages.GenerateCVSDiff_noDiffsFoundMsg)); adapter.setProperty(IStatusAdapterConstants.TITLE_PROPERTY, CVSUIMessages.GenerateCVSDiff_noDiffsFoundTitle); StatusManager.getManager().handle(adapter, StatusManager.SHOW); } protected ICVSFolder getLocalRoot(CVSTeamProvider provider) throws CVSException { ICVSFolder root = getPatchRootFolder(); if (root != null) return root; return super.getLocalRoot(provider); } private ICVSFolder getPatchRootFolder() { if (!isMultiPatch && !includeFullPathInformation) { //Check to see if the selected patchRoot has enough segments to consider it a folder/resource //if not just get the project IResource patchFolder = null; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); if (patchRoot.segmentCount() > 1) { patchFolder = root.getFolder(patchRoot); } else { patchFolder = root.getProject(patchRoot.toString()); } ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(patchFolder); if (!cvsResource.isFolder()) { cvsResource = cvsResource.getParent(); } return (ICVSFolder) cvsResource; } return null; } /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.ui.operations.RepositoryProviderOperation#consultModelsForMappings() */ public boolean consultModelsForMappings() { return false; } public boolean belongsTo(Object family) { if (family != null && family.equals(destination)) return true; return super.belongsTo(family); } }