private DiffContainer buildDiffContainer()

in org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/merge/GitMergeEditorInput.java [335:586]


	private DiffContainer buildDiffContainer(Repository repository,
			RevCommit headCommit, RevCommit ancestorCommit, RevWalk rw,
			IProgressMonitor monitor)
			throws IOException, InterruptedException {

		monitor.setTaskName(UIText.GitMergeEditorInput_CalculatingDiffTaskName);
		DiffContainer result = new DiffNode(Differencer.CONFLICTING);

		ConflictStyle style = null;
		try (TreeWalk tw = new TreeWalk(repository)) {
			int dirCacheIndex = tw.addTree(new DirCacheIterator(repository
					.readDirCache()));
			FileTreeIterator fIter = new FileTreeIterator(repository);
			int fileTreeIndex = tw.addTree(fIter);
			fIter.setDirCacheIterator(tw, dirCacheIndex);
			int repositoryTreeIndex = tw.addTree(rw.parseTree(repository
					.resolve(Constants.HEAD)));

			// filter by selected resources
			Collection<String> filterPaths = getFilterPaths();
			if (!filterPaths.isEmpty()) {
				if (filterPaths.size() > 1) {
					tw.setFilter(
							PathFilterGroup.createFromStrings(filterPaths));
				} else {
					String path = filterPaths.iterator().next();
					if (!path.isEmpty()) {
						tw.setFilter(PathFilterGroup.createFromStrings(path));
					}
				}
			}
			tw.setRecursive(true);

			while (tw.next()) {
				if (monitor.isCanceled())
					throw new InterruptedException();
				String gitPath = tw.getPathString();
				monitor.setTaskName(gitPath);

				FileTreeIterator fit = tw.getTree(fileTreeIndex,
						FileTreeIterator.class);
				if (fit == null)
					continue;

				DirCacheIterator dit = tw.getTree(dirCacheIndex,
						DirCacheIterator.class);

				final DirCacheEntry dirCacheEntry = dit == null ? null : dit
						.getDirCacheEntry();

				boolean conflicting = dirCacheEntry != null
						&& dirCacheEntry.getStage() > 0;

				AbstractTreeIterator rt = tw.getTree(repositoryTreeIndex,
						AbstractTreeIterator.class);

				// compare local file against HEAD to see if it was modified
				boolean modified = rt != null
						&& !fit.getEntryObjectId()
								.equals(rt.getEntryObjectId());

				// if this is neither conflicting nor changed, we skip it
				if (!conflicting && !modified)
					continue;

				ITypedElement right;
				String encoding = null;
				if (conflicting) {
					GitFileRevision revision = GitFileRevision.inIndex(
							repository, gitPath, DirCacheEntry.STAGE_3);
					encoding = CompareCoreUtils.getResourceEncoding(repository,
							gitPath);
					right = new FileRevisionTypedElement(revision, encoding);
				} else {
					right = CompareUtils.getFileRevisionTypedElement(gitPath,
							headCommit, repository);
				}
				// can this really happen?
				if (right instanceof EmptyTypedElement) {
					continue;
				}
				ITypedElement left;
				IFileRevision rev;
				// if the file is not conflicting (as it was auto-merged)
				// we will show the auto-merged (local) version

				Path repositoryPath = new Path(repository.getWorkTree()
						.getAbsolutePath());
				IPath location = repositoryPath.append(gitPath);
				assert location != null;
				IFile file = ResourceUtil.getFileForLocation(location, false);
				boolean useWorkingTree = !conflicting || useWorkspace;
				boolean stage2FromWorkingTree = false;
				if (!useWorkingTree && conflicting && dirCacheEntry != null) {
					// Normal conflict stages have a zero timestamp. If it's not
					// zero, we marked it below when the content was saved to
					// the working tree file in an earlier merge editor.
					useWorkingTree = !Instant.EPOCH
							.equals(dirCacheEntry.getLastModifiedInstant());
					stage2FromWorkingTree = useWorkingTree;
				}
				if (useWorkingTree) {
					boolean useOursFilter = conflicting && useOurs;
					int conflictMarkerSize = 7; // Git default
					if (useOursFilter) {
						Attributes attributes = tw.getAttributes();
						useOursFilter = attributes.canBeContentMerged();
						if (useOursFilter) {
							Attribute markerSize = attributes
									.get("conflict-marker-size"); //$NON-NLS-1$
							if (markerSize != null && Attribute.State.CUSTOM
									.equals(markerSize.getState())) {
								try {
									conflictMarkerSize = Integer
											.parseUnsignedInt(
													markerSize.getValue());
								} catch (NumberFormatException e) {
									// Ignore
								}
							}
						}
					}
					LocalResourceTypedElement item;
					if (useOursFilter) {
						if (style == null) {
							style = repository.getConfig().getEnum(
									ConfigConstants.CONFIG_MERGE_SECTION, null,
									ConfigConstants.CONFIG_KEY_CONFLICTSTYLE,
									ConflictStyle.MERGE);
						}
						boolean useDiff3Style = ConflictStyle.DIFF3
								.equals(style);
						String filter = (useDiff3Style ? 'O' : 'o')
								+ Integer.toString(conflictMarkerSize);
						URI uri = EgitFileSystem.createURI(repository, gitPath,
								"WORKTREE:" + filter); //$NON-NLS-1$
						Charset rscEncoding = null;
						if (file != null) {
							if (encoding == null) {
								encoding = CompareCoreUtils
										.getResourceEncoding(file);
							}
							try {
								rscEncoding = Charset.forName(encoding);
							} catch (IllegalArgumentException e) {
								// Ignore here; use default.
							}
						}
						item = createWithHiddenResource(uri, repository,
								gitPath, tw.getNameString(), file, rscEncoding);
						if (file != null) {
							item.setSharedDocumentListener(
									new LocalResourceSaver(item) {

										@Override
										protected void save()
												throws CoreException {
											super.save();
											file.refreshLocal(
													IResource.DEPTH_ZERO, null);
										}
									});
						} else {
							item.setSharedDocumentListener(
									new LocalResourceSaver(item));
						}
					} else {
						if (file != null) {
							item = new LocalResourceTypedElement(file);
						} else {
							item = new LocalNonWorkspaceTypedElement(repository,
									location);
						}
						item.setSharedDocumentListener(
								new LocalResourceSaver(item));
					}
					left = item;
				} else {
					IFile rsc = file != null ? file
							: createHiddenResource(location.toFile().toURI(),
									tw.getNameString(), null);
					assert rsc != null;
					// Stage 2 from index with backing IResource
					rev = GitFileRevision.inIndex(repository, gitPath,
							DirCacheEntry.STAGE_2);
					IRunnableContext runnableContext = getContainer();
					if (runnableContext == null) {
						runnableContext = PlatformUI.getWorkbench()
								.getProgressService();
						assert runnableContext != null;
					}
					left = new ResourceEditableRevision(rev, rsc,
							runnableContext);
					// 'left' saves to the working tree. Update the index entry
					// with the current time. Normal conflict stages have a
					// timestamp of zero, so this is a non-invasive fully
					// compatible way to mark this conflict stage so that the
					// next time we do take the file contents.
					((EditableRevision) left).addContentChangeListener(
							source -> updateIndexTimestamp(repository,
									gitPath));
					// make sure we don't need a round trip later
					try {
						((EditableRevision) left).cacheContents(monitor);
					} catch (CoreException e) {
						throw new IOException(e.getMessage(), e);
					}
				}

				int kind = Differencer.NO_CHANGE;
				if (conflicting) {
					kind = Differencer.CONFLICTING + Differencer.CHANGE;
				} else if (modified) {
					kind = Differencer.LEFT + Differencer.ADDITION;
				}
				IDiffContainer fileParent = getFileParent(result,
						repositoryPath, file, location);

				ITypedElement ancestor = null;
				if (ancestorCommit != null) {
					ancestor = CompareUtils.getFileRevisionTypedElement(gitPath,
							ancestorCommit, repository);
					// we get an ugly black icon if we have an EmptyTypedElement
					// instead of null
					if (ancestor instanceof EmptyTypedElement) {
						ancestor = null;
					}
				} else if (conflicting) {
					GitFileRevision revision = GitFileRevision.inIndex(
							repository, gitPath, DirCacheEntry.STAGE_1);
					if (encoding == null) {
						encoding = CompareCoreUtils
								.getResourceEncoding(repository, gitPath);
					}
					ancestor = new FileRevisionTypedElement(revision, encoding);
				}
				// create the node as child
				DiffNode node = new MergeDiffNode(fileParent, kind, ancestor,
						left, right);
				if (stage2FromWorkingTree) {
					customLabels.put(node, tw.getNameString());
				} else if (left instanceof EditableRevision) {
					String name = tw.getNameString();
					((EditableRevision) left).addContentChangeListener(
							source -> setLeftLabel(node, name, true));
				}
			}
			return result;
		} catch (URISyntaxException e) {
			throw new IOException(e.getMessage(), e);
		}
	}