33
44package app.hashers
55
6+ import app.FactKey
67import app.Logger
78import app.api.Api
89import app.extractors.Extractor
10+ import app.model.Author
911import app.model.Commit
1012import app.model.DiffContent
1113import app.model.DiffFile
1214import app.model.DiffRange
15+ import app.model.Fact
1316import app.model.LocalRepo
1417import app.model.Repo
1518import app.utils.RepoHelper
@@ -26,6 +29,8 @@ import org.eclipse.jgit.lib.ObjectId
2629import org.eclipse.jgit.errors.MissingObjectException
2730import org.eclipse.jgit.revwalk.RevCommit
2831import org.eclipse.jgit.util.io.DisabledOutputStream
32+ import java.time.LocalDateTime
33+ import java.time.ZoneOffset
2934import java.util.concurrent.TimeUnit
3035
3136/* *
@@ -35,32 +40,52 @@ class CommitHasher(private val localRepo: LocalRepo,
3540 private val repo : Repo = Repo (),
3641 private val api : Api ,
3742 private val git : Git ) {
43+
3844 private val gitRepo: Repository = git.repository
3945
4046 private fun findFirstOverlappingCommit (): Commit ? {
4147 val serverHistoryCommits = repo.commits.toHashSet()
42- return getObservableCommits ()
48+ return getCommitsAsObservable ()
4349 .skipWhile { commit -> ! serverHistoryCommits.contains(commit) }
4450 .blockingFirst(null )
4551 }
4652
4753 private fun hashAndSendCommits () {
4854 val lastKnownCommit = repo.commits.lastOrNull()
4955 val knownCommits = repo.commits.toHashSet()
56+
57+ val factsDayWeek = hashMapOf<Author , Array <Int >>()
58+ val factsDayTime = hashMapOf<Author , Array <Int >>()
59+
5060 // Commits are combined in pairs, an empty commit concatenated to
5161 // calculate the diff of the initial commit.
52- Observable .concat(getObservableCommits(), Observable .just(Commit ()))
62+ Observable .concat(getCommitsAsObservable()
63+ .doOnNext { commit ->
64+ Logger .debug(" Commit: ${commit.raw?.name ? : " " } : "
65+ + commit.raw?.shortMessage)
66+ commit.repo = repo
67+
68+ // Calculate facts.
69+ val author = commit.author
70+ val factDayWeek = factsDayWeek[author] ? : Array (7 ) { 0 }
71+ val factDayTime = factsDayTime[author] ? : Array (24 ) { 0 }
72+ val timestamp = commit.dateTimestamp
73+ val dateTime = LocalDateTime .ofEpochSecond(timestamp, 0 ,
74+ ZoneOffset .ofTotalSeconds(commit.dateTimeZoneOffset * 60 ))
75+ // The value is numbered from 1 (Monday) to 7 (Sunday).
76+ factDayWeek[dateTime.dayOfWeek.value - 1 ] + = 1
77+ // Hour from 0 to 23.
78+ factDayTime[dateTime.hour] + = 1
79+ factsDayWeek[author] = factDayWeek
80+ factsDayTime[author] = factDayTime
81+ }, Observable .just(Commit ()))
5382 .pairWithNext() // Pair commits to get diff.
5483 .takeWhile { (new, _) -> // Hash until last known commit.
5584 new.rehash != lastKnownCommit?.rehash }
5685 .filter { (new, _) -> knownCommits.isEmpty() // Don't hash known.
5786 || ! knownCommits.contains(new) }
5887 .filter { (new, _) -> emailFilter(new) } // Email filtering.
5988 .map { (new, old) -> // Mapping and stats extraction.
60- Logger .debug(" Commit: ${new.raw?.name ? : " " } : "
61- + new.raw?.shortMessage)
62- new.repo = repo
63-
6489 val diffFiles = getDiffFiles(new, old)
6590 Logger .debug(" Diff: ${diffFiles.size} entries" )
6691 new.stats = Extractor ().extract(diffFiles)
@@ -73,18 +98,33 @@ class CommitHasher(private val localRepo: LocalRepo,
7398 total + file.getAllAdded().size }
7499 new.numLinesDeleted = diffFiles.fold(0 ) { total, file ->
75100 total + file.getAllDeleted().size }
76-
77101 new
78102 }
79103 .observeOn(Schedulers .io()) // Different thread for data sending.
80104 .buffer(20 , TimeUnit .SECONDS ) // Group ready commits by time.
81- .doOnNext { commitsBundle -> // Send ready commits.
82- postCommitsToServer(commitsBundle) }
83- .blockingSubscribe({
84- // OnNext
85- }, { t -> // OnError
86- Logger .error(" Error while hashing: $t " )
87- t.printStackTrace()
105+ .blockingSubscribe({ commitsBundle -> // OnNext.
106+ postCommitsToServer(commitsBundle) // Send ready commits.
107+ }, { e -> // OnError.
108+ Logger .error(" Error while hashing: $e " )
109+ }, { // OnComplete.
110+ val facts = mutableListOf<Fact >()
111+ factsDayTime.map { (author, list) ->
112+ list.forEachIndexed { hour, count ->
113+ if (count > 0 ) {
114+ facts.add(Fact (repo, FactKey .COMMITS_DAY_TIME +
115+ hour, count.toDouble(), author))
116+ }
117+ }
118+ }
119+ factsDayWeek.map { (author, list) ->
120+ list.forEachIndexed { day, count ->
121+ if (count > 0 ) {
122+ facts.add(Fact (repo, FactKey .COMMITS_DAY_WEEK +
123+ day, count.toDouble(), author))
124+ }
125+ }
126+ }
127+ postFactsToServer(facts)
88128 })
89129 }
90130
@@ -142,14 +182,21 @@ class CommitHasher(private val localRepo: LocalRepo,
142182 }
143183 }
144184
185+ private fun postFactsToServer (facts : List <Fact >) {
186+ if (facts.isNotEmpty()) {
187+ api.postFacts(facts)
188+ Logger .debug(" Sent ${facts.size} facts to server" )
189+ }
190+ }
191+
145192 private fun deleteCommitsOnServer (commits : List <Commit >) {
146193 if (commits.isNotEmpty()) {
147194 api.deleteCommits(commits)
148195 Logger .debug(" Sent ${commits.size} deleted commits to server" )
149196 }
150197 }
151198
152- private fun getObservableCommits (): Observable <Commit > =
199+ private fun getCommitsAsObservable (): Observable <Commit > =
153200 Observable .create { subscriber ->
154201 try {
155202 val revWalk = RevWalk (gitRepo)
0 commit comments