Skip to content
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

fix/3327/fix-parser-suggestions-slow #3329

Merged
merged 8 commits into from
Jun 7, 2023
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/)

- Add metric tooltips that display attribute descriptors and provide hyperlinks in the sidebar to the metric's documentation [#3273](https://github.com/MaibornWolff/codecharta/pull/3273) </br>
<img src="https://user-images.githubusercontent.com/65733509/241383211-d9e8e54b-6b06-45bb-8b99-81cc8e0a4596.png" width="450px"/> <img src="https://github.com/MaibornWolff/codecharta/assets/65733509/0ade9ad4-e60b-4911-aadc-d8142167b21a" width="300px"/>
- Add helpful status messages when calculating parser suggestions [#3329](https://github.com/MaibornWolff/codecharta/pull/3329)

### Fixed 🐞

- Speed up parser suggestions significantly [#3329](https://github.com/MaibornWolff/codecharta/pull/3329)

## [1.117.0] - 2023-05-19

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,10 @@ class GitLogParser(

override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
return ResourceSearchHelper.isResourcePresent(resourceToBeParsed, ".git",
ResourceSearchHelper::doesStringEndWith, 1,
shouldSearchFullDirectory = false, resourceShouldBeFile = false)
println("Checking if GitLogParser is applicable...")
return ResourceSearchHelper.isResourceFulfillingSearchOperatorPresent(resourceToBeParsed, listOf(".git"),
ResourceSearchHelper::doesStringEndWith,
shouldOnlySearchCurrentDirectory = true, resourceShouldBeFile = false)
}
override fun getName(): String {
return InteractiveParserHelper.GitLogParserConstants.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,11 @@ class MetricGardenerImporter(
override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
val supportedLanguageFileEndings = getSupportedLanguageFileEndings()
println("Checking if MetricGardener is applicable...")

for (supportedLanguageFileEnding in supportedLanguageFileEndings) {
if (ResourceSearchHelper.isResourcePresent(resourceToBeParsed, supportedLanguageFileEnding,
ResourceSearchHelper::doesStringEndWith, 0,
shouldSearchFullDirectory = true, resourceShouldBeFile = true)) {
return true
}
}

return false
return ResourceSearchHelper.isResourceFulfillingSearchOperatorPresent(resourceToBeParsed, supportedLanguageFileEndings,
ResourceSearchHelper::doesStringEndWith,
shouldOnlySearchCurrentDirectory = false, resourceShouldBeFile = true)
}

override fun getName(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,11 @@ class SVNLogParser(

override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
return ResourceSearchHelper.isResourcePresent(resourceToBeParsed, ".svn",
ResourceSearchHelper::doStringsEqual, 1,
shouldSearchFullDirectory = false, resourceShouldBeFile = false)
println("Checking if SVNLogParser is applicable...")

return ResourceSearchHelper.isResourceFulfillingSearchOperatorPresent(resourceToBeParsed, listOf(".svn"),
ResourceSearchHelper::doStringsEqual,
shouldOnlySearchCurrentDirectory = true, resourceShouldBeFile = false)
}

override fun getName(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,17 @@ class SonarImporterMain(

override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
println("Checking if SonarImporter is applicable...")

val trimmedInput = resourceToBeParsed.trim()

if (trimmedInput.contains("^http(s)?://".toRegex())) {
return true
}

return ResourceSearchHelper.isResourcePresent(trimmedInput, "sonar-project.properties",
ResourceSearchHelper::doStringsEqual, 0,
shouldSearchFullDirectory = true, resourceShouldBeFile = true)
return ResourceSearchHelper.isResourceFulfillingSearchOperatorPresent(trimmedInput, listOf("sonar-project.properties"),
ResourceSearchHelper::doStringsEqual,
shouldOnlySearchCurrentDirectory = true, resourceShouldBeFile = true)
}

override fun getName(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ class SonarImporterMainTest {
fun provideValidInputFiles(): List<Arguments> {
return listOf(
Arguments.of("src/test/resources/my/sonar/repo"),
Arguments.of("src/test/resources/my/sonar/repo/sonar-project.properties"),
Arguments.of("src/test/resources/my/sonar"),
Arguments.of(""))
Arguments.of("src/test/resources/my/sonar/repo/sonar-project.properties"))
}

@JvmStatic
fun provideInvalidInputFiles(): List<Arguments> {
return listOf(
Arguments.of("src/test/resources/my/nonsonar/repo"),
Arguments.of("src/test/resources/this/does/not/exist"))
Arguments.of("src/test/resources/this/does/not/exist"),
Arguments.of("src/test/resources/my/sonar"),
Arguments.of(""))
}

@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,11 @@ class SourceCodeParserMain(

override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
return ResourceSearchHelper.isResourcePresent(resourceToBeParsed, ".java",
ResourceSearchHelper::doesStringEndWith, 0,
shouldSearchFullDirectory = true, resourceShouldBeFile = true)
println("Checking if SourceCodeParser is applicable...")

return ResourceSearchHelper.isResourceFulfillingSearchOperatorPresent(resourceToBeParsed, listOf(".java"),
ResourceSearchHelper::doesStringEndWith,
shouldOnlySearchCurrentDirectory = false, resourceShouldBeFile = true)
}

override fun getName(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,23 @@ import java.nio.file.Paths
class ResourceSearchHelper {

companion object {
fun isResourcePresent(resourceName: String, searchToken: String, searchOperator: (String, String) -> Boolean,
maxSearchingDepth: Int, shouldSearchFullDirectory: Boolean, resourceShouldBeFile: Boolean): Boolean {
val trimmedResourceName = resourceName.trim()
// To be able to generally search for the existence of files, do not check empty string here,
// otherwise the real check never gets executed.
if (searchOperator(trimmedResourceName, searchToken) && searchToken != "") {

/**
* Checks whether a resource contains one of the specified searchTokens. To check that, the given searchOperator is used.
*/
fun isResourceFulfillingSearchOperatorPresent(resource: String, searchToken: List<String>, searchOperator: (String, List<String>) -> Boolean,
shouldOnlySearchCurrentDirectory: Boolean, resourceShouldBeFile: Boolean): Boolean {
val trimmedResourceName = resource.trim()

// Check if given resource is directly the searched object
if (searchOperator(trimmedResourceName, searchToken)) {
return true
}

val searchFile = getFileFromResourceName(trimmedResourceName)
println("Did not find resource directly, scanning directory `${searchFile.absolutePath}` if applicable.")

return isResourcePresentInDirectory(searchFile, searchToken, searchOperator, maxSearchingDepth, shouldSearchFullDirectory, resourceShouldBeFile)
}

fun doesStringEndWith(toBeCheckedString: String, searchToken: String): Boolean {
return (toBeCheckedString.endsWith(searchToken))
}

fun doStringsEqual(string1: String, string2: String): Boolean {
return (string1 == string2)
return isResourcePresentInDirectory(searchFile, searchToken, searchOperator, shouldOnlySearchCurrentDirectory, resourceShouldBeFile)
}

private fun getFileFromResourceName(resourceName: String): File {
Expand All @@ -36,12 +33,12 @@ class ResourceSearchHelper {
}
}

private fun isResourcePresentInDirectory(searchFile: File, searchToken: String, searchOperator: (String, String) -> Boolean,
maxSearchingDepth: Int, shouldSearchFullDirectory: Boolean, resourceShouldBeFile: Boolean): Boolean {
private fun isResourcePresentInDirectory(searchFile: File, searchToken: List<String>, searchOperator: (String, List<String>) -> Boolean,
shouldOnlySearchCurrentDirectory: Boolean, resourceShouldBeFile: Boolean): Boolean {
var fileSearch = searchFile.walk()

if (!shouldSearchFullDirectory) {
fileSearch = fileSearch.maxDepth(maxSearchingDepth)
if (shouldOnlySearchCurrentDirectory) {
fileSearch = fileSearch.maxDepth(1)
}

return if (resourceShouldBeFile) {
Expand All @@ -57,5 +54,23 @@ class ResourceSearchHelper {
.any()
}
}

fun doesStringEndWith(toBeChecked: String, searchToken: List<String>): Boolean {
for (token in searchToken) {
if (toBeChecked.endsWith(token)) {
return true
}
}
return false
}

fun doStringsEqual(toBeChecked: String, searchToken: List<String>): Boolean {
for (token in searchToken) {
if (toBeChecked == token) {
return true
}
}
return false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package de.maibornwolff.codecharta.util

import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class ResourceSearchHelperTest {

@Test
fun `should return true if string equals one or more search tokens`() {
val resource = "toBeSearched.kt"
val searchToken = listOf("notToBeSearched1.kt", "toBeSearched.kt", "notToBeSearched2.kt")

val result = ResourceSearchHelper.doStringsEqual(resource, searchToken)

Assertions.assertThat(result).isTrue()
}

@Test
fun `should return false if no search token equals string`() {
val resource = "toBeSearched.kt"
val searchToken = listOf("notToBeSearched1.kt", "notToBeSearched2.kt", "notToBeSearched3.kt")

val result = ResourceSearchHelper.doStringsEqual(resource, searchToken)

Assertions.assertThat(result).isFalse()
}

@Test
fun `should return true if string ends with one or more of the search tokens`() {
val resource = "toBeSearched.kt"
val searchToken = listOf(".html", ".kt", ".js")

val result = ResourceSearchHelper.doesStringEndWith(resource, searchToken)

Assertions.assertThat(result).isTrue()
}

@Test
fun `should return false if strings ends with none of the search tokens`() {
val resource = "toBeSearched.kt"
val searchToken = listOf(".html", ".css", ".js")

val result = ResourceSearchHelper.doesStringEndWith(resource, searchToken)

Assertions.assertThat(result).isFalse()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import de.maibornwolff.codecharta.serialization.ProjectSerializer
import de.maibornwolff.codecharta.tools.interactiveparser.InteractiveParser
import de.maibornwolff.codecharta.tools.interactiveparser.ParserDialogInterface
import de.maibornwolff.codecharta.tools.interactiveparser.util.InteractiveParserHelper
import de.maibornwolff.codecharta.util.ResourceSearchHelper
import picocli.CommandLine
import java.io.File
import java.io.IOException
Expand Down Expand Up @@ -118,9 +117,15 @@ class RawTextParser(

override fun getDialog(): ParserDialogInterface = ParserDialog
override fun isApplicable(resourceToBeParsed: String): Boolean {
return ResourceSearchHelper.isResourcePresent(resourceToBeParsed, "",
ResourceSearchHelper::doesStringEndWith, 0,
shouldSearchFullDirectory = true, resourceShouldBeFile = true)
println("Checking if RawTextParser is applicable...")

val searchFile = if (resourceToBeParsed != "") File(resourceToBeParsed) else File(Paths.get("").toAbsolutePath().toString())

val fileSearch = searchFile.walk()

return fileSearch.asSequence()
.filter { it.isFile }
.any()
}

override fun getName(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class InteractiveParserSuggestionDialog {

private fun selectToBeExecutedInteractiveParsers(applicableParsers: List<String>): List<String> {
val selectedParsers = KInquirer.promptCheckbox(
message = "Choose from this list of applicable parsers",
message = "Choose from this list of applicable parsers. You can select individual parsers by pressing spacebar.",
choices = applicableParsers)

if (selectedParsers.isEmpty()) {
Expand Down