Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

wip: separate RepoHasher and CommitHasher, basic integration of CodeL... #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
astansler merged 2 commits into master from dev
Aug 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
// Copyright 2017 Sourcerer Inc. All Rights Reserved.
// Author: Alexander Surkov (alex@sourcerer.io)

package app

package app.hashers

import app.Logger
import app.api.Api
import app.config.Configurator
import app.model.LocalRepo
import app.model.Repo
import app.utils.RepoHelper
import org.eclipse.jgit.diff.DiffFormatter
import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.diff.RawText
import org.eclipse.jgit.internal.storage.file.FileRepository
import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.lib.ObjectLoader
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.revwalk.RevWalk
Expand All @@ -28,7 +32,8 @@ class RevCommitLine(val commit: RevCommit, val file: String, val line: Int)
*
* TODO(Alex): the text arg is solely for testing proposes (remove it)
*/
class CodeLine(val from: RevCommitLine, val to: RevCommitLine, val text: String) {
class CodeLine(val from: RevCommitLine, val to: RevCommitLine,
val text: String) {

// TODO(alex): oldId and newId may be computed as a hash built from commit,
// file name and line number, if we are going to send the data outside a
Expand Down Expand Up @@ -69,10 +74,14 @@ class CodeLine(val from: RevCommitLine, val to: RevCommitLine, val text: String)
/**
* Used to compute age of code lines in the repo.
*/
class CodeLongevity(repoPath: String, tailRev: String) {
val repo = FileRepository(repoPath)
class CodeLongevity(private val localRepo: LocalRepo,
private val serverRepo: Repo,
private val api: Api,
private val configurator: Configurator,
private val git: Git, tailRev: String = "") {
val repo: Repository = git.repository
val head: RevCommit =
RevWalk(repo).parseCommit(repo.resolve("refs/heads/master"))
RevWalk(repo).parseCommit(repo.resolve(RepoHelper.MASTER_BRANCH))
val tail: RevCommit? =
if (tailRev != "") RevWalk(repo).parseCommit(repo.resolve(tailRev))
else null
Expand All @@ -83,30 +92,31 @@ class CodeLongevity(repoPath: String, tailRev: String) {
*/
var codeLines: MutableList<CodeLine> = mutableListOf()

init {
fun update() {
compute()
}

// TODO(alex) debugging, remove it
fun ohNoDoesItReallyWork(email: String) {
var sum: Long = 0
var total: Long = 0
// TODO(anatoly): Add emails from server or hashAll.
val emails = hashSetOf(localRepo.author.email)

val sum: MutableMap<String, Long> = emails.associate { Pair(it, 0L) }
.toMutableMap()
val total: Int = codeLines.size
for (line in codeLines) {
val author = line.from.commit.getAuthorIdent()
if (author.getEmailAddress() != email) {
val email = line.from.commit.authorIdent.emailAddress
if (!emails.contains(email)) {
Copy link
Member

@sergey48k sergey48k Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to compute average for entire repo. Remember the chart?

Copy link
Member Author

@astansler astansler Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be in next pr very-very soon.

continue
}
println(line.toString())
println(" Age: ${line.age} secs")
sum += line.age
total++
}
Logger.debug(line.toString())
Logger.debug("Age: ${line.age} secs")

//println("All lines:")
//codeLines.forEach { line -> line.printme() }
sum[email] = sum[email]!! + line.age
}

var avg = if (total > 0) sum / total else 0
println("avg code line age for <$email> is ${avg} seconds, lines total: ${total}")
for (email in emails) {
val avg = if (total > 0) sum[email]!! / total else 0
println("Average code line age for <$email> is $avg seconds, "
+ "lines total: $total")
}
}

/**
Expand Down Expand Up @@ -143,14 +153,16 @@ class CodeLongevity(repoPath: String, tailRev: String) {

var commit: RevCommit? = revWalk.next() // move the walker to the head
while (commit != null && commit != tail) {
var parentCommit: RevCommit? = revWalk.next()
val parentCommit: RevCommit? = revWalk.next()

println("commit: ${commit.getName()}; '${commit.getShortMessage()}'")
Logger.debug("commit: ${commit.getName()}; " +
"'${commit.getShortMessage()}'")
if (parentCommit != null) {
println("parent commit: ${parentCommit.getName()}; '${parentCommit.getShortMessage()}'")
Logger.debug("parent commit: ${parentCommit.getName()}; "
+ "'${parentCommit.getShortMessage()}'")
}
else {
println("parent commit: null")
Logger.debug("parent commit: null")
}

// A step back in commits history. Update the files map according
Expand All @@ -161,7 +173,7 @@ class CodeLongevity(repoPath: String, tailRev: String) {
val oldId = diff.getOldId().toObjectId()
val newPath = diff.getNewPath()
val newId = diff.getNewId().toObjectId()
println("old: '$oldPath', new: '$newPath'")
Logger.debug("old: '$oldPath', new: '$newPath'")

// Skip binary files.
var fileId = if (newPath != DiffEntry.DEV_NULL) newId else oldId
Expand All @@ -186,8 +198,12 @@ class CodeLongevity(repoPath: String, tailRev: String) {
}

// If a file was deleted, then the new path is /dev/null.
val path = if (newPath != DiffEntry.DEV_NULL) newPath else oldPath
var lines = files.get(path)!!
val path = if (newPath != DiffEntry.DEV_NULL) {
Copy link
Member

@sergey48k sergey48k Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did this change? the original looked more compact.

Copy link
Member Author

@astansler astansler Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't fit 80 limit.

newPath
} else {
oldPath
}
val lines = files.get(path)!!

// Update the lines array to match the diff's edit list changes.
// Traverse the edit list backwards to keep indices of the edit
Expand All @@ -200,7 +216,8 @@ class CodeLongevity(repoPath: String, tailRev: String) {
var insStart = edit.getBeginB()
var insEnd = edit.getEndB()
val insCount = edit.getLengthB()
println("del ($delStart, $delEnd), ins ($insStart, $insEnd)")
Logger.debug("del ($delStart, $delEnd), "
+ "ins ($insStart, $insEnd)")

// Deletion case. Chase down the deleted lines through the
// history.
Expand All @@ -209,7 +226,9 @@ class CodeLongevity(repoPath: String, tailRev: String) {
for (idx in delStart .. delEnd - 1) {
tmpLines.add(RevCommitLine(commit, oldPath, idx))
}
lines.addAll(delStart, tmpLines)
// TODO(alex): Approve code change.
// delStart index caused IndexOutOfBoundException.
lines.addAll(tmpLines)
Copy link
Member

@sergey48k sergey48k Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really need unit tests, right @asurkov ?

Copy link
Contributor

@asurkov asurkov Sep 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. Btw, I always though that TODO(name) is about who added a todo item, not a person who's supposed to fix it.

Copy link
Member Author

@astansler astansler Sep 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think of this as a way to notify a person. Is there any conventions on that?

}

// Insertion case. Track it.
Expand Down Expand Up @@ -243,7 +262,8 @@ class CodeLongevity(repoPath: String, tailRev: String) {
for ((file, lines) in files) {
for (idx in 0 .. lines.size - 1) {
val from = RevCommitLine(tail, file, idx)
val cl = CodeLine(from, lines[idx], "no data (too lazy to compute)")
val cl = CodeLine(from, lines[idx],
"no data (too lazy to compute)")
codeLines.add(cl)
}
}
Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright 2017 Sourcerer Inc. All Rights Reserved.
// Author: Anatoly Kislov (anatoly@sourcerer.io)

package app
package app.hashers

import app.Logger
import app.api.Api
import app.config.Configurator
import app.extractors.Extractor
Expand All @@ -17,8 +18,6 @@ import org.eclipse.jgit.api.Git
import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.revwalk.RevWalk
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
import org.eclipse.jgit.diff.DiffFormatter
import org.eclipse.jgit.lib.ObjectId
Expand All @@ -28,42 +27,15 @@ import java.nio.file.Paths
import java.util.concurrent.TimeUnit

/**
* RepoHasher hashes repository and uploads stats to server.
* CommitHasher hashes repository and uploads stats to server.
*/
class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
private val configurator: Configurator) {
private var repo: Repo = Repo()
private val git: Git = loadGit() ?:
throw IllegalStateException("Git failed to load")
class CommitHasher(private val localRepo: LocalRepo,
private val repo: Repo = Repo(),
private val api: Api,
private val configurator: Configurator,
private val git: Git) {
private val gitRepo: Repository = git.repository

private fun loadGit(): Git? {
return try {
Git.open(File(localRepo.path))
} catch (e: IOException) {
Logger.error("Cannot access repository at path "
+ "$localRepo.path", e)
null
}
}

private fun closeGit() {
gitRepo.close()
git.close()
}

private fun calculateRepoRehashes() {
val initialCommit = getObservableCommits().blockingLast()
repo.initialCommitRehash = initialCommit.rehash
repo.rehash = RepoHelper.calculateRepoRehash(initialCommit.rehash,
localRepo)
}

private fun isKnownRepo(): Boolean {
return configurator.getRepos()
.find { it.rehash == repo.rehash } != null
}

private fun findFirstOverlappingCommit(): Commit? {
val serverHistoryCommits = repo.commits.toHashSet()
return getObservableCommits()
Expand Down Expand Up @@ -153,16 +125,6 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
}
}

private fun getRepoFromServer() {
repo = api.getRepo(repo.rehash)
Logger.debug("Received repo from server with ${repo.commits.size} " +
"commits")
}

private fun postRepoToServer() {
api.postRepo(repo)
}

private fun postCommitsToServer(commits: List<Commit>) {
if (commits.isNotEmpty()) {
api.postCommits(commits)
Expand Down Expand Up @@ -213,32 +175,15 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api,
}

fun update() {
if (!RepoHelper.isValidRepo(localRepo.path)) {
Logger.error("Invalid repo $localRepo")
return
}

println("Hashing $localRepo...")
localRepo.parseGitConfig(gitRepo.config)
repo.userEmail = localRepo.author.email
calculateRepoRehashes()

if (isKnownRepo()) {
getRepoFromServer()

// Delete missing commits. If found at least one common commit
// then next commits are not deleted because hash of a commit
// calculated including hashes of its parents.
val firstOverlapCommit = findFirstOverlappingCommit()
val deletedCommits = repo.commits
.takeWhile { it.rehash != firstOverlapCommit?.rehash }
deleteCommitsOnServer(deletedCommits)
}

// Delete locally missing commits from server. If found at least one
// common commit then next commits are not deleted because hash of a
// commit calculated including hashes of its parents.
val firstOverlapCommit = findFirstOverlappingCommit()
val deletedCommits = repo.commits
.takeWhile { it.rehash != firstOverlapCommit?.rehash }
deleteCommitsOnServer(deletedCommits)

// Hash added and missing server commits and send them to server.
hashAndSendCommits()
postRepoToServer()

println("Hashing $localRepo successfully finished.")
closeGit()
}
}
Loading

AltStyle によって変換されたページ (->オリジナル) /