diff --git a/src/main/kotlin/me/msoucy/gbat/Main.kt b/src/main/kotlin/me/msoucy/gbat/Main.kt index eb8e2ff..d643036 100644 --- a/src/main/kotlin/me/msoucy/gbat/Main.kt +++ b/src/main/kotlin/me/msoucy/gbat/Main.kt @@ -56,8 +56,8 @@ class GbatArgs(parser: ArgParser) { val not_interesting by parser.adding("--not-interesting", "-N", help="Regular expression to determine which files should not be included in calculations.") val case_sensitive by parser.flagging("Use case sensitive regexps when determining interesting files (default is case-insensitive)") - val departed by parser.storing("--departed-file", "-D", help="File listing departed devs, one per line").default(null) - val risk_file by parser.storing("--bus-risk-file", help="File of dev=float lines (e.g. ejorgensen=0.4) with custom bus risks for devs").default(null) + val departed by parser.storing("--departed-file", "-D", help="File listing departed devs, one per line", transform=::File).default(null) + val risk_file by parser.storing("--bus-risk-file", help="File of dev=float lines (e.g. ejorgensen=0.4) with custom bus risks for devs", transform=::File).default(null) val default_bus_risk by parser.storing("--default-bus-risk", help="Default risk that a dev will be hit by a bus in your analysis timeframe (defaults to 0.1).") { toDouble() }.default(0.1) // Multiprocessing options @@ -66,7 +66,7 @@ class GbatArgs(parser: ArgParser) { // Tuning options val risk_threshold by parser.storing("--risk-threshold", help="Threshold past which to summarize risk (defaults to default bus risk cubed)") { toDouble() }.default(null) - val creation_constant by parser.storing("--knowledge-creation-constant", help="How much knowledge a changed line should create if a new line creates 1 (defaults to 0.1)") {toDouble()}.default(null) + val creation_constant by parser.storing("--knowledge-creation-constant", help="How much knowledge a changed line should create if a new line creates 1 (defaults to 0.1)") { toDouble() }.default(null) // Misc options val git_exe by parser.storing("--git-exe", help="Path to the git executable", transform=::validateGit).default("git").addValidator { validateGit(value) } diff --git a/src/main/kotlin/me/msoucy/gbat/Models.kt b/src/main/kotlin/me/msoucy/gbat/Models.kt new file mode 100644 index 0000000..b25b28d --- /dev/null +++ b/src/main/kotlin/me/msoucy/gbat/Models.kt @@ -0,0 +1,85 @@ +package me.msoucy.gbat + +import java.io.File +import kotlin.io.forEachLine + +class RiskModel(val threshold : Double, + val default : Double, + val busRiskFile : File?, + val departedFile : File?) { + val departed = mutableSetOf() + val risks = mutableMapOf().withDefault {default} + + init { + parseBusRisks() + parseDeparted() + } + + operator fun get(author : String) : Double { + val name = author.trim() + if(name.isEmpty()) { + return threshold + } + return risks.getOrPut(name) { default } + } + + fun isDeparted(author : String) = author.trim() in departed + + fun jointBusProb(vararg authors : String) = + authors.map { this[it] }.reduce { a, b -> a * b } + + fun jointBusProbBelowThreshold(vararg authors : String) = + jointBusProb(*authors) <= threshold + + private fun parseBusRisks() { + busRiskFile?.forEachLine { line -> + val sline = line.trim() + if(sline.isNotEmpty()) { + val segments = sline.split("=") + val risk = segments.last() + val author = segments.dropLast(1).joinToString(separator="=") + risks[author] = risk.toDouble() + } + } + } + + private fun parseDeparted() { + departedFile?.forEachLine { line -> + val author = line.trim() + if(author.isNotEmpty()) { + risks[author] = 1.0 + departed.add(author) + } + } + } +} + +class LineModel() { + inner class Line(var num : Int, var text : String) + val model = mutableSetOf() + + fun add(line : Line) { + model.onEach { entry -> + if(entry.num >= line.num) { + entry.num++ + } + } + model.add(line) + } + + fun del(line : Line) { + model.removeIf { it.num == line.num } + model.onEach { entry -> + if(entry.num > line.num) { + entry.num-- + } + } + } + + fun change(line : Line) { + model.removeIf { it.num == line.num } + model.add(line) + } + + fun get() = model.sortedBy { it.num }.map { it.text } +} \ No newline at end of file