Added
Link Here
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 2013 Oracle and/or its affiliates. All rights reserved. |
5 |
* |
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates. |
7 |
* Other names may be trademarks of their respective owners. |
8 |
* |
9 |
* The contents of this file are subject to the terms of either the GNU |
10 |
* General Public License Version 2 only ("GPL") or the Common |
11 |
* Development and Distribution License("CDDL") (collectively, the |
12 |
* "License"). You may not use this file except in compliance with the |
13 |
* License. You can obtain a copy of the License at |
14 |
* http://www.netbeans.org/cddl-gplv2.html |
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
16 |
* specific language governing permissions and limitations under the |
17 |
* License. When distributing the software, include this License Header |
18 |
* Notice in each file and include the License file at |
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this |
20 |
* particular file as subject to the "Classpath" exception as provided |
21 |
* by Oracle in the GPL Version 2 section of the License file that |
22 |
* accompanied this code. If applicable, add the following below the |
23 |
* License Header, with the fields enclosed by brackets [] replaced by |
24 |
* your own identifying information: |
25 |
* "Portions Copyrighted [year] [name of copyright owner]" |
26 |
* |
27 |
* If you wish your version of this file to be governed by only the CDDL |
28 |
* or only the GPL Version 2, indicate your decision by adding |
29 |
* "[Contributor] elects to include this software in this distribution |
30 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
31 |
* single choice of license, a recipient has the option to distribute |
32 |
* your version of this file under either the CDDL, the GPL Version 2 or |
33 |
* to extend the choice of license to its licensees as provided above. |
34 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
35 |
* Version 2 license, then the option applies only if the new code is |
36 |
* made subject to such option by the copyright holder. |
37 |
* |
38 |
* Contributor(s): |
39 |
* |
40 |
* Portions Copyrighted 2013 Sun Microsystems, Inc. |
41 |
*/ |
42 |
package org.netbeans.modules.git.ui.rebase; |
43 |
|
44 |
import java.io.BufferedReader; |
45 |
import java.io.ByteArrayInputStream; |
46 |
import java.io.File; |
47 |
import java.io.FileReader; |
48 |
import java.io.IOException; |
49 |
import java.util.ArrayList; |
50 |
import java.util.Collection; |
51 |
import java.util.Collections; |
52 |
import java.util.Date; |
53 |
import java.util.HashMap; |
54 |
import java.util.List; |
55 |
import java.util.Map; |
56 |
import java.util.concurrent.Callable; |
57 |
import java.util.logging.Level; |
58 |
import java.util.logging.Logger; |
59 |
import javax.swing.JButton; |
60 |
import org.netbeans.libs.git.GitClient.RebaseOperationType; |
61 |
import org.netbeans.libs.git.GitException; |
62 |
import org.netbeans.libs.git.GitRebaseResult; |
63 |
import org.netbeans.libs.git.GitRepositoryState; |
64 |
import org.netbeans.libs.git.GitRevisionInfo; |
65 |
import org.netbeans.libs.git.SearchCriteria; |
66 |
import org.netbeans.libs.git.progress.ProgressMonitor; |
67 |
import org.netbeans.modules.git.Git; |
68 |
import org.netbeans.modules.git.client.GitClient; |
69 |
import org.netbeans.modules.git.client.GitClientExceptionHandler; |
70 |
import org.netbeans.modules.git.client.GitProgressSupport; |
71 |
import org.netbeans.modules.git.ui.actions.GitAction; |
72 |
import org.netbeans.modules.git.ui.actions.SingleRepositoryAction; |
73 |
import org.netbeans.modules.git.ui.conflicts.ResolveConflictsExecutor; |
74 |
import org.netbeans.modules.git.ui.output.OutputLogger; |
75 |
import org.netbeans.modules.git.utils.GitUtils; |
76 |
import org.netbeans.modules.git.utils.ResultProcessor; |
77 |
import org.openide.util.NbBundle; |
78 |
import org.netbeans.modules.git.ui.repository.RepositoryInfo; |
79 |
import org.netbeans.modules.versioning.hooks.GitHook; |
80 |
import org.netbeans.modules.versioning.hooks.GitHookContext; |
81 |
import org.netbeans.modules.versioning.hooks.VCSHooks; |
82 |
import org.netbeans.modules.versioning.spi.VCSContext; |
83 |
import org.netbeans.modules.versioning.util.FileUtils; |
84 |
import org.openide.DialogDisplayer; |
85 |
import org.openide.NotifyDescriptor; |
86 |
import org.openide.awt.ActionID; |
87 |
import org.openide.awt.ActionRegistration; |
88 |
import org.openide.awt.Mnemonics; |
89 |
|
90 |
/** |
91 |
* |
92 |
* @author Ondrej Vrabec |
93 |
*/ |
94 |
@ActionID(id = "org.netbeans.modules.git.ui.rebase.RebaseAction", category = "Git") |
95 |
@ActionRegistration(displayName = "#LBL_RebaseAction_Name") |
96 |
@NbBundle.Messages({ |
97 |
"LBL_RebaseAction_Name=&Rebase...", "LBL_RebaseAction_PopupName=Rebase..." |
98 |
}) |
99 |
public class RebaseAction extends SingleRepositoryAction { |
100 |
|
101 |
private static final Logger LOG = Logger.getLogger(RebaseAction.class.getName()); |
102 |
private static final String NETBEANS_REBASE_ORIGHEAD = "netbeans-rebase.orighead"; //NOI18N |
103 |
private static final String NETBEANS_REBASE_UPSTREAM = "netbeans-rebase.upstream"; //NOI18N |
104 |
private static final String NETBEANS_REBASE_ONTO = "netbeans-rebase.onto"; //NOI18N |
105 |
private static final String REBASE_MERGE_DIR = "rebase-merge"; //NOI18N |
106 |
|
107 |
@Override |
108 |
protected void performAction (File repository, File[] roots, VCSContext context) { |
109 |
RepositoryInfo info = RepositoryInfo.getInstance(repository); |
110 |
info.refresh(); |
111 |
rebase(repository, info); |
112 |
} |
113 |
|
114 |
@NbBundle.Messages({ |
115 |
"# {0} - repository state", "MSG_RebaseAction_rebaseNotAllowed=Rebase is not allowed in this state: {0}", |
116 |
"CTL_RebaseAction.continueButton.text=C&ontinue", |
117 |
"CTL_RebaseAction.continueButton.TTtext=Continue the interrupted rebase", |
118 |
"CTL_RebaseAction.abortButton.text=Abo&rt", |
119 |
"CTL_RebaseAction.abortButton.TTtext=Abort the interrupted rebase", |
120 |
"CTL_RebaseAction.skipButton.text=&Skip", |
121 |
"CTL_RebaseAction.skipButton.TTtext=Skip the current commit and continue the interrupted rebase", |
122 |
"LBL_Rebase.rebasingState.title=Unfinished Rebase", |
123 |
"# {0} - repository name", "MSG_Rebase.rebasingState.text=Repository {0} is in the middle of an unfinished rebase.\n" |
124 |
+ "Do you want to continue or abort the unfinished rebase\n" |
125 |
+ "or skip the current commit from the rebase?" |
126 |
}) |
127 |
private void rebase (File repository, RepositoryInfo info) { |
128 |
GitRepositoryState state = info.getRepositoryState(); |
129 |
if (state == GitRepositoryState.SAFE) { |
130 |
// should start |
131 |
} else if (state == GitRepositoryState.REBASING) { |
132 |
// abort or continue? |
133 |
JButton btnContinue = new JButton(); |
134 |
Mnemonics.setLocalizedText(btnContinue, Bundle.CTL_RebaseAction_continueButton_text()); |
135 |
btnContinue.setToolTipText(Bundle.CTL_RebaseAction_continueButton_TTtext()); |
136 |
JButton btnAbort = new JButton(); |
137 |
Mnemonics.setLocalizedText(btnAbort, Bundle.CTL_RebaseAction_abortButton_text()); |
138 |
btnAbort.setToolTipText(Bundle.CTL_RebaseAction_abortButton_TTtext()); |
139 |
JButton btnSkip = new JButton(); |
140 |
Mnemonics.setLocalizedText(btnSkip, Bundle.CTL_RebaseAction_skipButton_text()); |
141 |
btnSkip.setToolTipText(Bundle.CTL_RebaseAction_skipButton_TTtext()); |
142 |
Map<Object, RebaseOperationType> operations = new HashMap<Object, RebaseOperationType>(); |
143 |
operations.put(btnContinue, RebaseOperationType.CONTINUE); |
144 |
operations.put(btnSkip, RebaseOperationType.SKIP); |
145 |
operations.put(btnAbort, RebaseOperationType.ABORT); |
146 |
Object value = DialogDisplayer.getDefault().notify(new NotifyDescriptor( |
147 |
Bundle.MSG_Rebase_rebasingState_text(repository.getName()), |
148 |
Bundle.LBL_Rebase_rebasingState_title(), |
149 |
NotifyDescriptor.YES_NO_CANCEL_OPTION, |
150 |
NotifyDescriptor.QUESTION_MESSAGE, |
151 |
new Object[] { btnContinue, btnSkip, btnAbort, NotifyDescriptor.CANCEL_OPTION }, |
152 |
btnContinue)); |
153 |
RebaseOperationType op = operations.get(value); |
154 |
if (op != null) { |
155 |
finishRebase(repository, op); |
156 |
} |
157 |
} else { |
158 |
GitClientExceptionHandler.annotate(Bundle.MSG_RebaseAction_rebaseNotAllowed(state)); |
159 |
} |
160 |
} |
161 |
|
162 |
@NbBundle.Messages("MSG_RebaseAction_progress=Rebasing...") |
163 |
private void finishRebase (final File repository, final RebaseOperationType op) { |
164 |
GitProgressSupport supp = new GitProgressSupport() { |
165 |
|
166 |
@Override |
167 |
protected void perform () { |
168 |
try { |
169 |
GitUtils.runWithoutIndexing(new Callable<Void>() { |
170 |
@Override |
171 |
public Void call () throws Exception { |
172 |
String origHead = getRebaseFileContent(repository, NETBEANS_REBASE_ORIGHEAD); |
173 |
String onto = getOnto(repository); |
174 |
String upstream = getRebaseFileContent(repository, NETBEANS_REBASE_UPSTREAM); |
175 |
GitClient client = getClient(); |
176 |
RebaseResultProcessor rrp = new RebaseResultProcessor(client, repository, onto, upstream, origHead, |
177 |
getProgressSupport()); |
178 |
RebaseOperationType nextAction = op; |
179 |
while (nextAction != null && !isCanceled()) { |
180 |
GitRebaseResult result = client.rebase(nextAction, onto, getProgressMonitor()); |
181 |
rrp.processResult(result); |
182 |
nextAction = rrp.getNextAction(); |
183 |
} |
184 |
return null; |
185 |
} |
186 |
}); |
187 |
} catch (GitException ex) { |
188 |
GitClientExceptionHandler.notifyException(ex, true); |
189 |
} finally { |
190 |
setDisplayName(NbBundle.getMessage(GitAction.class, "LBL_Progress.RefreshingStatuses")); //NOI18N |
191 |
Git.getInstance().getFileStatusCache().refreshAllRoots(Collections.<File, Collection<File>>singletonMap(repository, Git.getInstance().getSeenRoots(repository))); |
192 |
GitUtils.headChanged(repository); |
193 |
} |
194 |
} |
195 |
|
196 |
private GitProgressSupport getProgressSupport () { |
197 |
return this; |
198 |
} |
199 |
}; |
200 |
supp.start(Git.getInstance().getRequestProcessor(repository), repository, Bundle.MSG_RebaseAction_progress()); |
201 |
} |
202 |
|
203 |
@NbBundle.Messages({ |
204 |
"MSG_RebaseAction.noMergeStrategies=Cannot continue rebase. It was probably started externally but without " |
205 |
+ "the merging algorithm (\"-m\" option) which is the only supported option in the NetBeans IDE.\n" |
206 |
+ "Please use the external tool you started rebase with to finish it." |
207 |
}) |
208 |
private static String getRebaseFileContent (File repository, String filename) throws GitException { |
209 |
File rebaseFolder = new File(GitUtils.getGitFolderForRoot(repository), REBASE_MERGE_DIR); |
210 |
if (rebaseFolder.exists()) { |
211 |
File file = new File(rebaseFolder, filename); |
212 |
if (file.canRead()) { |
213 |
BufferedReader br = null; |
214 |
try { |
215 |
br = new BufferedReader(new FileReader(file)); |
216 |
return br.readLine(); |
217 |
} catch (IOException ex) { |
218 |
LOG.log(Level.FINE, null, ex); |
219 |
} finally { |
220 |
if (br != null) { |
221 |
try { |
222 |
br.close(); |
223 |
} catch (IOException ex) {} |
224 |
} |
225 |
} |
226 |
} |
227 |
} else { |
228 |
throw new GitException(Bundle.MSG_RebaseAction_noMergeStrategies()); |
229 |
} |
230 |
return null; |
231 |
} |
232 |
|
233 |
private static String getOnto (File repository) throws GitException { |
234 |
String onto = getRebaseFileContent(repository, NETBEANS_REBASE_ONTO); |
235 |
if (onto == null) { |
236 |
onto = getRebaseFileContent(repository, "onto-name"); //NOI18N |
237 |
} |
238 |
if (onto == null) { |
239 |
onto = getRebaseFileContent(repository, "onto_name"); //NOI18N |
240 |
} |
241 |
if (onto == null) { |
242 |
onto = getRebaseFileContent(repository, "onto"); //NOI18N |
243 |
} |
244 |
return onto; |
245 |
} |
246 |
|
247 |
public static class RebaseResultProcessor extends ResultProcessor { |
248 |
|
249 |
private final OutputLogger logger; |
250 |
private final String onto; |
251 |
private final String origHead; |
252 |
private final String upstream; |
253 |
private RebaseOperationType nextAction; |
254 |
private final GitProgressSupport supp; |
255 |
|
256 |
public RebaseResultProcessor (GitClient client, File repository, String onto, String upstream, String origHead, |
257 |
GitProgressSupport supp) { |
258 |
super(client, repository, onto, supp.getProgressMonitor()); |
259 |
this.origHead = origHead; |
260 |
this.onto = onto; |
261 |
this.upstream = upstream; |
262 |
this.logger = supp.getLogger(); |
263 |
this.supp = supp; |
264 |
} |
265 |
|
266 |
@NbBundle.Messages({ |
267 |
"# {0} - rebase status", "MSG_RebaseAction.result=Rebase Result: {0}\n", |
268 |
"# {0} - head commit id", "MSG_RebaseAction.result.aborted=Rebase aborted and the current HEAD reset to {0}\n", |
269 |
"MSG_RebaseAction.result.conflict=Rebase interrupted because of conflicts in:\n", |
270 |
"# {0} - head commit id", "MSG_RebaseAction.result.ok=Rebase successfully finished and HEAD now points to {0}:\n", |
271 |
"# {0} - rebase target revision", "MSG_RebaseAction.result.alreadyUpToDate=HEAD already in sync with {0}" |
272 |
}) |
273 |
public void processResult (GitRebaseResult result) { |
274 |
nextAction = null; |
275 |
StringBuilder sb = new StringBuilder(Bundle.MSG_RebaseAction_result(result.getRebaseStatus().toString())); |
276 |
GitRevisionInfo info; |
277 |
try { |
278 |
info = client.log(GitUtils.HEAD, GitUtils.NULL_PROGRESS_MONITOR); |
279 |
} catch (GitException ex) { |
280 |
GitClientExceptionHandler.notifyException(ex, true); |
281 |
return; |
282 |
} |
283 |
persistNBConfig(); |
284 |
switch (result.getRebaseStatus()) { |
285 |
case ABORTED: |
286 |
sb.append(Bundle.MSG_RebaseAction_result_aborted(info.getRevision())); |
287 |
GitUtils.printInfo(sb, info); |
288 |
break; |
289 |
case FAILED: |
290 |
case CONFLICTS: |
291 |
if (LOG.isLoggable(Level.FINE)) { |
292 |
LOG.log(Level.FINE, "Local modifications in WT during rebase: {0} - {1}", new Object[] { repository, result.getFailures() }); //NOI18N |
293 |
} |
294 |
try { |
295 |
if (resolveLocalChanges(result.getFailures().toArray(new File[result.getFailures().size()]))) { |
296 |
nextAction = RebaseOperationType.BEGIN; |
297 |
} |
298 |
} catch (GitException ex) { |
299 |
GitClientExceptionHandler.notifyException(ex, true); |
300 |
} |
301 |
break; |
302 |
case NOTHING_TO_COMMIT: |
303 |
nextAction = resolveNothingToCommit(); |
304 |
break; |
305 |
case FAST_FORWARD: |
306 |
case OK: |
307 |
sb.append(Bundle.MSG_RebaseAction_result_ok(info.getRevision())); |
308 |
GitUtils.printInfo(sb, info); |
309 |
updatePushHooks(); |
310 |
break; |
311 |
case STOPPED: |
312 |
sb.append(Bundle.MSG_RebaseAction_result_conflict()); |
313 |
printConflicts(sb, result.getConflicts()); |
314 |
nextAction = resolveRebaseConflicts(result.getConflicts()); |
315 |
break; |
316 |
case UP_TO_DATE: |
317 |
sb.append(Bundle.MSG_RebaseAction_result_alreadyUpToDate(onto)); |
318 |
break; |
319 |
} |
320 |
logger.output(sb.toString()); |
321 |
} |
322 |
|
323 |
public RebaseOperationType getNextAction () { |
324 |
return nextAction; |
325 |
} |
326 |
|
327 |
@NbBundle.Messages({ |
328 |
"LBL_RebaseResultProcessor.abortButton.text=&Abort", |
329 |
"LBL_RebaseResultProcessor.abortButton.TTtext=Abort the interrupted rebase and reset back to the original commit.", |
330 |
"LBL_RebaseResultProcessor.resolveButton.text=&Resolve", |
331 |
"LBL_RebaseResultProcessor.resolveButton.TTtext=Files in conflict will be opened in a Resolve Conflict dialog.", |
332 |
"LBL_RebaseResultProcessor.resolveConflicts=Resolve Conflicts", |
333 |
"MSG_RebaseResultProcessor.resolveConflicts=Rebase produced unresolved conflicts.\n" |
334 |
+ "You can resolve them manually or review them in the Versioning view\n" |
335 |
+ "or completely abort the rebase.", |
336 |
"LBL_RebaseResultProcessor.revertButton.text=&Revert", |
337 |
"LBL_RebaseResultProcessor.revertButton.TTtext=Revert local changes to the state in the HEAD and removes unversioned files.", |
338 |
"LBL_RebaseResultProcessor.reviewButton.text=Re&view", |
339 |
"LBL_RebaseResultProcessor.reviewButton.TTtext=Opens the Versioning view and lists the conflicted files.", |
340 |
"MSG_Rebase.resolving=Resolving conflicts..." |
341 |
}) |
342 |
private RebaseOperationType resolveRebaseConflicts (Collection<File> conflicts) { |
343 |
RebaseOperationType action = null; |
344 |
JButton abort = new JButton(); |
345 |
Mnemonics.setLocalizedText(abort, Bundle.LBL_RebaseResultProcessor_abortButton_text()); |
346 |
abort.setToolTipText(Bundle.LBL_RebaseResultProcessor_abortButton_TTtext()); |
347 |
JButton resolve = new JButton(); |
348 |
Mnemonics.setLocalizedText(resolve, Bundle.LBL_RebaseResultProcessor_resolveButton_text()); |
349 |
resolve.setToolTipText(Bundle.LBL_RebaseResultProcessor_resolveButton_TTtext()); |
350 |
JButton review = new JButton(); |
351 |
Mnemonics.setLocalizedText(review, Bundle.LBL_RebaseResultProcessor_reviewButton_text()); |
352 |
review.setToolTipText(Bundle.LBL_RebaseResultProcessor_reviewButton_TTtext()); |
353 |
Object o = DialogDisplayer.getDefault().notify(new NotifyDescriptor( |
354 |
Bundle.MSG_RebaseResultProcessor_resolveConflicts(), |
355 |
Bundle.LBL_RebaseResultProcessor_resolveConflicts(), |
356 |
NotifyDescriptor.OK_CANCEL_OPTION, NotifyDescriptor.QUESTION_MESSAGE, |
357 |
new Object[] { resolve, review, abort, NotifyDescriptor.CANCEL_OPTION }, resolve)); |
358 |
if (o == review) { |
359 |
openInVersioningView(conflicts); |
360 |
} else if (o == resolve) { |
361 |
GitProgressSupport supp = new ResolveConflictsExecutor(conflicts.toArray(new File[conflicts.size()])); |
362 |
supp.start(Git.getInstance().getRequestProcessor(repository), repository, Bundle.MSG_Rebase_resolving()); |
363 |
} else if (o == abort) { |
364 |
action = RebaseOperationType.ABORT; |
365 |
} |
366 |
return action; |
367 |
} |
368 |
|
369 |
@NbBundle.Messages({ |
370 |
"LBL_RebaseResultProcessor.nothingToCommit=Nothing to Commit", |
371 |
"MSG_RebaseResultProcessor.nothingToCommit=No modifications to commit for the current rebase step.\n" |
372 |
+ "Do you want to skip the commit from the rebase and continue?", |
373 |
"LBL_RebaseResultProcessor.skipButton.text=&Skip", |
374 |
"LBL_RebaseResultProcessor.skipButton.TTtext=Skip the commit and continue rebase." |
375 |
}) |
376 |
private RebaseOperationType resolveNothingToCommit () { |
377 |
RebaseOperationType action = null; |
378 |
JButton abort = new JButton(); |
379 |
Mnemonics.setLocalizedText(abort, Bundle.LBL_RebaseResultProcessor_abortButton_text()); |
380 |
abort.setToolTipText(Bundle.LBL_RebaseResultProcessor_abortButton_TTtext()); |
381 |
JButton skip = new JButton(); |
382 |
Mnemonics.setLocalizedText(skip, Bundle.LBL_RebaseResultProcessor_skipButton_text()); |
383 |
skip.setToolTipText(Bundle.LBL_RebaseResultProcessor_skipButton_TTtext()); |
384 |
Object o = DialogDisplayer.getDefault().notify(new NotifyDescriptor( |
385 |
Bundle.MSG_RebaseResultProcessor_nothingToCommit(), |
386 |
Bundle.LBL_RebaseResultProcessor_nothingToCommit(), |
387 |
NotifyDescriptor.OK_CANCEL_OPTION, NotifyDescriptor.QUESTION_MESSAGE, |
388 |
new Object[] { skip, abort, NotifyDescriptor.CANCEL_OPTION }, skip)); |
389 |
if (o == skip) { |
390 |
action = RebaseOperationType.SKIP; |
391 |
} else if (o == abort) { |
392 |
action = RebaseOperationType.ABORT; |
393 |
} |
394 |
return action; |
395 |
} |
396 |
|
397 |
private void persistNBConfig () { |
398 |
if (onto != null && upstream != null && origHead != null) { |
399 |
File rebaseFolder = new File(GitUtils.getGitFolderForRoot(repository), REBASE_MERGE_DIR); |
400 |
if (rebaseFolder.canWrite()) { |
401 |
try { |
402 |
FileUtils.copyStreamToFile(new ByteArrayInputStream(onto.getBytes()), new File(rebaseFolder, NETBEANS_REBASE_ONTO)); |
403 |
FileUtils.copyStreamToFile(new ByteArrayInputStream(upstream.getBytes()), new File(rebaseFolder, NETBEANS_REBASE_UPSTREAM)); |
404 |
FileUtils.copyStreamToFile(new ByteArrayInputStream(origHead.getBytes()), new File(rebaseFolder, NETBEANS_REBASE_ORIGHEAD)); |
405 |
} catch (IOException ex) { |
406 |
LOG.log(Level.INFO, null, ex); |
407 |
} |
408 |
} |
409 |
} |
410 |
} |
411 |
|
412 |
@NbBundle.Messages("MSG_RebaseAction.updatingHooks=updating push hooks") |
413 |
private void updatePushHooks () { |
414 |
if (onto != null && upstream != null && origHead != null) { |
415 |
Collection<GitHook> hooks = VCSHooks.getInstance().getHooks(GitHook.class); |
416 |
if (!hooks.isEmpty() && !pm.isCanceled()) { |
417 |
supp.setProgress(Bundle.MSG_RebaseAction_updatingHooks()); |
418 |
try { |
419 |
GitHookContext.LogEntry[] originalEntries = getEntries(client, upstream, origHead, pm); |
420 |
if (pm.isCanceled()) { |
421 |
return; |
422 |
} |
423 |
GitHookContext.LogEntry[] newEntries = getEntries(client, onto, GitUtils.HEAD, pm); |
424 |
if (pm.isCanceled()) { |
425 |
return; |
426 |
} |
427 |
Map<String, String> mapping = findChangesetMapping(originalEntries, newEntries); |
428 |
for (GitHook gitHook : hooks) { |
429 |
gitHook.afterCommitReplace( |
430 |
new GitHookContext(new File[] { repository }, null, originalEntries), |
431 |
new GitHookContext(new File[] { repository }, null, newEntries), |
432 |
mapping); |
433 |
} |
434 |
} catch (GitException ex) { |
435 |
LOG.log(Level.INFO, null, ex); |
436 |
} |
437 |
} |
438 |
} |
439 |
} |
440 |
} |
441 |
|
442 |
private static Map<String, String> findChangesetMapping (GitHookContext.LogEntry[] originalEntries, GitHookContext.LogEntry[] newEntries) { |
443 |
Map<String, String> mapping = new HashMap<String, String>(originalEntries.length); |
444 |
for (GitHookContext.LogEntry original : originalEntries) { |
445 |
boolean found = false; |
446 |
for (GitHookContext.LogEntry newEntry : newEntries) { |
447 |
if (original.getChangeset().equals(newEntry.getChangeset()) || ( |
448 |
original.getDate().equals(newEntry.getDate()) |
449 |
&& original.getAuthor().equals(newEntry.getAuthor()) |
450 |
&& original.getMessage().equals(newEntry.getMessage()))) { |
451 |
// is it really the same commit??? |
452 |
mapping.put(original.getChangeset(), newEntry.getChangeset()); |
453 |
found = true; |
454 |
break; |
455 |
} |
456 |
} |
457 |
if (!found) { |
458 |
// delete ???? |
459 |
mapping.put(original.getChangeset(), null); |
460 |
} |
461 |
} |
462 |
return mapping; |
463 |
} |
464 |
|
465 |
private static GitHookContext.LogEntry[] getEntries (GitClient client, String revisionFrom, String revisionTo, |
466 |
ProgressMonitor pm) throws GitException { |
467 |
SearchCriteria crit = new SearchCriteria(); |
468 |
crit.setRevisionFrom(revisionFrom); |
469 |
crit.setRevisionTo(revisionTo); |
470 |
GitRevisionInfo[] log = client.log(crit, pm); |
471 |
return convertToEntries(log); |
472 |
} |
473 |
|
474 |
private static GitHookContext.LogEntry[] convertToEntries (GitRevisionInfo[] messages) { |
475 |
List<GitHookContext.LogEntry> entries = new ArrayList<GitHookContext.LogEntry>(messages.length); |
476 |
for (GitRevisionInfo msg : messages) { |
477 |
entries.add(new GitHookContext.LogEntry( |
478 |
msg.getFullMessage(), |
479 |
msg.getAuthor().toString(), |
480 |
msg.getRevision(), |
481 |
new Date(msg.getCommitTime()))); |
482 |
} |
483 |
return entries.toArray(new GitHookContext.LogEntry[entries.size()]); |
484 |
} |
485 |
|
486 |
} |