Skip to content

Commit 324b829

Browse files
author
Daniil.Karol
committed
Fixed issues with progsnap converter
1 parent 66ca56c commit 324b829

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.jetbrains.research.tasktracker.progsnap2
2+
3+
import java.io.File
4+
5+
fun main(args: Array<String>) {
6+
val (trackedFilesDirectory, destinationDirectory) = gatherArguments(args)
7+
with(trackedFilesDirectory) {
8+
ProgsnapParser(
9+
TaskTrackerData(
10+
resolve(ACTIVITY_DATA_CSV),
11+
resolve(DOCUMENT_DATA_CSV),
12+
resolve(FILE_EDITOR_DATA_CSV),
13+
resolve(RESEARCHES_CSV),
14+
resolve(TOOL_WINDOW_DATA_CSV),
15+
ProgsnapMeta(
16+
PROGSNAP_VERSION,
17+
CodeStateRepresentation.DIRECTORY,
18+
EventOrderScope.GLOBAL,
19+
true,
20+
"SubjectID"
21+
)
22+
)
23+
).convert(destinationDirectory)
24+
}
25+
}
26+
27+
private fun gatherArguments(args: Array<String>): Pair<File, File> {
28+
require(args.size == 2) { "Exactly 2 arguments are required: <csvFolder> <existingFolder>." }
29+
30+
val csvFolder = File(args[0])
31+
require(csvFolder.isDirectory) { "The first argument must be a directory containing CSV files." }
32+
val missingFiles = expectedCsvFiles.filter { !File(csvFolder, it).exists() }
33+
require(missingFiles.isEmpty()) {
34+
"The following required CSV files are missing: ${missingFiles.joinToString(", ")}"
35+
}
36+
37+
val existingDirectory = File(args[1])
38+
require(existingDirectory.isDirectory) { "The destination directory argument must be an existing directory." }
39+
40+
return Pair(csvFolder, existingDirectory)
41+
}
42+
43+
private const val ACTIVITY_DATA_CSV = "activitydata.csv"
44+
private const val DOCUMENT_DATA_CSV = "documentdata.csv"
45+
private const val FILE_EDITOR_DATA_CSV = "fileeditordata.csv"
46+
private const val RESEARCHES_CSV = "researches.csv"
47+
private const val TOOL_WINDOW_DATA_CSV = "toolwindowdata.csv"
48+
49+
private val expectedCsvFiles = listOf(
50+
ACTIVITY_DATA_CSV,
51+
DOCUMENT_DATA_CSV,
52+
FILE_EDITOR_DATA_CSV,
53+
RESEARCHES_CSV,
54+
TOOL_WINDOW_DATA_CSV
55+
)
56+
57+
private const val PROGSNAP_VERSION = 5

processing/src/main/kotlin/org/jetbrains/research/tasktracker/progsnap2/ProgsnapParser.kt

+20-6
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ import org.jetbrains.kotlinx.dataframe.io.writeCSV
99
import java.io.File
1010
import java.time.OffsetDateTime
1111
import java.time.format.DateTimeFormatter
12+
import java.time.format.DateTimeParseException
1213
import kotlin.io.path.createDirectories
1314
import kotlin.io.path.exists
1415

16+
@Suppress("TooManyFunctions")
1517
class ProgsnapParser(private val taskTrackerData: TaskTrackerData) {
1618

1719
companion object {
18-
private val DATE_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS XXX")
20+
private val DATE_FORMAT_WITH_MICROS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSXXX")
21+
private val DATE_WITHOUT_MICROS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssXXX")
22+
private val DATE_FORMATS = listOf(DATE_FORMAT_WITH_MICROS, DATE_WITHOUT_MICROS)
1923
private val DIRECTORIES_DELIMITERS = arrayOf("/", "\\")
2024
private const val CODE_STATES_DIRECTORY_NAME = "CodeStates"
2125
private const val MAIN_TABLE_FILENAME = "MainTable.csv"
@@ -29,6 +33,17 @@ class ProgsnapParser(private val taskTrackerData: TaskTrackerData) {
2933
createMainTableFile(destinationDirectory, researchGroups)
3034
}
3135

36+
private fun parseDate(dateString: String): OffsetDateTime {
37+
for (formatter in DATE_FORMATS) {
38+
try {
39+
return OffsetDateTime.parse(dateString, formatter)
40+
} catch (_: DateTimeParseException) {
41+
// Ignore and try the next format
42+
}
43+
}
44+
error("Invalid date format: $dateString")
45+
}
46+
3247
private fun createMetaFile(destinationDirectory: File) {
3348
val metaDataFile = destinationDirectory.resolve(META_DATA_FILENAME)
3449
taskTrackerData.metaData.toDataFrame().writeCSV(metaDataFile)
@@ -63,13 +78,9 @@ class ProgsnapParser(private val taskTrackerData: TaskTrackerData) {
6378
private var researches =
6479
taskTrackerData.researches.toDataFrame()
6580
.convert("id").to<Int>()
66-
private var surveyData =
67-
taskTrackerData.surveyData.toDataFrame()
6881
private var toolWindowData =
6982
taskTrackerData.toolWindowData.toDataFrame()
7083
.add("data_type") { "toolWindowData" }
71-
private var users =
72-
taskTrackerData.users.toDataFrame()
7384

7485
private fun File.toDataFrame() = DataFrame.readCSV(this)
7586

@@ -78,7 +89,7 @@ class ProgsnapParser(private val taskTrackerData: TaskTrackerData) {
7889
private fun DataFrame<*>.convertDate() = this
7990
.dropNA("date")
8091
.update("date")
81-
.with { OffsetDateTime.parse(it.toString(), DATE_FORMAT).toString() }
92+
.with { parseDate(it.toString()).toString() }
8293
.convert("research_id").to<Int>()
8394
.fullJoin(researches) { "research_id" match "id" }
8495
.dropNA("date")
@@ -159,6 +170,9 @@ class ProgsnapParser(private val taskTrackerData: TaskTrackerData) {
159170
"KeyPressed" -> "X-KeyPressed"
160171
"KeyReleased" -> "X-KeyReleased"
161172
"Action" -> "X-Action"
173+
"MouseClicked" -> "X-MouseClicked"
174+
"MouseMoved" -> "X-MouseMoved"
175+
"MouseWheel" -> "X-MouseWheel"
162176
else -> error("Undefined activity data type has been detected in the data `$type`")
163177
}
164178
}

processing/src/main/kotlin/org/jetbrains/research/tasktracker/progsnap2/TaskTrackerData.kt

-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ data class TaskTrackerData(
99
val documentData: File,
1010
val fileEditorData: File,
1111
val researches: File,
12-
val surveyData: File,
1312
val toolWindowData: File,
14-
val users: File,
1513
val metaData: ProgsnapMeta
1614
)
1715

0 commit comments

Comments
 (0)