Getting commits log via VcsLogProvider/Manager/Data

Answered

The class which I see mentioned here most often is "GitHistoryUtils", for Git.

However my requirement is extracting the commit log in a implementation-agnostic manner: I should get what the VCS log toolwindow gets.
After looking through the sources I found a series of interfaces and classes that looks promising.

VcsLogProvider
VcsLogManager
VcsLogData
DataPack

In the end I came up with this

// "queue" is a blocking queue used to wait for the new DataPack
// to become available
private fun getVcsCommits(): List<VcsCommitMetadata> {
val vcsLogManager = VcsProjectLog.getInstance(project).logManager!!
val vcsLogData = vcsLogManager.dataManager
val listener = object : DataPackChangeListener {
override fun onDataPackChange(newDataPack: DataPack) {
vcsLogData.removeDataPackChangeListener(this)
queue.put(Unit)
}
}

vcsLogData.addDataPackChangeListener(listener)
vcsLogData.refresh(vcsLogData.roots)
queue.take()

val metadata = mutableListOf<VcsCommitMetadata>()
val allCommits = vcsLogData.dataPack.permanentGraph.allCommits
vcsLogData.miniDetailsGetter.loadCommitsData(
allCommits.map { it.id },
metadata::add,
ProgressManager.getInstance().progressIndicator,
)

return metadata
}

However this doesn't feel right to me.

Are there better way to accomplish this task?
Also, optionally, how could I ask the log provider to give me a graph with only commits in a certain branch (maybe using "VcsRef"? It seems I can check for match with "getContainingBranches") ?

3 comments
Comment actions Permalink

My new code is

private fun getVcsCommits(): List<VcsCommitMetadata> {
val projectVcsManager = ProjectLevelVcsManager.getInstance(project)
val activeVcsRoots = projectVcsManager.allVcsRoots.toList()
return VcsLogManager.findLogProviders(activeVcsRoots, project)
.asSequence()
.map { (root, logProvider) -> logProvider.readFirstBlock(root) { 100 } }
.map { it.commits }
.toList()
.let(VcsLogMultiRepoJoiner<Hash, VcsCommitMetadata>()::join)
}

Which now makes total sense. I think I got it! Am I right?

0
Comment actions Permalink

You can simplify it with:

private fun getVcsCommits(): List<VcsCommitMetadata> =
  VcsProjectLog.getLogProviders(project)
.map { (root, logProvider) -> logProvider.readFirstBlock(root) { 100 }.commits }
.toList()
.let(VcsLogMultiRepoJoiner<Hash, VcsCommitMetadata>()::join)

0
Comment actions Permalink

Jakub Chrzanowski thank you very much!

On a related note, what about listening to log refresh events? For example when a user does a new commit, or when commits are pulled locally from remote.

Which listener is more appropriate?

DataPackChangeListener
VcsLogListener // This doesn't seem a good pick
VcsLogProvider#subscribeToRootRefreshEvents

I would like to cache commits if possible and only reload them when necessary.

There is also

TopCommitsCache
0

Please sign in to leave a comment.