KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > compare > internal > patch > WorkspacePatcher


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.compare.internal.patch;
12
13 import java.util.*;
14
15 import org.eclipse.compare.internal.Utilities;
16 import org.eclipse.compare.structuremergeviewer.Differencer;
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.core.runtime.jobs.ISchedulingRule;
20 import org.eclipse.core.runtime.jobs.MultiRule;
21 import org.eclipse.swt.widgets.Shell;
22
23 /**
24  * A Patcher
25  * - knows how to parse various patch file formats into some in-memory structure,
26  * - holds onto the parsed data and the options to use when applying the patches,
27  * - knows how to apply the patches to files and folders.
28  */

29 public class WorkspacePatcher extends Patcher {
30
31     private DiffProject[] fDiffProjects;
32     private boolean fIsWorkspacePatch= false;
33     private final Map retargetedDiffs = new HashMap();
34
35     public WorkspacePatcher() {
36         // nothing to do
37
}
38
39     public WorkspacePatcher(IResource target) {
40         setTarget(target);
41     }
42     
43     protected void patchParsed(PatchReader patchReader) {
44         super.patchParsed(patchReader);
45         fDiffProjects = patchReader.getDiffProjects();
46         fIsWorkspacePatch = patchReader.isWorkspacePatch();
47     }
48     
49     public DiffProject[] getDiffProjects() {
50         return fDiffProjects;
51     }
52
53     boolean isWorkspacePatch() {
54         return fIsWorkspacePatch;
55     }
56
57     //---- parsing patch files
58

59     public void applyAll(IProgressMonitor pm, Shell shell, String JavaDoc title) throws CoreException {
60         if (!fIsWorkspacePatch) {
61             super.applyAll(pm, shell, title);
62         } else {
63             final int WORK_UNIT= 10;
64
65             // get all files to be modified in order to call validateEdit
66
List list= new ArrayList();
67             for (int j= 0; j < fDiffProjects.length; j++) {
68                 DiffProject diffProject= fDiffProjects[j];
69                 if (diffProject.getProject().isAccessible())
70                     list.addAll(Arrays.asList(getTargetFiles(diffProject)));
71             }
72             // validate the files for editing
73
if (!Utilities.validateResources(list, shell, title))
74                 return;
75
76             FileDiff[] diffs = getDiffs();
77             if (pm != null) {
78                 String JavaDoc message= PatchMessages.Patcher_Task_message;
79                 pm.beginTask(message, diffs.length * WORK_UNIT);
80             }
81
82             for (int i= 0; i < diffs.length; i++) {
83
84                 int workTicks= WORK_UNIT;
85
86                 FileDiff diff= diffs[i];
87                 if (isAccessible(diff)) {
88                     IFile file= getTargetFile(diff);
89                     IPath path= file.getProjectRelativePath();
90                     if (pm != null)
91                         pm.subTask(path.toString());
92                     createPath(file.getProject(), path);
93
94                     List failed= new ArrayList();
95
96                     int type= diff.getDiffType(isReversed());
97                     switch (type) {
98                         case Differencer.ADDITION :
99                             // patch it and collect rejected hunks
100
List result= apply(diff, file, true, failed);
101                             if (result != null)
102                                 store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks));
103                             workTicks -= WORK_UNIT;
104                             break;
105                         case Differencer.DELETION :
106                             file.delete(true, true, new SubProgressMonitor(pm, workTicks));
107                             workTicks -= WORK_UNIT;
108                             break;
109                         case Differencer.CHANGE :
110                             // patch it and collect rejected hunks
111
result= apply(diff, file, false, failed);
112                             if (result != null)
113                                 store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks));
114                             workTicks -= WORK_UNIT;
115                             break;
116                     }
117
118                     if (isGenerateRejectFile() && failed.size() > 0) {
119                         IPath pp= null;
120                         if (path.segmentCount() > 1) {
121                             pp= path.removeLastSegments(1);
122                             pp= pp.append(path.lastSegment() + REJECT_FILE_EXTENSION);
123                         } else
124                             pp= new Path(path.lastSegment() + REJECT_FILE_EXTENSION);
125                         file= createPath(file.getProject(), pp);
126                         if (file != null) {
127                             store(getRejected(failed), file, pm);
128                             try {
129                                 IMarker marker= file.createMarker(MARKER_TYPE);
130                                 marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message);
131                                 marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
132                             } catch (CoreException ex) {
133                                 // NeedWork
134
}
135                         }
136                     }
137                 }
138
139                 if (pm != null) {
140                     if (pm.isCanceled())
141                         break;
142                     if (workTicks > 0)
143                         pm.worked(workTicks);
144                 }
145             }
146         }
147     }
148     
149     private boolean isAccessible(FileDiff diff) {
150         return isEnabled(diff) && diff.getProject().getProject().isAccessible();
151     }
152
153     /**
154      * Returns the target files of all the Diffs contained by this
155      * DiffProject.
156      * @param project
157      * @return An array of IFiles that are targeted by the Diffs
158      */

