/** * Get the history after a specified revision. * * <p>The default implementation first fetches the full history and then throws away the oldest * revisions. This is not efficient, so subclasses should override it in order to get good * performance. Once every subclass has implemented a more efficient method, the default * implementation should be removed and made abstract. * * @param file the file to get the history for * @param sinceRevision the revision right before the first one to return, or {@code null} to * return the full history * @return partial history for file * @throws HistoryException on error accessing the history */ History getHistory(File file, String sinceRevision) throws HistoryException { // If we want an incremental history update and get here, warn that // it may be slow. if (sinceRevision != null) { Logger logger = OpenGrokLogger.getLogger(); logger.log( Level.WARNING, "Incremental history retrieval is not implemented for {0}.", getClass().getSimpleName()); logger.log(Level.WARNING, "Falling back to slower full history retrieval."); } History history = getHistory(file); if (sinceRevision == null) { return history; } List<HistoryEntry> partial = new ArrayList<>(); for (HistoryEntry entry : history.getHistoryEntries()) { partial.add(entry); if (sinceRevision.equals(entry.getRevision())) { // Found revision right before the first one to return. break; } } removeAndVerifyOldestChangeset(partial, sinceRevision); history.setHistoryEntries(partial); return history; }
/** Helper for {@link #get(File, Repository)}. */ private History getHistory(File file, Repository repository, boolean withFiles) throws HistoryException, SQLException { final String filePath = getSourceRootRelativePath(file); final String reposPath = toUnixPath(repository.getDirectoryName()); final ArrayList<HistoryEntry> entries = new ArrayList<HistoryEntry>(); final ConnectionResource conn = connectionManager.getConnectionResource(); try { final PreparedStatement ps; if (file.isDirectory()) { // Fetch history for all files under this directory. ps = conn.getStatement(GET_DIR_HISTORY); ps.setString(2, filePath); } else { // Fetch history for a single file only. ps = conn.getStatement(GET_FILE_HISTORY); ps.setString(2, getParentPath(filePath)); ps.setString(3, getBaseName(filePath)); } ps.setString(1, reposPath); final PreparedStatement filePS = withFiles ? conn.getStatement(GET_CS_FILES) : null; try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { // Get the information about a changeset String revision = rs.getString(1); String author = rs.getString(2); Timestamp time = rs.getTimestamp(3); String message = rs.getString(4); HistoryEntry entry = new HistoryEntry(revision, time, author, null, message, true); entries.add(entry); // Fill the list of files touched by the changeset, if // requested. if (withFiles) { int changeset = rs.getInt(5); filePS.setInt(1, changeset); try (ResultSet fileRS = filePS.executeQuery()) { while (fileRS.next()) { entry.addFile(fileRS.getString(1)); } } } } } } finally { connectionManager.releaseConnection(conn); } History history = new History(); history.setHistoryEntries(entries); RuntimeEnvironment env = RuntimeEnvironment.getInstance(); if (env.isTagsEnabled() && repository.hasFileBasedTags()) { repository.assignTagsInHistory(history); } return history; }