Search in sources :

Example 1 with MergeData

use of com.intellij.openapi.vcs.merge.MergeData in project intellij-community by JetBrains.

the class HgMergeProviderTest method verifyMergeData.

private void verifyMergeData(final VirtualFile file, String expectedBase, String expectedLocal, String expectedServer) throws VcsException {
    EdtTestUtil.runInEdtAndWait(() -> {
        MergeData mergeData = myMergeProvider.loadRevisions(file);
        assertEquals(expectedBase, mergeData.ORIGINAL);
        assertEquals(expectedServer, mergeData.LAST);
        assertEquals(expectedLocal, mergeData.CURRENT);
    });
}
Also used : MergeData(com.intellij.openapi.vcs.merge.MergeData)

Example 2 with MergeData

use of com.intellij.openapi.vcs.merge.MergeData in project intellij-community by JetBrains.

the class SvnMergeProvider method loadRevisions.

@NotNull
public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
    final MergeData data = new MergeData();
    VcsRunnable runnable = () -> {
        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(virtualToIoFile(file));
        } 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;
}
Also used : SvnRevisionNumber(org.jetbrains.idea.svn.SvnRevisionNumber) VcsRunnable(com.intellij.vcsUtil.VcsRunnable) MergeData(com.intellij.openapi.vcs.merge.MergeData) VcsException(com.intellij.openapi.vcs.VcsException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Info(org.jetbrains.idea.svn.info.Info) VirtualFile(com.intellij.openapi.vfs.VirtualFile) VfsUtilCore.virtualToIoFile(com.intellij.openapi.vfs.VfsUtilCore.virtualToIoFile) File(java.io.File) SvnVcs(org.jetbrains.idea.svn.SvnVcs) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with MergeData

use of com.intellij.openapi.vcs.merge.MergeData in project intellij-community by JetBrains.

the class HgMergeProvider method loadRevisions.

@NotNull
@Override
public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
    final MergeData mergeData = new MergeData();
    final VcsRunnable runnable = new VcsRunnable() {

        @Override
        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.
                //Which one is local revision depends on which one is merged with,
                // i.e if you update to 17 revision and then merge it with 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 = HgContentRevision.create(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 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");
                mergeData.CURRENT = VcsUtil.getFileByteContent(origFile);
            }
            if (baseRevisionNumber != null) {
                final HgContentRevision base = HgContentRevision.create(myProject, hgFile, baseRevisionNumber);
                //if file doesn't exist in ancestor revision the base revision should be empty
                mergeData.ORIGINAL = base.getContent() != null ? base.getContentAsBytes() : ArrayUtil.EMPTY_BYTE_ARRAY;
            } else {
                // no base revision means that the file was added simultaneously with different content in both repositories
                mergeData.ORIGINAL = ArrayUtil.EMPTY_BYTE_ARRAY;
            }
            final HgContentRevision server = HgContentRevision.create(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;
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) VcsRunnable(com.intellij.vcsUtil.VcsRunnable) HgContentRevision(org.zmlx.hg4idea.HgContentRevision) HgPromptCommandExecutor(org.zmlx.hg4idea.execution.HgPromptCommandExecutor) MergeData(com.intellij.openapi.vcs.merge.MergeData) ArrayList(java.util.ArrayList) HgCommandResultNotifier(org.zmlx.hg4idea.action.HgCommandResultNotifier) HgWorkingCopyRevisionsCommand(org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand) HgCommandResult(org.zmlx.hg4idea.execution.HgCommandResult) HgFile(org.zmlx.hg4idea.HgFile) HgRevisionNumber(org.zmlx.hg4idea.HgRevisionNumber) VirtualFile(com.intellij.openapi.vfs.VirtualFile) HgFile(org.zmlx.hg4idea.HgFile) File(java.io.File) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with MergeData

use of com.intellij.openapi.vcs.merge.MergeData in project intellij-community by JetBrains.

the class ChangeDiffRequestProducer method createRequest.

@NotNull
private DiffRequest createRequest(@Nullable Project project, @NotNull Change change, @NotNull UserDataHolder context, @NotNull ProgressIndicator indicator) throws DiffRequestProducerException {
    if (ChangesUtil.isTextConflictingChange(change)) {
        // three side diff
        // FIXME: This part is ugly as a VCS merge subsystem itself.
        FilePath path = ChangesUtil.getFilePath(change);
        VirtualFile file = path.getVirtualFile();
        if (file == null) {
            file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.getPath());
        }
        if (file == null)
            throw new DiffRequestProducerException("Can't show merge conflict - file not found");
        if (project == null) {
            throw new DiffRequestProducerException("Can't show merge conflict - project is unknown");
        }
        final AbstractVcs vcs = ChangesUtil.getVcsForChange(change, project);
        if (vcs == null || vcs.getMergeProvider() == null) {
            throw new DiffRequestProducerException("Can't show merge conflict - operation nos supported");
        }
        try {
            // FIXME: loadRevisions() can call runProcessWithProgressSynchronously() inside
            final Ref<Throwable> exceptionRef = new Ref<>();
            final Ref<MergeData> mergeDataRef = new Ref<>();
            final VirtualFile finalFile = file;
            ApplicationManager.getApplication().invokeAndWait(() -> {
                try {
                    mergeDataRef.set(vcs.getMergeProvider().loadRevisions(finalFile));
                } catch (VcsException e) {
                    exceptionRef.set(e);
                }
            });
            if (!exceptionRef.isNull()) {
                Throwable e = exceptionRef.get();
                if (e instanceof VcsException)
                    throw (VcsException) e;
                if (e instanceof Error)
                    throw (Error) e;
                if (e instanceof RuntimeException)
                    throw (RuntimeException) e;
                throw new RuntimeException(e);
            }
            MergeData mergeData = mergeDataRef.get();
            ContentRevision bRev = change.getBeforeRevision();
            ContentRevision aRev = change.getAfterRevision();
            String beforeRevisionTitle = getRevisionTitle(bRev, "Your version");
            String afterRevisionTitle = getRevisionTitle(aRev, "Server version");
            String title = DiffRequestFactory.getInstance().getTitle(file);
            List<String> titles = ContainerUtil.list(beforeRevisionTitle, "Base Version", afterRevisionTitle);
            DiffContentFactory contentFactory = DiffContentFactory.getInstance();
            List<DiffContent> contents = ContainerUtil.list(contentFactory.createFromBytes(project, mergeData.CURRENT, file), contentFactory.createFromBytes(project, mergeData.ORIGINAL, file), contentFactory.createFromBytes(project, mergeData.LAST, file));
            SimpleDiffRequest request = new SimpleDiffRequest(title, contents, titles);
            MergeUtil.putRevisionInfos(request, mergeData);
            return request;
        } catch (VcsException | IOException e) {
            LOG.info(e);
            throw new DiffRequestProducerException(e);
        }
    } else {
        ContentRevision bRev = change.getBeforeRevision();
        ContentRevision aRev = change.getAfterRevision();
        if (bRev == null && aRev == null) {
            LOG.warn("Both revision contents are empty");
            throw new DiffRequestProducerException("Bad revisions contents");
        }
        if (bRev != null)
            checkContentRevision(project, bRev, context, indicator);
        if (aRev != null)
            checkContentRevision(project, aRev, context, indicator);
        String title = getRequestTitle(change);
        indicator.setIndeterminate(true);
        DiffContent content1 = createContent(project, bRev, context, indicator);
        DiffContent content2 = createContent(project, aRev, context, indicator);
        final String userLeftRevisionTitle = (String) myChangeContext.get(DiffUserDataKeysEx.VCS_DIFF_LEFT_CONTENT_TITLE);
        String beforeRevisionTitle = userLeftRevisionTitle != null ? userLeftRevisionTitle : getRevisionTitle(bRev, "Base version");
        final String userRightRevisionTitle = (String) myChangeContext.get(DiffUserDataKeysEx.VCS_DIFF_RIGHT_CONTENT_TITLE);
        String afterRevisionTitle = userRightRevisionTitle != null ? userRightRevisionTitle : getRevisionTitle(aRev, "Your version");
        SimpleDiffRequest request = new SimpleDiffRequest(title, content1, content2, beforeRevisionTitle, afterRevisionTitle);
        boolean bRevCurrent = bRev instanceof CurrentContentRevision;
        boolean aRevCurrent = aRev instanceof CurrentContentRevision;
        if (bRevCurrent && !aRevCurrent)
            request.putUserData(DiffUserDataKeys.MASTER_SIDE, Side.LEFT);
        if (!bRevCurrent && aRevCurrent)
            request.putUserData(DiffUserDataKeys.MASTER_SIDE, Side.RIGHT);
        return request;
    }
}
Also used : FilePath(com.intellij.openapi.vcs.FilePath) VirtualFile(com.intellij.openapi.vfs.VirtualFile) SimpleDiffRequest(com.intellij.diff.requests.SimpleDiffRequest) DiffRequestProducerException(com.intellij.diff.chains.DiffRequestProducerException) DiffContentFactory(com.intellij.diff.DiffContentFactory) MergeData(com.intellij.openapi.vcs.merge.MergeData) IOException(java.io.IOException) AbstractVcs(com.intellij.openapi.vcs.AbstractVcs) Ref(com.intellij.openapi.util.Ref) VcsException(com.intellij.openapi.vcs.VcsException) DiffContent(com.intellij.diff.contents.DiffContent) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with MergeData

