private boolean processOne(Candidate n) throws IOException { RevCommit parent = n.getParent(0); if (parent == null) return split(n.getNextCandidate(0), n); revPool.parseHeaders(parent); if (find(parent, n.sourcePath)) { if (idBuf.equals(n.sourceBlob)) return blameEntireRegionOnParent(n, parent); return splitBlameWithParent(n, parent); } if (n.sourceCommit == null) return result(n); DiffEntry r = findRename(parent, n.sourceCommit, n.sourcePath); if (r == null) return result(n); if (0 == r.getOldId().prefixCompare(n.sourceBlob)) { // A 100% rename without any content change can also // skip directly to the parent. n.sourceCommit = parent; n.sourcePath = PathFilter.create(r.getOldPath()); push(n); return false; } Candidate next = n.create(parent, PathFilter.create(r.getOldPath())); next.sourceBlob = r.getOldId().toObjectId(); next.renameScore = r.getScore(); next.loadText(reader); return split(next, n); }
protected boolean hasIgnoreFile(Repository repository, RevCommit revCommit, String relativePath) throws Exception { if (_ignoreFileName == null) { return false; } try (TreeWalk treeWalk = new TreeWalk(repository)) { treeWalk.addTree(revCommit.getTree()); if (revCommit.getParentCount() > 0) { RevCommit parentRevCommit = revCommit.getParent(0); treeWalk.addTree(parentRevCommit.getTree()); } treeWalk.setRecursive(true); treeWalk.setFilter( AndTreeFilter.create( PathFilter.create(relativePath + "/" + _ignoreFileName), TreeFilter.ANY_DIFF)); return treeWalk.next(); } }
/** * Create a blame generator for the repository and path (relative to repository) * * @param repository repository to access revision data from. * @param path initial path of the file to start scanning (relative to the repository). */ public BlameGenerator(Repository repository, String path) { this.repository = repository; this.resultPath = PathFilter.create(path); idBuf = new MutableObjectId(); setFollowFileRenames(true); initRevPool(false); remaining = -1; }
@SuppressWarnings("nls") @Override public String toString() { return "(FOLLOW(" + path.toString() + ")" // + " AND " // + ANY_DIFF.toString() + ")"; }
private DiffEntry findRename(RevCommit parent, RevCommit commit, PathFilter path) throws IOException { if (renameDetector == null) return null; treeWalk.setFilter(TreeFilter.ANY_DIFF); treeWalk.reset(parent.getTree(), commit.getTree()); renameDetector.reset(); renameDetector.addAll(DiffEntry.scan(treeWalk)); for (DiffEntry ent : renameDetector.compute()) { if (isRename(ent) && ent.getNewPath().equals(path.getPath())) return ent; } return null; }
private boolean isModified(String path) throws CorruptObjectException, IOException { NameConflictTreeWalk tw = new NameConflictTreeWalk(repo); tw.addTree(new DirCacheIterator(dc)); tw.addTree(new FileTreeIterator(repo)); tw.setRecursive(true); tw.setFilter(PathFilter.create(path)); DirCacheIterator dcIt; WorkingTreeIterator wtIt; while (tw.next()) { dcIt = tw.getTree(0, DirCacheIterator.class); wtIt = tw.getTree(1, WorkingTreeIterator.class); if (dcIt == null || wtIt == null) return true; if (wtIt.isModified(dcIt.getDirCacheEntry(), true)) { return true; } } return false; }
/** * Returns the list of files in the specified folder at the specified commit. If the repository * does not exist or is empty, an empty list is returned. * * @param repository * @param path if unspecified, root folder is assumed. * @param commit if null, HEAD is assumed. * @return list of files in specified path */ public static List<PathModel> getFilesInPath( Repository repository, String path, RevCommit commit) { List<PathModel> list = new ArrayList<PathModel>(); if (!hasCommits(repository)) { return list; } if (commit == null) { commit = getCommit(repository, null); } final TreeWalk tw = new TreeWalk(repository); try { tw.addTree(commit.getTree()); if (!(path == null)) { PathFilter f = PathFilter.create(path); tw.setFilter(f); tw.setRecursive(false); boolean foundFolder = false; while (tw.next()) { if (!foundFolder && tw.isSubtree()) { tw.enterSubtree(); } if (tw.getPathString().equals(path)) { foundFolder = true; continue; } if (foundFolder) { list.add(getPathModel(tw, path, commit)); } } } else { tw.setRecursive(false); while (tw.next()) { list.add(getPathModel(tw, null, commit)); } } } catch (IOException e) { // error(e, repository, "{0} failed to get files for commit {1}", commit.getName()); Logger.error(e, e.getMessage()); } finally { tw.release(); } Collections.sort(list); return list; }
/** * Determine the differences between two trees. * * <p>No output is created, instead only the file paths that are different are returned. Callers * may choose to format these paths themselves, or convert them into {@link FileHeader} instances * with a complete edit list by calling {@link #toFileHeader(DiffEntry)}. * * @param a the old (or previous) side. * @param b the new (or updated) side. * @return the paths that are different. * @throws IOException trees cannot be read or file contents cannot be read. */ public List<DiffEntry> scan(AbstractTreeIterator a, AbstractTreeIterator b) throws IOException { assertHaveRepository(); TreeWalk walk = new TreeWalk(reader); walk.addTree(a); walk.addTree(b); walk.setRecursive(true); TreeFilter filter = getDiffTreeFilterFor(a, b); if (pathFilter instanceof FollowFilter) { walk.setFilter( AndTreeFilter.create(PathFilter.create(((FollowFilter) pathFilter).getPath()), filter)); } else { walk.setFilter(AndTreeFilter.create(pathFilter, filter)); } source = new ContentSource.Pair(source(a), source(b)); List<DiffEntry> files = DiffEntry.scan(walk); if (pathFilter instanceof FollowFilter && isAdd(files)) { // The file we are following was added here, find where it // came from so we can properly show the rename or copy, // then continue digging backwards. // a.reset(); b.reset(); walk.reset(); walk.addTree(a); walk.addTree(b); walk.setFilter(filter); if (renameDetector == null) setDetectRenames(true); files = updateFollowFilter(detectRenames(DiffEntry.scan(walk))); } else if (renameDetector != null) files = detectRenames(files); return files; }
/** @return the path this filter matches. */ public String getPath() { return path.getPath(); }
/** * Is the configured already a submodule in the index? * * @return true if submodule exists in index, false otherwise * @throws IOException */ protected boolean submoduleExists() throws IOException { TreeFilter filter = PathFilter.create(path); return SubmoduleWalk.forIndex(repo).setFilter(filter).next(); }
@Override public void execute() throws BuildException { if (_property == null) { throw new BuildException("Property attribute is required", getLocation()); } if (_path == null) { throw new BuildException("Path attribute is required", getLocation()); } File gitDir = PathUtil.getGitDir(_gitDir, getProject(), getLocation()); String relativePath = PathUtil.toRelativePath(gitDir, _path); if (_useCache) { String hash = _hashes.get(relativePath); if (hash != null) { Project currentProject = getProject(); currentProject.setNewProperty(_property, hash); return; } } try (Repository repository = RepositoryCache.open(FileKey.exact(gitDir, FS.DETECTED))) { RevWalk revWalk = new RevWalk(repository); revWalk.setRetainBody(false); revWalk.markStart(revWalk.parseCommit(repository.resolve(Constants.HEAD))); if (_ignoreFileName == null) { revWalk.setRevFilter(MaxCountRevFilter.create(1)); } else { revWalk.setRevFilter(MaxCountRevFilter.create(2)); } revWalk.setTreeFilter( AndTreeFilter.create(PathFilter.create(relativePath), TreeFilter.ANY_DIFF)); RevCommit revCommit = revWalk.next(); if (revCommit == null) { throw new IllegalStateException("Unable to find any commit under " + _path); } if (hasIgnoreFile(repository, revCommit, relativePath)) { RevCommit secondRevCommit = revWalk.next(); if (secondRevCommit != null) { revCommit = secondRevCommit; } } Project currentProject = getProject(); String hash = revCommit.name(); currentProject.setNewProperty(_property, hash); if (_useCache) { _hashes.put(relativePath, hash); } revWalk.dispose(); } catch (Exception e) { throw new BuildException("Unable to get head hash for path " + _path, e); } }
private boolean processMerge(Candidate n) throws IOException { int pCnt = n.getParentCount(); // If any single parent exactly matches the merge, follow only // that one parent through history. ObjectId[] ids = null; for (int pIdx = 0; pIdx < pCnt; pIdx++) { RevCommit parent = n.getParent(pIdx); revPool.parseHeaders(parent); if (!find(parent, n.sourcePath)) continue; if (!(n instanceof ReverseCandidate) && idBuf.equals(n.sourceBlob)) return blameEntireRegionOnParent(n, parent); if (ids == null) ids = new ObjectId[pCnt]; ids[pIdx] = idBuf.toObjectId(); } // If rename detection is enabled, search for any relevant names. DiffEntry[] renames = null; if (renameDetector != null) { renames = new DiffEntry[pCnt]; for (int pIdx = 0; pIdx < pCnt; pIdx++) { RevCommit parent = n.getParent(pIdx); if (ids != null && ids[pIdx] != null) continue; DiffEntry r = findRename(parent, n.sourceCommit, n.sourcePath); if (r == null) continue; if (n instanceof ReverseCandidate) { if (ids == null) ids = new ObjectId[pCnt]; ids[pCnt] = r.getOldId().toObjectId(); } else if (0 == r.getOldId().prefixCompare(n.sourceBlob)) { // A 100% rename without any content change can also // skip directly to the parent. Note this bypasses an // earlier parent that had the path (above) but did not // have an exact content match. For performance reasons // we choose to follow the one parent over trying to do // possibly both parents. n.sourcePath = PathFilter.create(r.getOldPath()); return blameEntireRegionOnParent(n, parent); } renames[pIdx] = r; } } // Construct the candidate for each parent. Candidate[] parents = new Candidate[pCnt]; for (int pIdx = 0; pIdx < pCnt; pIdx++) { RevCommit parent = n.getParent(pIdx); Candidate p; if (renames != null && renames[pIdx] != null) { p = n.create(parent, PathFilter.create(renames[pIdx].getOldPath())); p.renameScore = renames[pIdx].getScore(); p.sourceBlob = renames[pIdx].getOldId().toObjectId(); } else if (ids != null && ids[pIdx] != null) { p = n.create(parent, n.sourcePath); p.sourceBlob = ids[pIdx]; } else { continue; } EditList editList; if (n instanceof ReverseCandidate && p.sourceBlob.equals(n.sourceBlob)) { // This special case happens on ReverseCandidate forks. p.sourceText = n.sourceText; editList = new EditList(0); } else { p.loadText(reader); editList = diffAlgorithm.diff(textComparator, p.sourceText, n.sourceText); } if (editList.isEmpty()) { // Ignoring whitespace (or some other special comparator) can // cause non-identical blobs to have an empty edit list. In // a case like this push the parent alone. if (n instanceof ReverseCandidate) { parents[pIdx] = p; continue; } p.regionList = n.regionList; n.regionList = null; parents[pIdx] = p; break; } p.takeBlame(editList, n); // Only remember this parent candidate if there is at least // one region that was blamed on the parent. if (p.regionList != null) { // Reverse blame requires inverting the regions. This puts // the regions the parent deleted from us into the parent, // and retains the common regions to look at other parents // for deletions. if (n instanceof ReverseCandidate) { Region r = p.regionList; p.regionList = n.regionList; n.regionList = r; } parents[pIdx] = p; } } if (n instanceof ReverseCandidate) { // On a reverse blame report all deletions found in the children, // and pass on to them a copy of our region list. Candidate resultHead = null; Candidate resultTail = null; for (int pIdx = 0; pIdx < pCnt; pIdx++) { Candidate p = parents[pIdx]; if (p == null) continue; if (p.regionList != null) { Candidate r = p.copy(p.sourceCommit); if (resultTail != null) { resultTail.queueNext = r; resultTail = r; } else { resultHead = r; resultTail = r; } } if (n.regionList != null) { p.regionList = n.regionList.deepCopy(); push(p); } } if (resultHead != null) return result(resultHead); return false; } // Push any parents that are still candidates. for (int pIdx = 0; pIdx < pCnt; pIdx++) { if (parents[pIdx] != null) push(parents[pIdx]); } if (n.regionList != null) return result(n); return false; }
private IDiffContainer buildDiffContainer( RevCommit baseCommit, RevCommit compareCommit, IProgressMonitor monitor) throws IOException, InterruptedException { boolean useIndex = compareVersion.equals(CompareTreeView.INDEX_VERSION); boolean checkIgnored = false; IDiffContainer result = new DiffNode(Differencer.CONFLICTING); try (TreeWalk tw = new TreeWalk(repository)) { // filter by selected resources if (filterPathStrings.size() > 1) { List<TreeFilter> suffixFilters = new ArrayList<TreeFilter>(); for (String filterPath : filterPathStrings) suffixFilters.add(PathFilter.create(filterPath)); TreeFilter otf = OrTreeFilter.create(suffixFilters); tw.setFilter(otf); } else if (filterPathStrings.size() > 0) { String path = filterPathStrings.get(0); if (path.length() != 0) tw.setFilter(PathFilter.create(path)); } tw.setRecursive(true); int baseTreeIndex; if (baseCommit == null) { // compare workspace with something checkIgnored = true; baseTreeIndex = tw.addTree(new FileTreeIterator(repository)); } else baseTreeIndex = tw.addTree( new CanonicalTreeParser(null, repository.newObjectReader(), baseCommit.getTree())); int compareTreeIndex; if (!useIndex) compareTreeIndex = tw.addTree( new CanonicalTreeParser( null, repository.newObjectReader(), compareCommit.getTree())); else // compare something with the index compareTreeIndex = tw.addTree(new DirCacheIterator(repository.readDirCache())); while (tw.next()) { if (monitor.isCanceled()) throw new InterruptedException(); AbstractTreeIterator compareVersionIterator = tw.getTree(compareTreeIndex, AbstractTreeIterator.class); AbstractTreeIterator baseVersionIterator = tw.getTree(baseTreeIndex, AbstractTreeIterator.class); if (checkIgnored && baseVersionIterator != null && ((WorkingTreeIterator) baseVersionIterator).isEntryIgnored()) continue; if (compareVersionIterator != null && baseVersionIterator != null) { boolean equalContent = compareVersionIterator .getEntryObjectId() .equals(baseVersionIterator.getEntryObjectId()); if (equalContent) continue; } String encoding = null; GitFileRevision compareRev = null; if (compareVersionIterator != null) { String entryPath = compareVersionIterator.getEntryPathString(); encoding = CompareCoreUtils.getResourceEncoding(repository, entryPath); if (!useIndex) compareRev = GitFileRevision.inCommit( repository, compareCommit, entryPath, tw.getObjectId(compareTreeIndex)); else compareRev = GitFileRevision.inIndex(repository, entryPath); } GitFileRevision baseRev = null; if (baseVersionIterator != null) { String entryPath = baseVersionIterator.getEntryPathString(); if (encoding == null) { encoding = CompareCoreUtils.getResourceEncoding(repository, entryPath); } baseRev = GitFileRevision.inCommit( repository, baseCommit, entryPath, tw.getObjectId(baseTreeIndex)); } if (compareVersionIterator != null && baseVersionIterator != null) { monitor.setTaskName(baseVersionIterator.getEntryPathString()); // content exists on both sides add( result, baseVersionIterator.getEntryPathString(), new DiffNode( new FileRevisionTypedElement(compareRev, encoding), new FileRevisionTypedElement(baseRev, encoding))); } else if (baseVersionIterator != null && compareVersionIterator == null) { monitor.setTaskName(baseVersionIterator.getEntryPathString()); // only on base side add( result, baseVersionIterator.getEntryPathString(), new DiffNode( Differencer.DELETION | Differencer.RIGHT, null, null, new FileRevisionTypedElement(baseRev, encoding))); } else if (compareVersionIterator != null && baseVersionIterator == null) { monitor.setTaskName(compareVersionIterator.getEntryPathString()); // only on compare side add( result, compareVersionIterator.getEntryPathString(), new DiffNode( Differencer.ADDITION | Differencer.RIGHT, null, new FileRevisionTypedElement(compareRev, encoding), null)); } if (monitor.isCanceled()) throw new InterruptedException(); } return result; } }
/** @return path file path being processed. */ public String getResultPath() { return resultPath.getPath(); }
private void buildMaps( Repository repository, RevCommit baseCommit, RevCommit compareCommit, IProgressMonitor monitor) throws InterruptedException, IOException { monitor.beginTask(UIText.CompareTreeView_AnalyzingRepositoryTaskText, IProgressMonitor.UNKNOWN); boolean useIndex = compareVersion.equals(INDEX_VERSION); deletedPaths.clear(); equalContentPaths.clear(); baseVersionMap.clear(); compareVersionMap.clear(); compareVersionPathsWithChildren.clear(); addedPaths.clear(); baseVersionPathsWithChildren.clear(); boolean checkIgnored = false; TreeWalk tw = new TreeWalk(repository); try { int baseTreeIndex; if (baseCommit == null) { checkIgnored = true; baseTreeIndex = tw.addTree( new AdaptableFileTreeIterator( repository, ResourcesPlugin.getWorkspace().getRoot())); } else baseTreeIndex = tw.addTree( new CanonicalTreeParser(null, repository.newObjectReader(), baseCommit.getTree())); int compareTreeIndex; if (!useIndex) compareTreeIndex = tw.addTree( new CanonicalTreeParser( null, repository.newObjectReader(), compareCommit.getTree())); else compareTreeIndex = tw.addTree(new DirCacheIterator(repository.readDirCache())); if (input instanceof IResource[]) { IResource[] resources = (IResource[]) input; List<TreeFilter> orFilters = new ArrayList<TreeFilter>(resources.length); for (IResource resource : resources) { String relPath = repositoryMapping.getRepoRelativePath(resource); if (relPath.length() > 0) orFilters.add(PathFilter.create(relPath)); } if (orFilters.size() > 1) tw.setFilter(OrTreeFilter.create(orFilters)); else if (orFilters.size() == 1) tw.setFilter(orFilters.get(0)); } tw.setRecursive(true); if (monitor.isCanceled()) throw new InterruptedException(); while (tw.next()) { if (monitor.isCanceled()) throw new InterruptedException(); AbstractTreeIterator compareVersionIterator = tw.getTree(compareTreeIndex, AbstractTreeIterator.class); AbstractTreeIterator baseVersionIterator = tw.getTree(baseTreeIndex, AbstractTreeIterator.class); if (checkIgnored && baseVersionIterator != null && ((WorkingTreeIterator) baseVersionIterator).isEntryIgnored()) continue; if (compareVersionIterator != null && baseVersionIterator != null) { monitor.setTaskName(baseVersionIterator.getEntryPathString()); IPath currentPath = new Path(baseVersionIterator.getEntryPathString()); if (!useIndex) compareVersionMap.put( currentPath, GitFileRevision.inCommit( repository, compareCommit, baseVersionIterator.getEntryPathString(), tw.getObjectId(compareTreeIndex))); else compareVersionMap.put( currentPath, GitFileRevision.inIndex(repository, baseVersionIterator.getEntryPathString())); if (baseCommit != null) baseVersionMap.put( currentPath, GitFileRevision.inCommit( repository, baseCommit, baseVersionIterator.getEntryPathString(), tw.getObjectId(baseTreeIndex))); boolean equalContent = compareVersionIterator .getEntryObjectId() .equals(baseVersionIterator.getEntryObjectId()); if (equalContent) equalContentPaths.add(currentPath); if (equalContent && !showEquals) continue; while (currentPath.segmentCount() > 0) { currentPath = currentPath.removeLastSegments(1); if (!baseVersionPathsWithChildren.add(currentPath)) break; } } else if (baseVersionIterator != null && compareVersionIterator == null) { monitor.setTaskName(baseVersionIterator.getEntryPathString()); // only on base side IPath currentPath = new Path(baseVersionIterator.getEntryPathString()); addedPaths.add(currentPath); if (baseCommit != null) baseVersionMap.put( currentPath, GitFileRevision.inCommit( repository, baseCommit, baseVersionIterator.getEntryPathString(), tw.getObjectId(baseTreeIndex))); while (currentPath.segmentCount() > 0) { currentPath = currentPath.removeLastSegments(1); if (!baseVersionPathsWithChildren.add(currentPath)) break; } } else if (compareVersionIterator != null && baseVersionIterator == null) { monitor.setTaskName(compareVersionIterator.getEntryPathString()); // only on compare side IPath currentPath = new Path(compareVersionIterator.getEntryPathString()); deletedPaths.add(currentPath); List<PathNodeAdapter> children = compareVersionPathsWithChildren.get(currentPath.removeLastSegments(1)); if (children == null) { children = new ArrayList<PathNodeAdapter>(1); compareVersionPathsWithChildren.put(currentPath.removeLastSegments(1), children); } children.add(new PathNodeAdapter(new PathNode(currentPath, Type.FILE_DELETED))); if (!useIndex) compareVersionMap.put( currentPath, GitFileRevision.inCommit( repository, compareCommit, compareVersionIterator.getEntryPathString(), tw.getObjectId(compareTreeIndex))); else compareVersionMap.put( currentPath, GitFileRevision.inIndex(repository, compareVersionIterator.getEntryPathString())); } } } finally { tw.release(); monitor.done(); } }
@Override public boolean shouldBeRecursive() { return path.shouldBeRecursive() || ANY_DIFF.shouldBeRecursive(); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { handleAuth(req); resp.setCharacterEncoding("UTF-8"); final PrintWriter out = resp.getWriter(); try { String pathInfo = req.getPathInfo(); Pattern pattern = Pattern.compile("/([^/]*)(?:/([^/]*)(?:/(.*))?)?"); Matcher matcher = pattern.matcher(pathInfo); matcher.matches(); String projectName = null; String refName = null; String filePath = null; if (matcher.groupCount() > 0) { projectName = matcher.group(1); refName = matcher.group(2); filePath = matcher.group(3); if (projectName == null || projectName.equals("")) { projectName = null; } else { projectName = java.net.URLDecoder.decode(projectName, "UTF-8"); } if (refName == null || refName.equals("")) { refName = null; } else { refName = java.net.URLDecoder.decode(refName, "UTF-8"); } if (filePath == null || filePath.equals("")) { filePath = null; } else { filePath = java.net.URLDecoder.decode(filePath, "UTF-8"); } } if (projectName != null) { if (filePath == null) filePath = ""; NameKey projName = NameKey.parse(projectName); ProjectControl control; try { control = projControlFactory.controlFor(projName); if (!control.isVisible()) { log.debug("Project not visible!"); resp.sendError( HttpServletResponse.SC_UNAUTHORIZED, "You need to be logged in to see private projects"); return; } } catch (NoSuchProjectException e1) { } Repository repo = repoManager.openRepository(projName); if (refName == null) { JSONArray contents = new JSONArray(); List<Ref> call; try { call = new Git(repo).branchList().call(); Git git = new Git(repo); for (Ref ref : call) { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("name", ref.getName()); jsonObject.put("type", "ref"); jsonObject.put("size", "0"); jsonObject.put("path", ""); jsonObject.put("project", projectName); jsonObject.put("ref", ref.getName()); lastCommit(git, null, ref.getObjectId(), jsonObject); } catch (JSONException e) { } contents.put(jsonObject); } String response = contents.toString(); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "W/\"" + response.length() + "-" + response.hashCode() + "\""); log.debug(response); out.write(response); } catch (GitAPIException e) { } } else { Ref head = repo.getRef(refName); if (head == null) { JSONArray contents = new JSONArray(); String response = contents.toString(); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "W/\"" + response.length() + "-" + response.hashCode() + "\""); log.debug(response); out.write(response); return; } RevWalk walk = new RevWalk(repo); // add try catch to catch failures Git git = new Git(repo); RevCommit commit = walk.parseCommit(head.getObjectId()); RevTree tree = commit.getTree(); TreeWalk treeWalk = new TreeWalk(repo); treeWalk.addTree(tree); treeWalk.setRecursive(false); if (!filePath.equals("")) { PathFilter pathFilter = PathFilter.create(filePath); treeWalk.setFilter(pathFilter); } if (!treeWalk.next()) { CanonicalTreeParser canonicalTreeParser = treeWalk.getTree(0, CanonicalTreeParser.class); JSONArray contents = new JSONArray(); if (canonicalTreeParser != null) { while (!canonicalTreeParser.eof()) { String path = canonicalTreeParser.getEntryPathString(); FileMode mode = canonicalTreeParser.getEntryFileMode(); listEntry( path, mode.equals(FileMode.TREE) ? "dir" : "file", "0", path, projectName, head.getName(), git, contents); canonicalTreeParser.next(); } } String response = contents.toString(); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "\"" + tree.getId().getName() + "\""); log.debug(response); out.write(response); } else { // if (treeWalk.isSubtree()) { // treeWalk.enterSubtree(); // } JSONArray contents = getListEntries(treeWalk, repo, git, head, filePath, projectName); String response = contents.toString(); resp.setContentType("application/json"); resp.setHeader("Cache-Control", "no-cache"); resp.setHeader("ETag", "\"" + tree.getId().getName() + "\""); log.debug(response); out.write(response); } walk.release(); treeWalk.release(); } } } catch (RepositoryNotFoundException e) { handleException(resp, e, 400); } catch (MissingObjectException e) { // example "Missing unknown 7035305927ca125757ecd8407e608f6dcf0bd8a5" // usually indicative of being unable to locate a commit from a submodule log.error(e.getMessage(), e); String msg = e.getMessage() + ". This exception could have been caused by the use of a git submodule, " + "which is currently not supported by the repository browser."; handleException(resp, new Exception(msg), 501); } catch (IOException e) { handleException(resp, e, 500); } finally { out.close(); } }
private boolean handleGetDiff( HttpServletRequest request, HttpServletResponse response, Repository db, String scope, String pattern, OutputStream out) throws Exception { Git git = new Git(db); DiffCommand diff = git.diff(); diff.setOutputStream(new BufferedOutputStream(out)); AbstractTreeIterator oldTree; AbstractTreeIterator newTree = new FileTreeIterator(db); if (scope.contains("..")) { // $NON-NLS-1$ String[] commits = scope.split("\\.\\."); // $NON-NLS-1$ if (commits.length != 2) { String msg = NLS.bind("Failed to generate diff for {0}", scope); return statusHandler.handleRequest( request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null)); } oldTree = getTreeIterator(db, commits[0]); newTree = getTreeIterator(db, commits[1]); } else if (scope.equals(GitConstants.KEY_DIFF_CACHED)) { ObjectId head = db.resolve(Constants.HEAD + "^{tree}"); // $NON-NLS-1$ if (head == null) { String msg = NLS.bind("Failed to generate diff for {0}, no HEAD", scope); return statusHandler.handleRequest( request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, msg, null)); } CanonicalTreeParser p = new CanonicalTreeParser(); ObjectReader reader = db.newObjectReader(); try { p.reset(reader, head); } finally { reader.release(); } oldTree = p; newTree = new DirCacheIterator(db.readDirCache()); } else if (scope.equals(GitConstants.KEY_DIFF_DEFAULT)) { oldTree = new DirCacheIterator(db.readDirCache()); } else { oldTree = getTreeIterator(db, scope); } String[] paths = request.getParameterValues(ProtocolConstants.KEY_PATH); TreeFilter filter = null; TreeFilter pathFilter = null; if (paths != null) { if (paths.length > 1) { Set<TreeFilter> pathFilters = new HashSet<TreeFilter>(paths.length); for (String path : paths) { pathFilters.add(PathFilter.create(path)); } pathFilter = OrTreeFilter.create(pathFilters); } else if (paths.length == 1) { pathFilter = PathFilter.create(paths[0]); } } if (pattern != null) { PathFilter patternFilter = PathFilter.create(pattern); if (pathFilter != null) filter = AndTreeFilter.create(patternFilter, pathFilter); else filter = patternFilter; } else { filter = pathFilter; } if (filter != null) diff.setPathFilter(filter); diff.setOldTree(oldTree); diff.setNewTree(newTree); diff.call(); return true; }
/** * Create a new tree filter for a user supplied path. * * <p>Path strings are relative to the root of the repository. If the user's input should be * assumed relative to a subdirectory of the repository the caller must prepend the subdirectory's * path prior to creating the filter. * * <p>Path strings use '/' to delimit directories on all platforms. * * @param path the path to filter on. Must not be the empty string. All trailing '/' characters * will be trimmed before string's length is checked or is used as part of the constructed * filter. * @return a new filter for the requested path. * @throws IllegalArgumentException the path supplied was the empty string. */ public static FollowFilter create(String path) { return new FollowFilter(PathFilter.create(path)); }
@Override public TreeFilter clone() { return new FollowFilter(path.clone()); }
@Override public boolean include(final TreeWalk walker) throws MissingObjectException, IncorrectObjectTypeException, IOException { return path.include(walker) && ANY_DIFF.include(walker); }
protected void addInformationForPath( Repository repository, Git git, DocumentWriter writer, RevCommit commit, String path, CallSpecification spec, Values values) throws GitAPIException, IOException { // Make sure the path is in the canonical form we need ... if (path.startsWith("/")) { if (path.length() == 1) path = ""; else path = path.substring(1); } // Now see if we're actually referring to the "jcr:content" node ... boolean isContentNode = false; if (path.endsWith(JCR_CONTENT_SUFFIX)) { isContentNode = true; path = path.substring(0, path.length() - JCR_CONTENT_SUFFIX.length()); } // Create the TreeWalk that we'll use to navigate the files/directories ... final TreeWalk tw = new TreeWalk(repository); tw.addTree(commit.getTree()); if ("".equals(path)) { // This is the top-level directory, so we don't need to pre-walk to find anything ... tw.setRecursive(false); while (tw.next()) { String childName = tw.getNameString(); String childId = spec.childId(childName); writer.addChild(childId, childName); } } else { // We need to first find our path *before* we can walk the children ... PathFilter filter = PathFilter.create(path); tw.setFilter(filter); while (tw.next()) { if (filter.isDone(tw)) { break; } else if (tw.isSubtree()) { tw.enterSubtree(); } } // Now that the TreeWalk is the in right location given by the 'path', we can get the if (tw.isSubtree()) { // The object at the 'path' is a directory, so go into it ... tw.enterSubtree(); // Find the commit in which this folder was last modified ... // This may not be terribly efficient, but it seems to work faster on subsequent runs ... RevCommit folderCommit = git.log().addPath(path).call().iterator().next(); // Add folder-related properties ... String committer = folderCommit.getCommitterIdent().getName(); String author = folderCommit.getAuthorIdent().getName(); DateTime committed = values.dateFrom(folderCommit.getCommitTime()); writer.setPrimaryType(GitLexicon.FOLDER); writer.addProperty(JcrLexicon.CREATED, committed); writer.addProperty(JcrLexicon.CREATED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, folderCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, folderCommit.getShortMessage()); // And now walk the contents of the directory ... while (tw.next()) { String childName = tw.getNameString(); String childId = spec.childId(childName); writer.addChild(childId, childName); } } else { // The path specifies a file (or a content node) ... // Find the commit in which this folder was last modified ... // This may not be terribly efficient, but it seems to work faster on subsequent runs ... RevCommit fileCommit = git.log().addPath(path).call().iterator().next(); // Add file-related properties ... String committer = fileCommit.getCommitterIdent().getName(); String author = fileCommit.getAuthorIdent().getName(); DateTime committed = values.dateFrom(fileCommit.getCommitTime()); if (isContentNode) { writer.setPrimaryType(GitLexicon.RESOURCE); writer.addProperty(JcrLexicon.LAST_MODIFIED, committed); writer.addProperty(JcrLexicon.LAST_MODIFIED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, fileCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, fileCommit.getShortMessage()); // Create the BinaryValue ... ObjectId fileObjectId = tw.getObjectId(0); ObjectLoader fileLoader = repository.open(fileObjectId); BinaryKey key = new BinaryKey(fileObjectId.getName()); BinaryValue value = values.binaryFor(key, fileLoader.getSize()); if (value == null) { // It wasn't found in the binary store ... if (fileLoader.isLarge()) { // Too large to hold in memory, so use the binary store (which reads the file // immediately) ... value = values.binaryFrom(fileLoader.openStream()); } else { // This is small enough to fit into a byte[], but it still may be pretty big ... value = new GitBinaryValue( fileObjectId, fileLoader, connector.getSourceName(), name, connector.getMimeTypeDetector()); } } writer.addProperty(JcrLexicon.DATA, value); if (connector.includeMimeType()) { try { String filename = spec.parameter(spec.parameterCount() - 1); // the last is 'jcr:content' String mimeType = value.getMimeType(filename); if (mimeType != null) writer.addProperty(JcrLexicon.MIMETYPE, mimeType); } catch (RepositoryException e) { // do nothing } catch (IOException e) { // do nothing } } } else { writer.setPrimaryType(GitLexicon.FILE); writer.addProperty(JcrLexicon.CREATED, committed); writer.addProperty(JcrLexicon.CREATED_BY, committer); writer.addProperty(GitLexicon.OBJECT_ID, fileCommit.getId().name()); writer.addProperty(GitLexicon.AUTHOR, author); writer.addProperty(GitLexicon.COMMITTER, committer); writer.addProperty(GitLexicon.COMMITTED, committed); writer.addProperty(GitLexicon.TITLE, fileCommit.getShortMessage()); // Add the "jcr:content" child node ... String childId = spec.childId(JCR_CONTENT); writer.addChild(childId, JCR_CONTENT); } } } }