/** * Returns the list of lines in the specified source file annotated with the source commit * metadata. * * @param repository * @param blobPath * @param objectId * @return list of annotated lines */ public static List<AnnotatedLine> blame(Repository repository, String blobPath, String objectId) { List<AnnotatedLine> lines = new ArrayList<AnnotatedLine>(); try { ObjectId object; if (StringUtils.isEmpty(objectId)) { object = JGitUtils.getDefaultBranch(repository); } else { object = repository.resolve(objectId); } BlameCommand blameCommand = new BlameCommand(repository); blameCommand.setFilePath(blobPath); blameCommand.setStartCommit(object); BlameResult blameResult = blameCommand.call(); RawText rawText = blameResult.getResultContents(); int length = rawText.size(); for (int i = 0; i < length; i++) { RevCommit commit = blameResult.getSourceCommit(i); AnnotatedLine line = new AnnotatedLine(commit, i + 1, rawText.getString(i)); lines.add(line); } } catch (Throwable t) { try { error(t, repository, "failed to generate blame for {0} {1}!", blobPath, objectId); } catch (Exception e) { } } return lines; }
/** * Push a candidate blob onto the generator's traversal stack. * * <p>Candidates should be pushed in history order from oldest-to-newest. Applications should push * the starting commit first, then the index revision (if the index is interesting), and finally * the working tree copy (if the working tree is interesting). * * @param description description of the blob revision, such as "Working Tree". * @param contents contents of the file. * @return {@code this} * @throws IOException the repository cannot be read. */ public BlameGenerator push(String description, RawText contents) throws IOException { if (description == null) description = JGitText.get().blameNotCommittedYet; BlobCandidate c = new BlobCandidate(description, resultPath); c.sourceText = contents; c.regionList = new Region(0, 0, contents.size()); remaining = contents.size(); push(c); return this; }
public Edition(Edit edit, RawText a, RawText b) { this.beginA = edit.getBeginA(); this.beginB = edit.getBeginB(); this.type = typeof(edit.getType()); this.ca = new ArrayList<String>(); this.cb = new ArrayList<String>(); for (int i = beginA; i < edit.getEndA(); ++i) { ca.add(a.getString(i) + '\n'); } for (int i = beginB; i < edit.getEndB(); ++i) { cb.add(b.getString(i) + '\n'); } }
private int findLine(int b, String regex) { String re = regex.substring(1, regex.length() - 1); if (!re.startsWith("^")) // $NON-NLS-1$ re = ".*" + re; // $NON-NLS-1$ if (!re.endsWith("$")) // $NON-NLS-1$ re = re + ".*"; // $NON-NLS-1$ Pattern p = Pattern.compile(re); RawText text = blame.getResultContents(); for (int line = b; line < text.size(); line++) { if (p.matcher(text.getString(line)).matches()) return line; } return b; }
private boolean isBinary(Entry entry) throws IOException { InputStream in = entry.openInputStream(); try { return RawText.isBinary(in); } finally { safeClose(in); } }
/** * Get list of hunks * * @throws java.io.IOException */ public List<Hunk> getHunks() throws IOException { List<Hunk> hunks = new ArrayList<>(); for (int curIdx = 0; curIdx < editList.size(); ) { Hunk hunk = new Hunk(); Edit curEdit = editList.get(curIdx); final int endIdx = findCombinedEnd(editList, curIdx); final Edit endEdit = editList.get(endIdx); int aCur = Math.max(0, curEdit.getBeginA() - context); int bCur = Math.max(0, curEdit.getBeginB() - context); final int aEnd = Math.min(a.size(), endEdit.getEndA() + context); final int bEnd = Math.min(b.size(), endEdit.getEndB() + context); hunk.beginA = aCur; hunk.endA = aEnd; hunk.beginB = bCur; hunk.endB = bEnd; while (aCur < aEnd || bCur < bEnd) { if (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) { hunk.lines.add(new DiffLine(this, DiffLineType.CONTEXT, aCur, bCur, a.getString(aCur))); isEndOfLineMissing = checkEndOfLineMissing(a, aCur); aCur++; bCur++; } else if (aCur < curEdit.getEndA()) { hunk.lines.add(new DiffLine(this, DiffLineType.REMOVE, aCur, bCur, a.getString(aCur))); isEndOfLineMissing = checkEndOfLineMissing(a, aCur); aCur++; } else if (bCur < curEdit.getEndB()) { hunk.lines.add(new DiffLine(this, DiffLineType.ADD, aCur, bCur, b.getString(bCur))); isEndOfLineMissing = checkEndOfLineMissing(a, aCur); bCur++; } if (end(curEdit, aCur, bCur) && ++curIdx < editList.size()) curEdit = editList.get(curIdx); } hunks.add(hunk); } return hunks; }
@Override protected void writeLine(final char prefix, final RawText text, final int cur) throws IOException { if (nofLinesCurrent++ == 0) { handleChange(); startCurrent = os.size(); } // update entry diffstat currentPath.update(prefix); if (isOff) { return; } totalNofLinesCurrent++; if (nofLinesCurrent > maxDiffLinesPerFile && maxDiffLinesPerFile > 0) { reset(); } else { // output diff os.write("<tr>".getBytes()); switch (prefix) { case '+': os.write( ("<th class='diff-line'></th><th class='diff-line' data-lineno='" + (right++) + "'></th>") .getBytes()); os.write("<th class='diff-state diff-state-add'></th>".getBytes()); os.write("<td class='diff-cell add2'>".getBytes()); break; case '-': os.write( ("<th class='diff-line' data-lineno='" + (left++) + "'></th><th class='diff-line'></th>") .getBytes()); os.write("<th class='diff-state diff-state-sub'></th>".getBytes()); os.write("<td class='diff-cell remove2'>".getBytes()); break; default: os.write( ("<th class='diff-line' data-lineno='" + (left++) + "'></th><th class='diff-line' data-lineno='" + (right++) + "'></th>") .getBytes()); os.write("<th class='diff-state'></th>".getBytes()); os.write("<td class='diff-cell context2'>".getBytes()); break; } os.write(encode(codeLineToHtml(prefix, text.getString(cur)))); os.write("</td></tr>\n".getBytes()); } }
private ObjectNode fileAsJson(String path, org.tmatesoft.svn.core.io.SVNRepository repository) throws SVNException, IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); SVNProperties prop = new SVNProperties(); repository.getFile(path, -1l, prop, baos); SVNDirEntry entry = repository.info(path, -1l); long size = entry.getSize(); boolean isBinary; String mimeType; String data = null; if (size > MAX_FILE_SIZE_CAN_BE_VIEWED) { isBinary = true; mimeType = "application/octet-stream"; } else { byte[] bytes = baos.toByteArray(); isBinary = RawText.isBinary(bytes); if (!isBinary) { data = new String(bytes, FileUtil.detectCharset(bytes)); } mimeType = new Tika().detect(bytes, path); } String author = prop.getStringValue(SVNProperty.LAST_AUTHOR); User user = User.findByLoginId(author); String commitDate = prop.getStringValue(SVNProperty.COMMITTED_DATE); DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTime(); Long commitTime = dateFormatter.parseMillis(commitDate); ObjectNode result = Json.newObject(); result.put("type", "file"); result.put("revisionNo", prop.getStringValue(SVNProperty.COMMITTED_REVISION)); result.put("author", author); result.put("avatar", getAvatar(user)); result.put("userName", user.name); result.put("userLoginId", user.loginId); result.put("createdDate", commitTime); result.put("commitMessage", entry.getCommitMessage()); result.put("commiter", author); result.put("size", size); result.put("isBinary", isBinary); result.put("mimeType", mimeType); result.put("data", data); return result; }
private boolean isBinary(byte[] content, int sz) { return RawText.isBinary(content, sz); }
private boolean checkEndOfLineMissing(final RawText text, final int line) { return line + 1 == text.size() && text.isMissingNewlineAtEnd(); }