use of com.intellij.openapi.vcs.merge.MergeData in project intellij-community by JetBrains.

the class GitMergeProvider method loadRevisions.

@Override
@NotNull
public MergeData loadRevisions(@NotNull final VirtualFile file) throws VcsException {
    final MergeData mergeData = new MergeData();
    final VirtualFile root = GitUtil.getGitRoot(file);
    final FilePath path = VcsUtil.getFilePath(file.getPath());
    VcsRunnable runnable = new VcsRunnable() {

        @Override
        @SuppressWarnings({ "ConstantConditions" })
        public void run() throws VcsException {
            GitFileRevision original = new GitFileRevision(myProject, path, new GitRevisionNumber(":" + ORIGINAL_REVISION_NUM));
            GitFileRevision current = new GitFileRevision(myProject, path, new GitRevisionNumber(":" + yoursRevision(root)));
            GitFileRevision last = new GitFileRevision(myProject, path, new GitRevisionNumber(":" + theirsRevision(root)));
            try {
                try {
                    mergeData.ORIGINAL = original.getContent();
                } catch (Exception ex) {
                    /// This could happen in case if rebasing.
                    try {
                        mergeData.ORIGINAL = file.contentsToByteArray();
                    } catch (IOException e) {
                        LOG.error(e);
                        mergeData.ORIGINAL = ArrayUtil.EMPTY_BYTE_ARRAY;
                    }
                }
                mergeData.CURRENT = loadRevisionCatchingErrors(current);
                mergeData.LAST = loadRevisionCatchingErrors(last);
                // TODO: can be done once for a root
                mergeData.CURRENT_REVISION_NUMBER = findCurrentRevisionNumber(root);
                mergeData.LAST_REVISION_NUMBER = findLastRevisionNumber(root);
                mergeData.ORIGINAL_REVISION_NUMBER = findOriginalRevisionNumber(root, mergeData.CURRENT_REVISION_NUMBER, mergeData.LAST_REVISION_NUMBER);
                Trinity<String, String, String> blobs = getAffectedBlobs(root, file);
                mergeData.CURRENT_FILE_PATH = getBlobPathInRevision(root, file, blobs.getFirst(), mergeData.CURRENT_REVISION_NUMBER);
                mergeData.ORIGINAL_FILE_PATH = getBlobPathInRevision(root, file, blobs.getSecond(), mergeData.ORIGINAL_REVISION_NUMBER);
                mergeData.LAST_FILE_PATH = getBlobPathInRevision(root, file, blobs.getThird(), mergeData.LAST_REVISION_NUMBER);
            } catch (IOException e) {
                throw new IllegalStateException("Failed to load file content", e);
            }
        }
    };
    VcsUtil.runVcsProcessWithProgress(runnable, GitBundle.message("merge.load.files"), false, myProject);
    return mergeData;
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) FilePath(com.intellij.openapi.vcs.FilePath) VcsRunnable(com.intellij.vcsUtil.VcsRunnable) GitRevisionNumber(git4idea.GitRevisionNumber) GitFileRevision(git4idea.GitFileRevision) MergeData(com.intellij.openapi.vcs.merge.MergeData) IOException(java.io.IOException) VcsException(com.intellij.openapi.vcs.VcsException) IOException(java.io.IOException) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

