Checkpoint

This commit is contained in:
Matt Soucy 2020-07-03 17:50:47 -04:00
parent cabf35c16d
commit 2b4d799d4a
5 changed files with 166 additions and 83 deletions

View File

@ -1,5 +1,6 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version "$kotlinVersion" id 'org.jetbrains.kotlin.jvm' version "$kotlinVersion"
id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlinVersion"
id 'application' id 'application'
} }
@ -24,5 +25,6 @@ dependencies {
implementation "org.jetbrains.exposed:exposed-dao:$kotlin_exposed_version" implementation "org.jetbrains.exposed:exposed-dao:$kotlin_exposed_version"
implementation "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version" implementation "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version"
implementation "org.xerial:sqlite-jdbc:3.30.1" implementation "org.xerial:sqlite-jdbc:3.30.1"
implementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
} }

View File

@ -138,8 +138,9 @@ fun main(args: Array<String>) = mainBody {
val dbFname = File(outDir, "summary.db") val dbFname = File(outDir, "summary.db")
val summaryDb = Database.connect("jdbc:sqlite:${dbFname.absolutePath}", driver="org.sqlite.JDBC") val summaryDb = Database.connect("jdbc:sqlite:${dbFname.absolutePath}", driver="org.sqlite.JDBC")
transaction(summaryDb) { transaction(summaryDb) {
exec("PRAGMA journal_mode = OFF") addLogger(StdOutSqlLogger)
exec("PRAGMA synchronous = OFF") // exec("PRAGMA journal_mode = OFF")
// exec("PRAGMA synchronous = OFF")
} }
val summaryModel = SummaryModel(summaryDb) val summaryModel = SummaryModel(summaryDb)
@ -155,6 +156,8 @@ fun main(args: Array<String>) = mainBody {
} }
} }
renderSummary(projectRootFile, summaryModel, outDir)
// Render summary // Render summary
System.err.println("Done, summary is in ${outDir}/index.html") System.err.println("Done, summary is in ${outDir}/index.html")
} }

View File

@ -0,0 +1,56 @@
package me.msoucy.gbat
import java.io.File
import me.msoucy.gbat.models.ProjectTreeNode
import me.msoucy.gbat.models.ProjectTreeResult
import me.msoucy.gbat.models.Statistics
import me.msoucy.gbat.models.SummaryModel
import com.google.gson.GsonBuilder
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
val NUM_RISKIEST_AUTHORS = 10
val NUM_RISKIEST_FILES = 10
class SummaryRenderer(
val summaryModel : SummaryModel,
val outputDir : File
) {
private val filesDir = File(outputDir, "files")
private val gson = GsonBuilder().setPrettyPrinting().create()
fun renderAll(projectRoot : File) {
createFilesDir()
renderSummaryJson(projectRoot)
renderFileJson(projectRoot)
// renderSrc(projectRoot)
}
private fun renderSummaryJson(projectRoot : File) {
val summary = summaryModel.projectSummary(projectRoot.absolutePath)
val json = gson.toJson(summary)
File(filesDir, "summary.json").writeText(json)
}
private fun renderFileJson(projectRoot : File) {
summaryModel.projectFiles(projectRoot.absolutePath).forEach {
val json = gson.toJson(summaryModel.fileSummary(it.fileId))
File(filesDir, "${it.fileId}.json").writeText(json)
}
}
private fun createFilesDir() = filesDir.mkdirs()
}
fun renderSummary(
projectRoot : File,
summaryModel : SummaryModel,
outputDir : File
) {
transaction(summaryModel.db) {
val renderer = SummaryRenderer(summaryModel, outputDir)
renderer.renderAll(projectRoot)
}
}

View File

