Use try-with-resource to avoid leaks with RevWalk and TreeWalk
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / fetch / FetchGerritChangePage.java
blobefab8be7541fbc53abb717b0f8046d9b4ea9dfef
1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 SAP AG 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
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 * Marc Khouzam (Ericsson) - Add an option not to checkout the new branch
11 *******************************************************************************/
12 package org.eclipse.egit.ui.internal.fetch;
14 import java.io.IOException;
15 import java.lang.reflect.InvocationTargetException;
16 import java.net.URISyntaxException;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.List;
21 import java.util.SortedSet;
22 import java.util.TreeSet;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25 import java.util.regex.PatternSyntaxException;
27 import org.eclipse.core.resources.WorkspaceJob;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.jobs.Job;
32 import org.eclipse.egit.core.op.CreateLocalBranchOperation;
33 import org.eclipse.egit.core.op.ListRemoteOperation;
34 import org.eclipse.egit.core.op.TagOperation;
35 import org.eclipse.egit.ui.Activator;
36 import org.eclipse.egit.ui.JobFamilies;
37 import org.eclipse.egit.ui.UIPreferences;
38 import org.eclipse.egit.ui.UIUtils;
39 import org.eclipse.egit.ui.internal.UIText;
40 import org.eclipse.egit.ui.internal.ValidationUtils;
41 import org.eclipse.egit.ui.internal.branch.BranchOperationUI;
42 import org.eclipse.egit.ui.internal.dialogs.AbstractBranchSelectionDialog;
43 import org.eclipse.egit.ui.internal.dialogs.BranchEditDialog;
44 import org.eclipse.egit.ui.internal.dialogs.CheckoutConflictDialog;
45 import org.eclipse.jface.bindings.keys.KeyStroke;
46 import org.eclipse.jface.dialogs.Dialog;
47 import org.eclipse.jface.dialogs.IDialogSettings;
48 import org.eclipse.jface.dialogs.IInputValidator;
49 import org.eclipse.jface.fieldassist.ContentProposalAdapter;
50 import org.eclipse.jface.fieldassist.IContentProposal;
51 import org.eclipse.jface.fieldassist.IContentProposalProvider;
52 import org.eclipse.jface.fieldassist.TextContentAdapter;
53 import org.eclipse.jface.layout.GridDataFactory;
54 import org.eclipse.jface.operation.IRunnableWithProgress;
55 import org.eclipse.jface.resource.JFaceResources;
56 import org.eclipse.jface.window.Window;
57 import org.eclipse.jface.wizard.WizardPage;
58 import org.eclipse.jgit.api.CheckoutCommand;
59 import org.eclipse.jgit.api.CheckoutResult;
60 import org.eclipse.jgit.api.CheckoutResult.Status;
61 import org.eclipse.jgit.api.Git;
62 import org.eclipse.jgit.api.errors.CheckoutConflictException;
63 import org.eclipse.jgit.api.errors.GitAPIException;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.PersonIdent;
66 import org.eclipse.jgit.lib.Ref;
67 import org.eclipse.jgit.lib.Repository;
68 import org.eclipse.jgit.lib.TagBuilder;
69 import org.eclipse.jgit.revwalk.RevCommit;
70 import org.eclipse.jgit.revwalk.RevWalk;
71 import org.eclipse.jgit.transport.FetchResult;
72 import org.eclipse.jgit.transport.RefSpec;
73 import org.eclipse.jgit.transport.RemoteConfig;
74 import org.eclipse.jgit.transport.URIish;
75 import org.eclipse.osgi.util.NLS;
76 import org.eclipse.swt.SWT;
77 import org.eclipse.swt.dnd.Clipboard;
78 import org.eclipse.swt.dnd.TextTransfer;
79 import org.eclipse.swt.events.ModifyEvent;
80 import org.eclipse.swt.events.ModifyListener;
81 import org.eclipse.swt.events.SelectionAdapter;
82 import org.eclipse.swt.events.SelectionEvent;
83 import org.eclipse.swt.layout.GridData;
84 import org.eclipse.swt.layout.GridLayout;
85 import org.eclipse.swt.widgets.Button;
86 import org.eclipse.swt.widgets.Combo;
87 import org.eclipse.swt.widgets.Composite;
88 import org.eclipse.swt.widgets.Group;
89 import org.eclipse.swt.widgets.Label;
90 import org.eclipse.swt.widgets.Shell;
91 import org.eclipse.swt.widgets.Text;
92 import org.eclipse.ui.IWorkbenchCommandConstants;
93 import org.eclipse.ui.PlatformUI;
95 /**
96 * Fetch a change from Gerrit
98 public class FetchGerritChangePage extends WizardPage {
99 private static final String FETCH_GERRIT_CHANGE_PAGE_SECTION = "FetchGerritChangePage"; //$NON-NLS-1$
101 private static final String LAST_URI_POSTFIX = ".lastUri"; //$NON-NLS-1$
103 private static final String RUN_IN_BACKGROUND = "runInBackground"; //$NON-NLS-1$
105 private final Repository repository;
107 private final IDialogSettings settings;
109 private final String lastUriKey;
111 private Combo uriCombo;
113 private List<Change> changeRefs;
115 private Text refText;
117 private Button createBranch;
119 private Button createTag;
121 private Button checkout;
123 private Button dontCheckout;
125 private Label tagTextlabel;
127 private Text tagText;
129 private Label branchTextlabel;
131 private Text branchText;
133 private String refName;
135 private Composite warningAdditionalRefNotActive;
137 private Button activateAdditionalRefs;
139 private Button runInBackgroud;
141 private IInputValidator branchValidator;
142 private IInputValidator tagValidator;
144 private Button branchEditButton;
146 private Button branchCheckoutButton;
149 * @param repository
150 * @param refName initial value for the ref field
152 public FetchGerritChangePage(Repository repository, String refName) {
153 super(FetchGerritChangePage.class.getName());
154 this.repository = repository;
155 this.refName = refName;
156 setTitle(NLS
157 .bind(UIText.FetchGerritChangePage_PageTitle,
158 Activator.getDefault().getRepositoryUtil()
159 .getRepositoryName(repository)));
160 setMessage(UIText.FetchGerritChangePage_PageMessage);
161 settings = getDialogSettings();
162 lastUriKey = repository + LAST_URI_POSTFIX;
164 branchValidator = ValidationUtils.getRefNameInputValidator(repository,
165 Constants.R_HEADS, true);
166 tagValidator = ValidationUtils.getRefNameInputValidator(repository,
167 Constants.R_TAGS, true);
170 @Override
171 protected IDialogSettings getDialogSettings() {
172 IDialogSettings s = Activator.getDefault().getDialogSettings();
173 IDialogSettings section = s
174 .getSection(FETCH_GERRIT_CHANGE_PAGE_SECTION);
175 if (section == null)
176 section = s.addNewSection(FETCH_GERRIT_CHANGE_PAGE_SECTION);
177 return section;
180 @Override
181 public void createControl(Composite parent) {
182 Clipboard clipboard = new Clipboard(parent.getDisplay());
183 String clipText = (String) clipboard.getContents(TextTransfer
184 .getInstance());
185 String defaultUri = null;
186 String defaultCommand = null;
187 String defaultChange = null;
188 if (clipText != null) {
189 final String pattern = "git fetch (\\w+:\\S+) (refs/changes/\\d+/\\d+/\\d+) && git (\\w+) FETCH_HEAD"; //$NON-NLS-1$
190 Matcher matcher = Pattern.compile(pattern).matcher(clipText);
191 if (matcher.matches()) {
192 defaultUri = matcher.group(1);
193 defaultChange = matcher.group(2);
194 defaultCommand = matcher.group(3);
197 Composite main = new Composite(parent, SWT.NONE);
198 main.setLayout(new GridLayout(2, false));
199 GridDataFactory.fillDefaults().grab(true, true).applyTo(main);
200 new Label(main, SWT.NONE)
201 .setText(UIText.FetchGerritChangePage_UriLabel);
202 uriCombo = new Combo(main, SWT.DROP_DOWN);
203 GridDataFactory.fillDefaults().grab(true, false).applyTo(uriCombo);
204 uriCombo.addSelectionListener(new SelectionAdapter() {
205 @Override
206 public void widgetSelected(SelectionEvent e) {
207 changeRefs = null;
210 new Label(main, SWT.NONE)
211 .setText(UIText.FetchGerritChangePage_ChangeLabel);
212 refText = new Text(main, SWT.BORDER);
213 if (defaultChange != null)
214 refText.setText(defaultChange);
215 GridDataFactory.fillDefaults().grab(true, false).applyTo(refText);
216 addRefContentProposalToText(refText);
218 final Group checkoutGroup = new Group(main, SWT.SHADOW_ETCHED_IN);
219 checkoutGroup.setLayout(new GridLayout(3, false));
220 GridDataFactory.fillDefaults().span(3, 1).grab(true, false)
221 .applyTo(checkoutGroup);
222 checkoutGroup.setText(UIText.FetchGerritChangePage_AfterFetchGroup);
224 // radio: create local branch
225 createBranch = new Button(checkoutGroup, SWT.RADIO);
226 GridDataFactory.fillDefaults().span(1, 1).applyTo(createBranch);
227 createBranch.setText(UIText.FetchGerritChangePage_LocalBranchRadio);
228 createBranch.addSelectionListener(new SelectionAdapter() {
229 @Override
230 public void widgetSelected(SelectionEvent e) {
231 checkPage();
235 branchCheckoutButton = new Button(checkoutGroup, SWT.CHECK);
236 GridDataFactory.fillDefaults().span(2, 1).align(SWT.END, SWT.CENTER)
237 .applyTo(branchCheckoutButton);
238 branchCheckoutButton.setFont(JFaceResources.getDialogFont());
239 branchCheckoutButton
240 .setText(UIText.FetchGerritChangePage_LocalBranchCheckout);
241 branchCheckoutButton.setSelection(true);
243 branchTextlabel = new Label(checkoutGroup, SWT.NONE);
244 GridDataFactory.defaultsFor(branchTextlabel).exclude(false)
245 .applyTo(branchTextlabel);
246 branchTextlabel.setText(UIText.FetchGerritChangePage_BranchNameText);
247 branchText = new Text(checkoutGroup, SWT.SINGLE | SWT.BORDER);
248 GridDataFactory.fillDefaults().grab(true, false).applyTo(branchText);
249 branchText.addModifyListener(new ModifyListener() {
250 @Override
251 public void modifyText(ModifyEvent e) {
252 checkPage();
256 branchEditButton = new Button(checkoutGroup, SWT.PUSH);
257 branchEditButton.setFont(JFaceResources.getDialogFont());
258 branchEditButton.setText(UIText.FetchGerritChangePage_BranchEditButton);
259 branchEditButton.addSelectionListener(new SelectionAdapter() {
260 @Override
261 public void widgetSelected(SelectionEvent selectionEvent) {
262 String txt = branchText.getText();
263 String refToMark = "".equals(txt) ? null : Constants.R_HEADS + txt; //$NON-NLS-1$
264 AbstractBranchSelectionDialog dlg = new BranchEditDialog(
265 checkoutGroup.getShell(), repository, refToMark);
266 if (dlg.open() == Window.OK) {
267 branchText.setText(Repository.shortenRefName(dlg
268 .getRefName()));
269 } else {
270 // force calling branchText's modify listeners
271 branchText.setText(branchText.getText());
275 GridDataFactory.defaultsFor(branchEditButton).exclude(false)
276 .applyTo(branchEditButton);
278 // radio: create tag
279 createTag = new Button(checkoutGroup, SWT.RADIO);
280 GridDataFactory.fillDefaults().span(3, 1).applyTo(createTag);
281 createTag.setText(UIText.FetchGerritChangePage_TagRadio);
282 createTag.addSelectionListener(new SelectionAdapter() {
283 @Override
284 public void widgetSelected(SelectionEvent e) {
285 checkPage();
289 tagTextlabel = new Label(checkoutGroup, SWT.NONE);
290 GridDataFactory.defaultsFor(tagTextlabel).exclude(true)
291 .applyTo(tagTextlabel);
292 tagTextlabel.setText(UIText.FetchGerritChangePage_TagNameText);
293 tagText = new Text(checkoutGroup, SWT.SINGLE | SWT.BORDER);
294 GridDataFactory.fillDefaults().exclude(true).grab(true, false)
295 .applyTo(tagText);
296 tagText.addModifyListener(new ModifyListener() {
297 @Override
298 public void modifyText(ModifyEvent e) {
299 checkPage();
303 // radio: checkout FETCH_HEAD
304 checkout = new Button(checkoutGroup, SWT.RADIO);
305 GridDataFactory.fillDefaults().span(3, 1).applyTo(checkout);
306 checkout.setText(UIText.FetchGerritChangePage_CheckoutRadio);
307 checkout.addSelectionListener(new SelectionAdapter() {
308 @Override
309 public void widgetSelected(SelectionEvent e) {
310 checkPage();
314 // radio: don't checkout
315 dontCheckout = new Button(checkoutGroup, SWT.RADIO);
316 GridDataFactory.fillDefaults().span(3, 1).applyTo(checkout);
317 dontCheckout.setText(UIText.FetchGerritChangePage_UpdateRadio);
318 dontCheckout.addSelectionListener(new SelectionAdapter() {
319 @Override
320 public void widgetSelected(SelectionEvent e) {
321 checkPage();
325 if ("checkout".equals(defaultCommand)) //$NON-NLS-1$
326 checkout.setSelection(true);
327 else
328 createBranch.setSelection(true);
330 warningAdditionalRefNotActive = new Composite(main, SWT.NONE);
331 GridDataFactory.fillDefaults().span(2, 1).grab(true, false)
332 .exclude(true).applyTo(warningAdditionalRefNotActive);
333 warningAdditionalRefNotActive.setLayout(new GridLayout(2, false));
334 warningAdditionalRefNotActive.setVisible(false);
336 activateAdditionalRefs = new Button(warningAdditionalRefNotActive,
337 SWT.CHECK);
338 activateAdditionalRefs
339 .setText(UIText.FetchGerritChangePage_ActivateAdditionalRefsButton);
340 activateAdditionalRefs
341 .setToolTipText(UIText.FetchGerritChangePage_ActivateAdditionalRefsTooltip);
343 refText.addModifyListener(new ModifyListener() {
344 @Override
345 public void modifyText(ModifyEvent e) {
346 Change change = Change.fromRef(refText.getText());
347 if (change != null) {
348 branchText.setText(NLS
349 .bind(UIText.FetchGerritChangePage_SuggestedRefNamePattern,
350 change.getChangeNumber(),
351 change.getPatchSetNumber()));
352 tagText.setText(branchText.getText());
353 } else {
354 branchText.setText(""); //$NON-NLS-1$
355 tagText.setText(""); //$NON-NLS-1$
357 checkPage();
361 runInBackgroud = new Button(main, SWT.CHECK);
362 GridDataFactory.fillDefaults().span(2, 1).align(SWT.BEGINNING, SWT.END)
363 .grab(true, true)
364 .applyTo(runInBackgroud);
365 runInBackgroud.setText(UIText.FetchGerritChangePage_RunInBackground);
367 // get all available URIs from the repository
368 SortedSet<String> uris = new TreeSet<String>();
369 try {
370 for (RemoteConfig rc : RemoteConfig.getAllRemoteConfigs(repository
371 .getConfig())) {
372 if (rc.getURIs().size() > 0)
373 uris.add(rc.getURIs().get(0).toPrivateString());
374 for (URIish u : rc.getPushURIs())
375 uris.add(u.toPrivateString());
378 } catch (URISyntaxException e) {
379 Activator.handleError(e.getMessage(), e, false);
380 setErrorMessage(e.getMessage());
382 for (String aUri : uris)
383 uriCombo.add(aUri);
384 if (defaultUri != null)
385 uriCombo.setText(defaultUri);
386 else
387 selectLastUsedUri();
388 restoreRunInBackgroundSelection();
389 refText.setFocus();
390 Dialog.applyDialogFont(main);
391 setControl(main);
392 checkPage();
395 private void storeLastUsedUri(String uri) {
396 settings.put(lastUriKey, uri.trim());
399 private void selectLastUsedUri() {
400 String lastUri = settings.get(lastUriKey);
401 if (lastUri != null) {
402 int i = uriCombo.indexOf(lastUri);
403 if (i != -1) {
404 uriCombo.select(i);
405 return;
408 uriCombo.select(0);
411 private void storeRunInBackgroundSelection() {
412 settings.put(RUN_IN_BACKGROUND, runInBackgroud.getSelection());
415 private void restoreRunInBackgroundSelection() {
416 runInBackgroud.setSelection(settings.getBoolean(RUN_IN_BACKGROUND));
419 @Override
420 public void setVisible(boolean visible) {
421 super.setVisible(visible);
422 if (visible && refName != null)
423 refText.setText(refName);
426 private void checkPage() {
427 boolean createBranchSelected = createBranch.getSelection();
428 branchText.setEnabled(createBranchSelected);
429 branchText.setVisible(createBranchSelected);
430 branchTextlabel.setVisible(createBranchSelected);
431 branchEditButton.setVisible(createBranchSelected);
432 branchCheckoutButton.setVisible(createBranchSelected);
433 GridData gd = (GridData) branchText.getLayoutData();
434 gd.exclude = !createBranchSelected;
435 gd = (GridData) branchTextlabel.getLayoutData();
436 gd.exclude = !createBranchSelected;
437 gd = (GridData) branchEditButton.getLayoutData();
438 gd.exclude = !createBranchSelected;
439 gd = (GridData) branchCheckoutButton.getLayoutData();
440 gd.exclude = !createBranchSelected;
442 boolean createTagSelected = createTag.getSelection();
443 tagText.setEnabled(createTagSelected);
444 tagText.setVisible(createTagSelected);
445 tagTextlabel.setVisible(createTagSelected);
446 gd = (GridData) tagText.getLayoutData();
447 gd.exclude = !createTagSelected;
448 gd = (GridData) tagTextlabel.getLayoutData();
449 gd.exclude = !createTagSelected;
450 branchText.getParent().layout(true);
452 boolean showActivateAdditionalRefs = false;
453 showActivateAdditionalRefs = (checkout.getSelection() || dontCheckout
454 .getSelection())
455 && !Activator
456 .getDefault()
457 .getPreferenceStore()
458 .getBoolean(
459 UIPreferences.RESOURCEHISTORY_SHOW_ADDITIONAL_REFS);
461 gd = (GridData) warningAdditionalRefNotActive.getLayoutData();
462 gd.exclude = !showActivateAdditionalRefs;
463 warningAdditionalRefNotActive.setVisible(showActivateAdditionalRefs);
464 warningAdditionalRefNotActive.getParent().layout(true);
466 setErrorMessage(null);
467 try {
468 if (refText.getText().length() > 0) {
469 Change change = Change.fromRef(refText.getText());
470 if (change == null) {
471 setErrorMessage(UIText.FetchGerritChangePage_MissingChangeMessage);
472 return;
474 } else {
475 setErrorMessage(UIText.FetchGerritChangePage_MissingChangeMessage);
476 return;
479 if (createBranchSelected)
480 setErrorMessage(branchValidator.isValid(branchText.getText()));
481 else if (createTagSelected)
482 setErrorMessage(tagValidator.isValid(tagText.getText()));
483 } finally {
484 setPageComplete(getErrorMessage() == null);
488 private List<Change> getRefsForContentAssist()
489 throws InvocationTargetException, InterruptedException {
490 if (changeRefs == null) {
491 final String uriText = uriCombo.getText();
492 getWizard().getContainer().run(true, true,
493 new IRunnableWithProgress() {
494 @Override
495 public void run(IProgressMonitor monitor)
496 throws InvocationTargetException,
497 InterruptedException {
498 ListRemoteOperation listOp;
499 try {
500 listOp = new ListRemoteOperation(
501 repository,
502 new URIish(uriText),
503 Activator
504 .getDefault()
505 .getPreferenceStore()
506 .getInt(UIPreferences.REMOTE_CONNECTION_TIMEOUT));
507 } catch (URISyntaxException e) {
508 throw new InvocationTargetException(e);
511 listOp.run(monitor);
512 changeRefs = new ArrayList<Change>();
513 for (Ref ref : listOp.getRemoteRefs()) {
514 Change change = Change.fromRef(ref.getName());
515 if (change != null)
516 changeRefs.add(change);
518 Collections.sort(changeRefs,
519 new Comparator<Change>() {
520 @Override
521 public int compare(Change o1, Change o2) {
522 // change number descending
523 int changeDiff = o2.changeNumber
524 .compareTo(o1.changeNumber);
525 if (changeDiff == 0)
526 // patch set number descending
527 changeDiff = o2
528 .getPatchSetNumber()
529 .compareTo(
530 o1.getPatchSetNumber());
531 return changeDiff;
537 return changeRefs;
540 boolean doFetch() {
542 final RefSpec spec = new RefSpec().setSource(refText.getText())
543 .setDestination(Constants.FETCH_HEAD);
544 final String uri = uriCombo.getText();
545 final boolean doCheckout = checkout.getSelection();
546 final boolean doCreateTag = createTag.getSelection();
547 final boolean doCreateBranch = createBranch.getSelection();
548 final boolean doCheckoutNewBranch = branchCheckoutButton.getSelection();
549 final boolean doActivateAdditionalRefs = (checkout.getSelection() || dontCheckout
550 .getSelection()) && activateAdditionalRefs.getSelection();
551 final String textForTag = tagText.getText();
552 final String textForBranch = branchText.getText();
554 storeRunInBackgroundSelection();
556 if (runInBackgroud.getSelection()) {
557 Job job = new WorkspaceJob(
558 UIText.FetchGerritChangePage_GetChangeTaskName) {
560 @Override
561 public IStatus runInWorkspace(IProgressMonitor monitor) {
562 internalDoFetch(spec, uri, doCheckout, doCreateTag,
563 doCreateBranch, doCheckoutNewBranch,
564 doActivateAdditionalRefs,
565 textForTag, textForBranch, monitor);
566 return org.eclipse.core.runtime.Status.OK_STATUS;
569 @Override
570 public boolean belongsTo(Object family) {
571 if (JobFamilies.FETCH.equals(family))
572 return true;
573 return super.belongsTo(family);
576 job.setUser(true);
577 job.schedule();
578 return true;
579 } else {
580 try {
581 getWizard().getContainer().run(true, true,
582 new IRunnableWithProgress() {
583 @Override
584 public void run(IProgressMonitor monitor)
585 throws InvocationTargetException,
586 InterruptedException {
587 try {
588 internalDoFetch(spec, uri, doCheckout,
589 doCreateTag, doCreateBranch,
590 doCheckoutNewBranch,
591 doActivateAdditionalRefs, textForTag,
592 textForBranch, monitor);
593 } catch (RuntimeException e) {
594 throw e;
595 } catch (Exception e) {
596 throw new InvocationTargetException(e);
597 } finally {
598 monitor.done();
602 } catch (InvocationTargetException e) {
603 Activator.handleError(e.getCause().getMessage(), e.getCause(),
604 true);
605 return false;
606 } catch (InterruptedException e) {
607 // just return
609 return true;
613 private void internalDoFetch(RefSpec spec, String uri, boolean doCheckout,
614 boolean doCreateTag, boolean doCreateBranch,
615 boolean doCheckoutNewBranch,
616 boolean doActivateAdditionalRefs, String textForTag,
617 String textForBranch, IProgressMonitor monitor) {
619 int totalWork = 1;
620 if (doCheckout)
621 totalWork++;
622 if (doCreateTag || doCreateBranch)
623 totalWork++;
624 monitor.beginTask(
625 UIText.FetchGerritChangePage_GetChangeTaskName,
626 totalWork);
628 try {
629 RevCommit commit = fetchChange(uri, spec,
630 monitor);
632 if (doCreateTag)
633 createTag(spec, textForTag, commit, monitor);
635 if (doCreateBranch)
636 createBranch(textForBranch, doCheckoutNewBranch, commit, monitor);
638 if (doCheckout || doCreateTag)
639 checkout(commit, monitor);
641 if (doActivateAdditionalRefs)
642 activateAdditionalRefs();
644 storeLastUsedUri(uri);
646 } catch (Exception e) {
647 Activator.handleError(e.getMessage(), e, true);
648 } finally {
649 monitor.done();
653 private RevCommit fetchChange(String uri, RefSpec spec,
654 IProgressMonitor monitor) throws CoreException, URISyntaxException,
655 IOException {
656 int timeout = Activator.getDefault().getPreferenceStore()
657 .getInt(UIPreferences.REMOTE_CONNECTION_TIMEOUT);
659 List<RefSpec> specs = new ArrayList<RefSpec>(1);
660 specs.add(spec);
662 String taskName = NLS
663 .bind(UIText.FetchGerritChangePage_FetchingTaskName,
664 spec.getSource());
665 monitor.setTaskName(taskName);
666 FetchResult fetchRes = new FetchOperationUI(repository,
667 new URIish(uri), specs, timeout, false).execute(monitor);
669 monitor.worked(1);
670 try (RevWalk rw = new RevWalk(repository)) {
671 return rw.parseCommit(
672 fetchRes.getAdvertisedRef(spec.getSource()).getObjectId());
676 private void createTag(final RefSpec spec, final String textForTag,
677 RevCommit commit, IProgressMonitor monitor) throws CoreException {
678 monitor.setTaskName(UIText.FetchGerritChangePage_CreatingTagTaskName);
679 final TagBuilder tag = new TagBuilder();
680 PersonIdent personIdent = new PersonIdent(repository);
682 tag.setTag(textForTag);
683 tag.setTagger(personIdent);
684 tag.setMessage(NLS.bind(
685 UIText.FetchGerritChangePage_GeneratedTagMessage,
686 spec.getSource()));
687 tag.setObjectId(commit);
688 new TagOperation(repository, tag, false).execute(monitor);
689 monitor.worked(1);
692 private void createBranch(final String textForBranch, boolean doCheckout,
693 RevCommit commit, IProgressMonitor monitor) throws CoreException,
694 GitAPIException {
695 monitor.setTaskName(UIText.FetchGerritChangePage_CreatingBranchTaskName);
696 CreateLocalBranchOperation bop = new CreateLocalBranchOperation(
697 repository, textForBranch, commit);
698 bop.execute(monitor);
700 if (doCheckout) {
701 CheckoutCommand co = new Git(repository).checkout();
702 try {
703 co.setName(textForBranch).call();
704 } catch (CheckoutConflictException e) {
705 final CheckoutResult result = co.getResult();
707 if (result.getStatus() == Status.CONFLICTS) {
708 final Shell shell = getWizard().getContainer().getShell();
710 shell.getDisplay().asyncExec(new Runnable() {
711 @Override
712 public void run() {
713 new CheckoutConflictDialog(shell, repository,
714 result.getConflictList()).open();
720 monitor.worked(1);
723 private void checkout(RevCommit commit, IProgressMonitor monitor)
724 throws CoreException {
725 monitor.setTaskName(UIText.FetchGerritChangePage_CheckingOutTaskName);
726 BranchOperationUI.checkout(repository, commit.name()).run(monitor);
728 monitor.worked(1);
731 private void activateAdditionalRefs() {
732 // do this in the UI thread as it results in a
733 // refresh() on the history page
734 PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
735 @Override
736 public void run() {
737 Activator
738 .getDefault()
739 .getPreferenceStore()
740 .setValue(
741 UIPreferences.RESOURCEHISTORY_SHOW_ADDITIONAL_REFS,
742 true);
747 private void addRefContentProposalToText(final Text textField) {
748 KeyStroke stroke = UIUtils
749 .getKeystrokeOfBestActiveBindingFor(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST);
750 if (stroke != null)
751 UIUtils.addBulbDecorator(textField, NLS.bind(
752 UIText.FetchGerritChangePage_ContentAssistTooltip,
753 stroke.format()));
755 IContentProposalProvider cp = new IContentProposalProvider() {
756 @Override
757 public IContentProposal[] getProposals(String contents, int position) {
758 List<IContentProposal> resultList = new ArrayList<IContentProposal>();
760 // make the simplest possible pattern check: allow "*"
761 // for multiple characters
762 String patternString = contents;
763 // ignore spaces in the beginning
764 while (patternString.length() > 0
765 && patternString.charAt(0) == ' ')
766 patternString = patternString.substring(1);
768 // we quote the string as it may contain spaces
769 // and other stuff colliding with the Pattern
770 patternString = Pattern.quote(patternString);
772 patternString = patternString.replaceAll("\\x2A", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
774 // make sure we add a (logical) * at the end
775 if (!patternString.endsWith(".*")) //$NON-NLS-1$
776 patternString = patternString + ".*"; //$NON-NLS-1$
778 // let's compile a case-insensitive pattern (assumes ASCII only)
779 Pattern pattern;
780 try {
781 pattern = Pattern.compile(patternString,
782 Pattern.CASE_INSENSITIVE);
783 } catch (PatternSyntaxException e) {
784 pattern = null;
787 List<Change> proposals;
788 try {
789 proposals = getRefsForContentAssist();
790 } catch (InvocationTargetException e) {
791 Activator.handleError(e.getMessage(), e, false);
792 return null;
793 } catch (InterruptedException e) {
794 return null;
797 if (proposals != null)
798 for (final Change ref : proposals) {
799 if (pattern != null
800 && !pattern.matcher(
801 ref.getChangeNumber().toString())
802 .matches())
803 continue;
804 IContentProposal propsal = new ChangeContentProposal(
805 ref);
806 resultList.add(propsal);
809 return resultList.toArray(new IContentProposal[resultList
810 .size()]);
814 ContentProposalAdapter adapter = new ContentProposalAdapter(textField,
815 new TextContentAdapter(), cp, stroke, null);
816 // set the acceptance style to always replace the complete content
817 adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
820 private final static class Change {
821 private final String refName;
823 private final Integer changeNumber;
825 private final Integer patchSetNumber;
827 static Change fromRef(String refName) {
828 try {
829 if (!refName.startsWith("refs/changes/")) //$NON-NLS-1$
830 return null;
831 String[] tokens = refName.substring(13).split("/"); //$NON-NLS-1$
832 if (tokens.length != 3)
833 return null;
834 Integer changeNumber = Integer.valueOf(tokens[1]);
835 Integer patchSetNumber = Integer.valueOf(tokens[2]);
836 return new Change(refName, changeNumber, patchSetNumber);
837 } catch (NumberFormatException e) {
838 // if we can't parse this, just return null
839 return null;
840 } catch (IndexOutOfBoundsException e) {
841 // if we can't parse this, just return null
842 return null;
846 private Change(String refName, Integer changeNumber,
847 Integer patchSetNumber) {
848 this.refName = refName;
849 this.changeNumber = changeNumber;
850 this.patchSetNumber = patchSetNumber;
853 public String getRefName() {
854 return refName;
857 public Integer getChangeNumber() {
858 return changeNumber;
861 public Integer getPatchSetNumber() {
862 return patchSetNumber;
865 /* (non-Javadoc)
866 * @see java.lang.Object#toString()
868 @Override
869 public String toString() {
870 return refName;
874 private final static class ChangeContentProposal implements
875 IContentProposal {
876 private final Change myChange;
878 ChangeContentProposal(Change change) {
879 myChange = change;
882 @Override
883 public String getContent() {
884 return myChange.getRefName();
887 @Override
888 public int getCursorPosition() {
889 return 0;
892 @Override
893 public String getDescription() {
894 return NLS.bind(
895 UIText.FetchGerritChangePage_ContentAssistDescription,
896 myChange.getPatchSetNumber(), myChange.getChangeNumber());
899 @Override
900 public String getLabel() {
901 return NLS
902 .bind("{0} - {1}", myChange.getChangeNumber(), myChange.getPatchSetNumber()); //$NON-NLS-1$
905 /* (non-Javadoc)
906 * @see java.lang.Object#toString()
908 @Override
909 public String toString() {
910 return getContent();