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);
});
}
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;
}
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;
}
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;
}
}
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;
}
Aggregations