MergeData (com.intellij.openapi.vcs.merge.MergeData)6 VirtualFile (com.intellij.openapi.vfs.VirtualFile)5 NotNull (org.jetbrains.annotations.NotNull)5 VcsException (com.intellij.openapi.vcs.VcsException)4 VcsRunnable (com.intellij.vcsUtil.VcsRunnable)3 File (java.io.File)3 IOException (java.io.IOException)3 FilePath (com.intellij.openapi.vcs.FilePath)2 DiffContentFactory (com.intellij.diff.DiffContentFactory)1 DiffRequestProducerException (com.intellij.diff.chains.DiffRequestProducerException)1 DiffContent (com.intellij.diff.contents.DiffContent)1 SimpleDiffRequest (com.intellij.diff.requests.SimpleDiffRequest)1 Ref (com.intellij.openapi.util.Ref)1 AbstractVcs (com.intellij.openapi.vcs.AbstractVcs)1 VfsUtilCore.virtualToIoFile (com.intellij.openapi.vfs.VfsUtilCore.virtualToIoFile)1 GitFileRevision (git4idea.GitFileRevision)1 GitRevisionNumber (git4idea.GitRevisionNumber)1 BufferedInputStream (java.io.BufferedInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileInputStream (java.io.FileInputStream)1