@ -237,7 +237,6 @@ class KnowledgeModel(val db : Database, val constant : Double, val riskModel : R
} }
private fun createTables() = transaction(db) { private fun createTables() = transaction(db) {
println ("-- In create tables")
SchemaUtils.dropDatabase() SchemaUtils.dropDatabase()
SchemaUtils.createMissingTablesAndColumns(AuthorsTable, KnowledgeAcctsTable, KnowledgeAuthorsTable, LineKnowledge) SchemaUtils.createMissingTablesAndColumns(AuthorsTable, KnowledgeAcctsTable, KnowledgeAuthorsTable, LineKnowledge)
AuthorsTable.insertIgnore { AuthorsTable.insertIgnore {

View File

@ -7,39 +7,37 @@ import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
class SummaryModel(val db : Database) { private object ProjectTable : IntIdTable("projects", "projectid") {
object ProjectTable : IntIdTable("projects", "projectid") {
val project = text("project").uniqueIndex("project_idx") val project = text("project").uniqueIndex("project_idx")
} }
object DirsTable : IntIdTable("dirs", "dirid") { private object DirsTable : IntIdTable("dirs", "dirid") {
val dir = text("dir") val dir = text("dir")
val parentdirid = integer("parentdirid").references(DirsTable.id) val parentdirid = integer("parentdirid").references(DirsTable.id)
val projectid = integer("projectid").references(ProjectTable.id) val projectid = integer("projectid").references(ProjectTable.id)
val dirsproj_idx = uniqueIndex("dirsproj_idx", dir, parentdirid, projectid) val dirsproj_idx = uniqueIndex("dirsproj_idx", dir, parentdirid, projectid)
} }
object FilesTable : IntIdTable("files", "fileid") { private object FilesTable : IntIdTable("files", "fileid") {
val fname = text("fname") val fname = text("fname")
val dirid = integer("dirid").index("filesdir_idx").references(DirsTable.id) val dirid = integer("dirid").index("filesdir_idx").references(DirsTable.id)
} }
object LinesTable : IntIdTable("lines", "lineid") { private object LinesTable : IntIdTable("lines", "lineid") {
val line = text("line") val line = text("line")
val fileid = integer("fileid").index("linesfile_idx").references(FilesTable.id) val fileid = integer("fileid").index("linesfile_idx").references(FilesTable.id)
val linenum = integer("linenum") val linenum = integer("linenum")
val linesnumfile_idx = uniqueIndex("linesnumfile_idx", fileid, linenum) val linesnumfile_idx = uniqueIndex("linesnumfile_idx", fileid, linenum)
} }
object AuthorsTable : IntIdTable("authors", "authorid") { private object AuthorsTable : IntIdTable("authors", "authorid") {
val author = text("author").uniqueIndex("authorstrs_idx") val author = text("author").uniqueIndex("authorstrs_idx")
} }
object AuthorsGroupsTable : IntIdTable("authorgroups", "authorgroupid") { private object AuthorsGroupsTable : IntIdTable("authorgroups", "authorgroupid") {
val authors = text("authorsstr").uniqueIndex("authorgroupsstrs_idx") val authors = text("authorsstr").uniqueIndex("authorgroupsstrs_idx")
} }
object AuthorsAuthorGroupsTable : Table("authors_authorgroups") { private object AuthorsAuthorGroupsTable : Table("authors_authorgroups") {
val authorid = integer("authorid").references(AuthorsTable.id) val authorid = integer("authorid").references(AuthorsTable.id)
val groupid = integer("authorgroupid").references(AuthorsGroupsTable.id) val groupid = integer("authorgroupid").references(AuthorsGroupsTable.id)
override val primaryKey = PrimaryKey(authorid, groupid) override val primaryKey = PrimaryKey(authorid, groupid)
} }
object AllocationsTable : IntIdTable("allocations", "allocationid") { private object AllocationsTable : IntIdTable("allocations", "allocationid") {
val knowledge = double("knowledge") val knowledge = double("knowledge")
val risk = double("risk") val risk = double("risk")
val orphaned = double("orphaned") val orphaned = double("orphaned")
@ -47,20 +45,6 @@ class SummaryModel(val db : Database) {
val authorgroupid = integer("authorgroupid").references(AuthorsGroupsTable.id) val authorgroupid = integer("authorgroupid").references(AuthorsGroupsTable.id)
} }
val GIT_BY_A_BUS_BELOW_THRESHOLD = "Git by a Bus Safe Author"
init {
createTables()
}
data class Statistics(var totKnowledge : Double = 0.0,
var totRisk : Double = 0.0,
var totOrphaned : Double = 0.0) {
constructor(row : ResultRow) :
this(row[AllocationsTable.knowledge.sum()] ?: 0.0,
row[AllocationsTable.risk.sum()] ?: 0.0,
row[AllocationsTable.orphaned.sum()] ?: 0.0) {}
}
class LineDict { class LineDict {
var stats = Statistics() var stats = Statistics()
var authorRisks = mutableMapOf<String, Statistics>() var authorRisks = mutableMapOf<String, Statistics>()
@ -71,7 +55,7 @@ class SummaryModel(val db : Database) {
var authorRisks = mutableMapOf<String, Statistics>() var authorRisks = mutableMapOf<String, Statistics>()
var lines = mutableListOf<LineDict>() var lines = mutableListOf<LineDict>()
} }
class FileEntry(var name : String) { class FileEntry(var name : String = "") {
var stats = Statistics() var stats = Statistics()
var authorRisks = mutableMapOf<String, Statistics>() var authorRisks = mutableMapOf<String, Statistics>()
} }
@ -80,6 +64,18 @@ class SummaryModel(val db : Database) {
var files = mutableMapOf<Int, FileEntry>() var files = mutableMapOf<Int, FileEntry>()
var dirs = mutableListOf<Int>() var dirs = mutableListOf<Int>()
} }
class ProjectFilesResult(var fileId : Int, var fname : Path)
data class Statistics(
var totKnowledge : Double = 0.0,
var totRisk : Double = 0.0,
var totOrphaned : Double = 0.0
) {
constructor(row : ResultRow) :
this(row[AllocationsTable.knowledge.sum()] ?: 0.0,
row[AllocationsTable.risk.sum()] ?: 0.0,
row[AllocationsTable.orphaned.sum()] ?: 0.0) {}
}
class ProjectTreeNode { class ProjectTreeNode {
var name = "root" var name = "root"
var files = mutableListOf<FileEntry>() var files = mutableListOf<FileEntry>()
@ -89,7 +85,14 @@ class SummaryModel(val db : Database) {
var stats = Statistics() var stats = Statistics()
var authorRisks = mutableMapOf<String, Statistics>() var authorRisks = mutableMapOf<String, Statistics>()
} }
class ProjectFilesResult(var fileId : Int, var fname : Path)
class SummaryModel(val db : Database) {
val GIT_BY_A_BUS_BELOW_THRESHOLD = "Git by a Bus Safe Author"
init {
createTables()
}
private val lineAllocations = (LinesTable leftJoin AllocationsTable) private val lineAllocations = (LinesTable leftJoin AllocationsTable)
private val lineAllocationGroups = (lineAllocations leftJoin AuthorsGroupsTable) private val lineAllocationGroups = (lineAllocations leftJoin AuthorsGroupsTable)
@ -204,7 +207,9 @@ class SummaryModel(val db : Database) {
entry.value.files[row[FilesTable.id].value] = FileEntry(row[FilesTable.fname]) entry.value.files[row[FilesTable.id].value] = FileEntry(row[FilesTable.fname])
} }
entry.value.files.entries.forEach { (fileId, fileEntry) -> entry.value.files.entries.forEach { (fileId, fileEntry) ->
lineAllocations.select { LinesTable.fileid eq fileId } lineAllocations
.slice(AllocationsTable.knowledge.sum(), AllocationsTable.risk.sum(), AllocationsTable.orphaned.sum())
.select { LinesTable.fileid eq fileId }
.groupBy(LinesTable.fileid) .groupBy(LinesTable.fileid)
.forEach { row -> .forEach { row ->
fileEntry.stats.totKnowledge = row[AllocationsTable.knowledge.sum()] ?: 0.0 fileEntry.stats.totKnowledge = row[AllocationsTable.knowledge.sum()] ?: 0.0
@ -213,7 +218,13 @@ class SummaryModel(val db : Database) {
} }
} }
entry.value.files.entries.forEach { (fileId, fileEntry) -> entry.value.files.entries.forEach { (fileId, fileEntry) ->
lineAllocationGroups.select { LinesTable.fileid eq fileId } lineAllocationGroups
.slice(
AllocationsTable.knowledge.sum(),
AllocationsTable.risk.sum(),
AllocationsTable.orphaned.sum(),
AuthorsGroupsTable.authors
).select { LinesTable.fileid eq fileId }
.groupBy(AllocationsTable.authorgroupid) .groupBy(AllocationsTable.authorgroupid)
.orderBy(AuthorsGroupsTable.authors) .orderBy(AuthorsGroupsTable.authors)
.forEach { row -> .forEach { row ->
@ -227,13 +238,25 @@ class SummaryModel(val db : Database) {
val root = transformedRoot.dirs.first() val root = transformedRoot.dirs.first()
val projectTree = ProjectTreeResult(project, root) val projectTree = ProjectTreeResult(project, root)
allJoined.select { DirsTable.projectid eq projectId } allJoined
.slice(
AllocationsTable.knowledge.sum(),
AllocationsTable.risk.sum(),
AllocationsTable.orphaned.sum(),
AuthorsGroupsTable.authors
)
.select { DirsTable.projectid eq projectId }
.groupBy(AuthorsGroupsTable.id) .groupBy(AuthorsGroupsTable.id)
.forEach { row -> .forEach { row ->
projectTree.authorRisks[row[AuthorsGroupsTable.authors]] = Statistics(row) projectTree.authorRisks[row[AuthorsGroupsTable.authors]] = Statistics(row)
} }
manyJoined.select { manyJoined
.slice(
AllocationsTable.knowledge.sum(),
AllocationsTable.risk.sum(),
AllocationsTable.orphaned.sum()
).select {
DirsTable.projectid eq projectId DirsTable.projectid eq projectId
}.first().let { row -> }.first().let { row ->
projectTree.stats = Statistics(row) projectTree.stats = Statistics(row)