@NotNull
  @Override
  public MergeData loadRevisions(final VirtualFile file) throws VcsException {
    final MergeData mergeData = new MergeData();
    final VcsRunnable runnable =
        new VcsRunnable() {
          public void run() throws VcsException {
            final HgWorkingCopyRevisionsCommand command =
                new HgWorkingCopyRevisionsCommand(myProject);
            final VirtualFile repo = HgUtil.getHgRootOrThrow(myProject, file);
            final HgFile hgFile = new HgFile(myProject, file);

            HgRevisionNumber serverRevisionNumber;
            HgRevisionNumber localRevisionNumber;
            HgRevisionNumber baseRevisionNumber = null;
            // there are two possibilities: we have checked in local changes in the selected file or
            // we didn't.
            if (wasFileCheckedIn(repo, file)) {
              // 1. We checked in.
              // We have a merge in progress, which means we have 2 heads (parents).
              // the second one is "their" revision pulled from the parent repo,
              // first parent is the local change.
              // to retrieve the base version we get the parent of the local change, i.e. the [only]
              // parent of the first parent.
              // Whick one is local revision depends on which one is merged with,
              // i.e if you update to 17 revision and then merge it woth 23, so 17 is your local and
              // 17->parent is your base revision.
              // This may produce misunderstanding when you update your project with merging (your
              // update firstly to next revisions  and then
              // merge with previous). see
              // http://hgbook.red-bean.com/read/managing-releases-and-branchy-development.html
              final Couple<HgRevisionNumber> parents = command.parents(repo, file);
              serverRevisionNumber = parents.second;
              localRevisionNumber = parents.first;
              final HgContentRevision local =
                  new HgContentRevision(myProject, hgFile, localRevisionNumber);
              mergeData.CURRENT = local.getContentAsBytes();
              // we are sure that we have a common ancestor, because otherwise we'll get "repository
              // is unrelated" error while pulling,
              // due to different root changesets which is prohibited.
              // Find common ancestor of two revisions : hg debugancestor rev1 rev2
              // Using quotes may produce wrong escaping errors on Unix-type systems
              List<String> arguments = new ArrayList<String>();
              String localChangeset = localRevisionNumber.getChangeset();
              String serverChangeset = serverRevisionNumber.getChangeset();
              arguments.add(
                  StringUtil.isEmptyOrSpaces(localChangeset)
                      ? localRevisionNumber.getRevision()
                      : localChangeset);
              arguments.add(
                  StringUtil.isEmptyOrSpaces(serverChangeset)
                      ? serverRevisionNumber.getRevision()
                      : serverChangeset);
              HgCommandResult result =
                  new HgPromptCommandExecutor(myProject)
                      .executeInCurrentThread(repo, "debugancestor", arguments);
              if (result != null) {
                String output = result.getRawOutput();
                final List<String> parts = StringUtil.split(output, ":");
                if (parts.size() < 2) {
                  LOG.info("Couldn't parse result of debugancestor command execution " + arguments);
                  new HgCommandResultNotifier(myProject)
                      .notifyError(
                          null,
                          HgVcsMessages.message("hg4idea.error.debugancestor.command.execution"),
                          HgVcsMessages.message("hg4idea.error.debugancestor.command.description"));
                } else {
                  baseRevisionNumber = HgRevisionNumber.getInstance(parts.get(0), parts.get(1));
                }
              } else {
                LOG.info(
                    HgVcsMessages.message("hg4idea.error.debugancestor.command.execution")
                        + arguments);
                new HgCommandResultNotifier(myProject)
                    .notifyError(
                        null,
                        HgVcsMessages.message("hg4idea.error.debugancestor.command.execution"),
                        HgVcsMessages.message("hg4idea.error.debugancestor.command.description"));
              }
            } else {
              // 2. local changes are not checked in.
              // then there is only one parent, which is server changes.
              // local changes are retrieved from the file system, they are not in the Mercurial
              // yet.
              // base is the only parent of server changes.
              serverRevisionNumber = command.parents(repo, file).first;
              baseRevisionNumber = command.parents(repo, file, serverRevisionNumber).first;
              final File origFile = new File(file.getPath() + ".orig");
              try {
                mergeData.CURRENT = VcsUtil.getFileByteContent(origFile);
              } catch (IOException e) {
                LOG.info("Couldn't retrieve byte content of the file: " + origFile.getPath(), e);
              }
            }

            if (baseRevisionNumber != null) {
              final HgContentRevision base =
                  new HgContentRevision(myProject, hgFile, baseRevisionNumber);
              // if file doesn't exist in ancestor revision the base revision should be empty
              mergeData.ORIGINAL =
                  base.getContent() != null ? base.getContentAsBytes() : new byte[0];
            } else { // no base revision means that the file was added simultaneously with different
                     // content in both repositories
              mergeData.ORIGINAL = new byte[0];
            }
            final HgContentRevision server =
                new HgContentRevision(myProject, hgFile, serverRevisionNumber);
            mergeData.LAST = server.getContentAsBytes();
            file.refresh(false, false);
          }
        };
    VcsUtil.runVcsProcessWithProgress(
        runnable,
        VcsBundle.message("multiple.file.merge.loading.progress.title"),
        false,
        myProject);
    return mergeData;
  }
Ejemplo n.º 2
0
  @NotNull
  public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
    final MergeData data = new MergeData();
    VcsRunnable runnable =
        new VcsRunnable() {
          public void run() throws VcsException {
            File oldFile = null;
            File newFile = null;
            File workingFile = null;
            boolean mergeCase = false;
            SvnVcs vcs = SvnVcs.getInstance(myProject);
            Info info = vcs.getInfo(file);

            if (info != null) {
              oldFile = info.getConflictOldFile();
              newFile = info.getConflictNewFile();
              workingFile = info.getConflictWrkFile();
              mergeCase = workingFile == null || workingFile.getName().contains("working");
              // for debug
              if (workingFile == null) {
                LOG.info(
                    "Null working file when merging text conflict for "
                        + file.getPath()
                        + " old file: "
                        + oldFile
                        + " new file: "
                        + newFile);
              }
              if (mergeCase) {
                // this is merge case
                oldFile = info.getConflictNewFile();
                newFile = info.getConflictOldFile();
                workingFile = info.getConflictWrkFile();
              }
              data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
            } else {
              throw new VcsException("Could not get info for " + file.getPath());
            }
            if (oldFile == null || newFile == null || workingFile == null) {
              ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
              data.ORIGINAL = bos.toByteArray();
              data.LAST = bos.toByteArray();
              data.CURRENT = readFile(new File(file.getPath()));
            } else {
              data.ORIGINAL = readFile(oldFile);
              data.LAST = readFile(newFile);
              data.CURRENT = readFile(workingFile);
            }
            if (mergeCase) {
              final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
              if (!Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
                // swap base and server: another order of merge arguments
                byte[] original = data.ORIGINAL;
                data.ORIGINAL = data.LAST;
                data.LAST = original;
              }
            }
          }
        };
    VcsUtil.runVcsProcessWithProgress(
        runnable,
        VcsBundle.message("multiple.file.merge.loading.progress.title"),
        false,
        myProject);

    return data;
  }