/**
   * This is called when "Rebase and Push" button (default button) is pressed. 1. Closes the dialog.
   * 2. Fetches project and rebases. 3. Repeats step 2 if needed - while current repository is
   * behind the parent one. 4. Then pushes. It may fail on one of these steps (especially on
   * rebasing with conflict) - then a notification error will be shown and the process will be
   * interrupted.
   */
  private void rebaseAndPush() {
    final Task.Backgroundable rebaseAndPushTask =
        new Task.Backgroundable(myProject, GitBundle.getString("push.active.fetching")) {
          public void run(@NotNull ProgressIndicator indicator) {
            List<VcsException> exceptions = new ArrayList<VcsException>();
            List<VcsException> pushExceptions = new ArrayList<VcsException>();
            for (int i = 0; i < 3; i++) {
              RebaseInfo rebaseInfo = collectRebaseInfo();

              if (rebaseInfo.reorderedCommits
                  .isEmpty()) { // if we have to reorder commits, rebase must pre
                final Collection<Root> rootsToPush =
                    getRootsToPush(); // collect roots from the dialog
                exceptions = executePushCommand(rootsToPush);
                if (exceptions.isEmpty()
                    && !rootsToPush.isEmpty()) { // if nothing to push, execute rebase anyway
                  int commitsNum = 0;
                  for (Root root : rootsToPush) {
                    commitsNum += root.commits.size();
                    Set<String> unchecked = rebaseInfo.uncheckedCommits.get(root.root);
                    if (unchecked != null) {
                      commitsNum -= unchecked.size();
                    }
                  }
                  final String pushMessage =
                      "Pushed " + commitsNum + " " + StringUtil.pluralize("commit", commitsNum);
                  VcsBalloonProblemNotifier.showOverVersionControlView(
                      myVcs.getProject(), pushMessage, MessageType.INFO);

                  for (Root root : rootsToPush) {
                    GitRepositoryManager.getInstance(myProject)
                        .updateRepository(root.root, GitRepository.TrackedTopic.ALL);
                  }
                  return;
                }
                pushExceptions = new ArrayList<VcsException>(exceptions);
                exceptions.clear();
              }

              final List<Root> roots = loadRoots(myProject, myVcsRoots, exceptions, true); // fetch
              if (!exceptions.isEmpty()) {
                notifyMessage(
                    myProject, "Failed to fetch", null, NotificationType.ERROR, true, exceptions);
                return;
              }
              updateTree(roots, rebaseInfo.uncheckedCommits);

              if (isRebaseNeeded()) {
                rebaseInfo = collectRebaseInfo();
                executeRebase(exceptions, rebaseInfo);
                if (!exceptions.isEmpty()) {
                  notifyMessage(
                      myProject,
                      "Failed to rebase",
                      null,
                      NotificationType.ERROR,
                      true,
                      exceptions);
                  return;
                }
                VcsFileUtil.refreshFiles(myProject, rebaseInfo.roots);
              }
            }
            notifyMessage(
                myProject,
                "Failed to push",
                "Update project and push again",
                NotificationType.ERROR,
                true,
                pushExceptions);
          }
        };
    GitVcs.runInBackground(rebaseAndPushTask);
  }
예제 #2
0
  /**
   * The most general execution method.
   *
   * @param sync Set to <code>true</code> to make the calling thread wait for the task execution.
   * @param modal If <code>true</code>, the task will be modal with a modal progress dialog. If
   *     false, the task will be executed in background. <code>modal</code> implies <code>sync
   *     </code>, i.e. if modal then sync doesn't matter: you'll wait anyway.
   * @param resultHandler Handle the result.
   * @see #execute(boolean)
   */
  public void execute(boolean sync, boolean modal, final GitTaskResultHandler resultHandler) {
    final Object LOCK = new Object();
    final AtomicBoolean completed = new AtomicBoolean();

    if (modal) {
      final ModalTask task =
          new ModalTask(myProject, myHandler, myTitle) {
            @Override
            public void onSuccess() {
              commonOnSuccess(LOCK, resultHandler);
              completed.set(true);
            }

            @Override
            public void onCancel() {
              commonOnCancel(LOCK, resultHandler);
              completed.set(true);
            }
          };
      GuiUtils.invokeAndWaitIfNeeded(
          new Runnable() {
            @Override
            public void run() {
              ProgressManager.getInstance().run(task);
            }
          },
          ModalityState.defaultModalityState());
    } else {
      final BackgroundableTask task =
          new BackgroundableTask(myProject, myHandler, myTitle) {
            @Override
            public void onSuccess() {
              commonOnSuccess(LOCK, resultHandler);
              completed.set(true);
            }

            @Override
            public void onCancel() {
              commonOnCancel(LOCK, resultHandler);
              completed.set(true);
            }
          };
      if (myProgressIndicator == null) {
        GitVcs.runInBackground(task);
      } else {
        task.runAlone();
      }
    }

    if (sync) {
      while (!completed.get()) {
        try {
          synchronized (LOCK) {
            LOCK.wait(50);
          }
        } catch (InterruptedException e) {
          LOG.info(e);
        }
      }
    }
  }