159     public IFile[] getTargetFiles(DiffProject project) {
160         List files= new ArrayList();
161         FileDiff[] diffs = project.getFileDiffs();
162         for (int i = 0; i < diffs.length; i++) {
163             FileDiff diff = diffs[i];
164             if (isEnabled(diff)) {
165                 files.add(getTargetFile(diff));
166             }
167         }
168         return (IFile[]) files.toArray(new IFile[files.size()]);
169     }
170
171     protected IFile getTargetFile(FileDiff diff) {
172         IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed());
173         DiffProject project = getProject(diff);
174         if (project != null)
175             return project.getFile(path);
176         return super.getTargetFile(diff);
177     }
178     
179     private IPath getFullPath(FileDiff diff) {
180         IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed());
181         DiffProject project = getProject(diff);
182         if (project != null)
183             return project.getFile(path).getFullPath();
184         return getTarget().getFullPath().append(path);
185     }
186
187     public ISchedulingRule[] getTargetProjects() {
188         List projects= new ArrayList();
189         IResourceRuleFactory ruleFactory= ResourcesPlugin.getWorkspace().getRuleFactory();
190         // Determine the appropriate scheduling rules
191
for (int i= 0; i < fDiffProjects.length; i++) {
192             IProject tempProject= fDiffProjects[i].getProject();
193             // The goal here is to lock as little of the workspace as necessary
194
// but still allow the patcher to obtain the locks it needs.
195
// As such, we need to get the modify rules from the rule factory for the .project file. A pessimistic
196
// rule factory will return the root, while others might return just the project. Combining
197
// this rule with the project will result in the smallest possible locking set.
198
ISchedulingRule scheduleRule= ruleFactory.modifyRule(tempProject.getFile(IProjectDescription.DESCRIPTION_FILE_NAME));
199             MultiRule multiRule= new MultiRule(new ISchedulingRule[] { scheduleRule, tempProject } );
200             projects.add(multiRule);
201         }
202     
203         return (ISchedulingRule[]) projects.toArray(new ISchedulingRule[projects.size()]);
204     }
205
206     public void setDiffProjects(DiffProject[] newProjectArray) {
207         fDiffProjects = new DiffProject[newProjectArray.length];
208         System.arraycopy(newProjectArray,0, fDiffProjects, 0, newProjectArray.length);
209     }
210
211     public void removeProject(DiffProject project) {
212         DiffProject[] temp = new DiffProject[fDiffProjects.length - 1];
213         int counter = 0;
214         for (int i = 0; i < fDiffProjects.length; i++) {
215             if (fDiffProjects[i] != project){
216                 temp[counter++] = fDiffProjects[i];
217             }
218         }
219         fDiffProjects = temp;
220     }
221     
222     protected Object JavaDoc getElementParent(Object JavaDoc element) {
223         if (element instanceof FileDiff && fDiffProjects != null) {
224             FileDiff diff = (FileDiff) element;
225             for (int i = 0; i < fDiffProjects.length; i++) {
226                 DiffProject project = fDiffProjects[i];
227                 if (project.contains(diff))
228                     return project;
229             }
230         }
231         return null;
232     }
233
234     public boolean isRetargeted(Object JavaDoc object) {
235         return retargetedDiffs.containsKey(object);
236     }
237     
238     public IPath getOriginalPath(Object JavaDoc object) {
239         return (IPath)retargetedDiffs.get(object);
240     }
241
242     public void retargetDiff(FileDiff diff, IFile file) {
243         retargetedDiffs.put(diff, diff.getPath(false));
244         Hunk[] hunks = diff.getHunks();
245         
246         if (isWorkspacePatch()){
247             //since the diff has no more hunks to apply, remove it from the parent and the patcher
248
diff.getProject().remove(diff);
249         }
250         removeDiff(diff);
251         FileDiff newDiff = getDiffForFile(file);
252         for (int i = 0; i < hunks.length; i++) {
253             Hunk hunk = hunks[i];
254             newDiff.add(hunk);
255         }
256     }
257
258     private FileDiff getDiffForFile(IFile file) {
259         DiffProject diffProject = null;
260         FileDiff[] diffsToCheck;
261         if (isWorkspacePatch()){
262             // Check if the diff project already exists for the file
263
IProject project = file.getProject();
264             DiffProject[] diffProjects = getDiffProjects();
265             for (int i = 0; i < diffProjects.length; i++) {
266                 if (diffProjects[i].getProject().equals(project)){
267                     diffProject = diffProjects[i];
268                     break;
269                 }
270             }
271             // If the project doesn't exist yet, create it and add it to the project list
272
if (diffProject == null){
273                 diffProject = addDiffProjectForProject(project);
274             }
275             diffsToCheck = diffProject.getFileDiffs();
276         } else {
277             diffsToCheck = getDiffs();
278         }
279         // Check to see if a diff already exists for the file
280
for (int i = 0; i < diffsToCheck.length; i++) {
281             FileDiff fileDiff = diffsToCheck[i];
282             if (isDiffForFile(fileDiff, file)) {
283                 return fileDiff;
284             }
285         }
286         
287         // Create a new diff for the file
288
IPath path = getDiffPath(file);
289         FileDiff newDiff = new FileDiff(path, 0, path, 0);
290         if (diffProject != null){
291             diffProject.add(newDiff);
292         }
293         addDiff(newDiff);
294         return newDiff;
295     }
296
297     private IPath getDiffPath(IFile file) {
298         DiffProject project = getDiffProject(file.getProject());
299         if (project != null) {
300             return file.getProjectRelativePath();
301         }
302         return file.getFullPath().removeFirstSegments(getTarget().getFullPath().segmentCount());
303     }
304
305     private boolean isDiffForFile(FileDiff fileDiff, IFile file) {
306         return getFullPath(fileDiff).equals(file.getFullPath());
307     }
308
309     private DiffProject addDiffProjectForProject(IProject project) {
310         DiffProject[] diffProjects = getDiffProjects();
311         DiffProject diffProject = new DiffProject(project);
312         DiffProject[] newProjectArray = new DiffProject[diffProjects.length + 1];
313         System.arraycopy(diffProjects, 0, newProjectArray, 0, diffProjects.length);
314         newProjectArray[diffProjects.length] = diffProject;
315         setDiffProjects(newProjectArray);
316         return diffProject;
317     }
318
319     public void retargetHunk(Hunk hunk, IFile file) {
320         FileDiff newDiff = getDiffForFile(file);
321         newDiff.add(hunk);
322     }
323
324     public void retargetProject(DiffProject project, IProject targetProject) {
325         retargetedDiffs.put(project, project.getProject().getFullPath());
326         FileDiff[] diffs = project.getFileDiffs();
327         DiffProject selectedProject = getDiffProject(targetProject);
328         if (selectedProject == null)
329             selectedProject = addDiffProjectForProject(targetProject);
330         // Copy over the diffs to the new project
331
for (int i = 0; i < diffs.length; i++) {
332             selectedProject.add(diffs[i]);
333         }
334         // Since the project has been retargeted, remove it from the patcher
335
removeProject(project);
336     }
337     
338     /**
339      * Return the diff project for the given project
340      * or <code>null</code> if the diff project doesn't exist
341      * or if the patch is not a workspace patch.
342      * @param project the project
343      * @return the diff project for the given project
344      * or <code>null</code>
345      */

346     private DiffProject getDiffProject(IProject project) {
347         if (!isWorkspacePatch())
348             return null;
349         DiffProject[] projects = getDiffProjects();
350         for (int i = 0; i < projects.length; i++) {
351             if (projects[i].getProject().equals(project))
352                 return projects[i];
353         }
354         return null;
355     }
356     
357     int getStripPrefixSegments() {
358         // Segments are never stripped from a workspace patch
359
if (isWorkspacePatch())
360             return 0;
361         return super.getStripPrefixSegments();
362     }
363     
364 }
365
Popular Tags