Skip to content

Commit

Permalink
Merge pull request #40
Browse files Browse the repository at this point in the history
Handle multiple `scan paths`
  • Loading branch information
jayasuryat authored Oct 11, 2023
2 parents 0009acc + 61e4021 commit 1a27ecc
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 39 deletions.
18 changes: 10 additions & 8 deletions docs/howto/Cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

<a href="https://github.com/jayasuryat/mendable/releases/download/v0.6.0/mendable-app.jar"><img alt="Download Mendable" src="https://img.shields.io/badge/Mendable.jar-0.6.0-%2306090E?style=for-the-badge&logo=jetpackcompose"/></a>


It is very straightforward. Download and execute the `jar` file while **pointing it to the directory** which
contains all the Compose-compiler generated metrics files.

Expand All @@ -21,8 +20,10 @@ and `generate` a beautiful `report` for you.

### ✨ Generate report with a single command ✨

[Download](https://github.com/jayasuryat/mendable/releases/download/v0.6.0/mendable-app.jar) and place the `jar` file in the
same folder which contains all the generated Compose compiler metrics (should be `YourProject/build/compose_metrics`). And then execute the `jar` file with the following `command`.
[Download](https://github.com/jayasuryat/mendable/releases/download/v0.6.0/mendable-app.jar) and place the `jar` file in
the
same folder which contains all the generated Compose compiler metrics (should be `YourProject/build/compose_metrics`).
And then execute the `jar` file with the following `command`.

```
java -jar mendable-app.jar
Expand All @@ -34,12 +35,13 @@ combined metrics of all the modules.
---

### ✨Configuration ✨

While the above method is the easiest, and should work fine for most of the use cases, `Mendable` also supports some
configuration. The following are the supported options via `CLI arguments`.

```
java -jar mendable.jar
--composablesReportsPath, -i [Default value : <Current working dir>] -> Path to the directory containing all of the composables.txt files
--scanPaths, -i [Default value : <Current working dir>] -> Paths to the directories containing the composables.txt files (for multiple paths use this format "path1 path2")
--scanRecursively, -sr [Default value : false] -> Weather to scan the directory recursively or not
--outputPath, -o [Default value : <Current working dir>] -> Report output directory
--outputName, -oName [Default value : "index"] -> Name of the output file
Expand All @@ -53,16 +55,16 @@ For example :
```
java -jar mendable.jar
--scanRecursively \
-i /Users/username/Desktop/Your-project/build/compose_metrics \
-i "/Users/username/Desktop/Your-project/build/compose_metrics /Users/username/Desktop/Other-project/build/compose_metrics" \
-o /Users/username/Desktop/Reports \
-oName Your-project-metrics \
-eType html \
-rType all \
```

For the above command, files will be `read` from `/Users/username/Desktop/Your-project/build/compose_metrics` by recurisvely
going through every directory in this directory and the `output` file will be `saved` at
`/Users/username/Desktop/Reports/Your-project-metrics.html`.
For the above command, files will be `read` from `/Users/username/Desktop/Your-project/build/compose_metrics`
and `/Users/username/Desktop/Other-project/build/compose_metrics` by recurisvely going through every directory in these
directories and the `output` file will be `saved` at `/Users/username/Desktop/Reports/Your-project-metrics.html`.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.jayasuryat.mendable.app.system.SystemExit
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.default
import kotlinx.cli.delimiter
import java.io.File
import java.nio.file.Paths
import kotlin.io.path.absolutePathString
Expand All @@ -46,13 +47,14 @@ internal class CliArguments(

private val parser = ArgParser("Mendable")

/** The path to the directory containing all the composables.txt files. */
val composablesReportsPath: String by parser.option(
/** Paths to the directories containing the composables.txt files. */
val scanPaths: List<String> by parser.option(
type = ArgType.String,
fullName = "composablesReportsPath",
fullName = "scanPaths",
shortName = "i",
description = "Path to the directory containing all of the composables.txt files",
).default(defaultReadPath)
description = "Paths to the directories containing the composables.txt files (for multiple paths use \"path1 path2\" format)",
).delimiter(" ")
.default(listOf(defaultReadPath))

/** Indicates whether to scan the directory recursively. */
val scanRecursively: Boolean by parser.option(
Expand Down Expand Up @@ -105,14 +107,19 @@ internal class CliArguments(
return "$paramName cannot be empty. Either pass an appropriate value or skip passing a value to conform to the default value."
}

if (composablesReportsPath.isBlank()) printErrorAndExit(message("--composablesReportsPath or -i"))
if (scanPaths.isEmpty()) printErrorAndExit(message("--scanPaths or -i"))
val areAllPathsEmpty = scanPaths.all { scanPath -> scanPath.isBlank() }
if (areAllPathsEmpty) printErrorAndExit(message("--scanPaths or -i"))

scanPaths.forEach { scanPath ->
val input = File(scanPath)
if (!input.exists()) printErrorAndExit("Directory $scanPath does not exist")
if (!input.isDirectory) printErrorAndExit("$scanPath is not a directory")
}

if (outputPath.isBlank()) printErrorAndExit(message("--outputPath or -o"))
if (outputFileName.isBlank()) printErrorAndExit(message("--outputFileName or -oName"))

val input = File(composablesReportsPath)
if (!input.exists()) printErrorAndExit("Directory $input does not exist")
if (!input.isDirectory) printErrorAndExit("$input is not a directory")

val output = File(outputPath)
if (!output.exists()) printErrorAndExit("Directory $output does not exist")
if (!output.isDirectory) printErrorAndExit("$output is not a directory")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public fun main(args: Array<String>) {

// Transform arguments into a request for generating the report
val request = MendableReportGeneratorRequest(
scanPath = arguments.composablesReportsPath,
scanPaths = arguments.scanPaths,
scanRecursively = arguments.scanRecursively,
outputPath = arguments.outputPath,
outputFileName = arguments.outputFileName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.jayasuryat.mendable.app

import com.jayasuryat.mendable.MendableReportGenerator.Progress
import com.jayasuryat.mendable.MendableReportGeneratorRequest
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter

Expand Down Expand Up @@ -53,7 +54,21 @@ internal class ProgressPrinter(

@Suppress("UnusedReceiverParameter")
private fun Progress.Initiated.message(): String {
return "Scanning files ${if (request.scanRecursively) "recursively " else ""}in file://${request.scanPath} directory\n"

val message = StringBuilder("Scanning files ${if (request.scanRecursively) "recursively " else ""}")

if (request.scanPaths.size == 1) {
message.append("in file:${File.separator}${File.separator}${request.scanPaths.first()} directory\n")
} else {
message.append("in the following directories:\n")
val padStart = request.scanPaths.size.toString().length
request.scanPaths.forEachIndexed { index, scanPath ->
val modIndex = (index + 1).toString().padStart(padStart)
message.append("$modIndex. $scanPath \n")
}
}

return message.toString()
}

private fun Progress.MetricsFilesFound.message(): String {
Expand Down Expand Up @@ -90,14 +105,14 @@ internal class ProgressPrinter(
@Suppress("UnusedReceiverParameter")
private fun Progress.NoMetricsFilesFound.message(): String {
return """
No composables.txt files found in the directory : ${request.scanPath}
Make sure to point the application to the directory which contains all the composables.txt files via the '--composablesReportsPath' or '--i' argument.
No composables.txt files found in the following directories : ${request.scanPaths.joinToString()}
Make sure to point the application to the directory which contains all the composables.txt files via the '--scanPaths' or '--i' argument.
For more help execute the jar with '-h' argument
""".trimIndent()
}

private fun Progress.SuccessfullyCompleted.message(): String {
return "$exportType report successfully saved at file://$outputPath"
return "$exportType report successfully saved at file:${File.separator}${File.separator}$outputPath"
}

private fun Progress.Error.message(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.jayasuryat.mendable.app.FakeSystemExit.FakeSystemExitException
import com.jayasuryat.mendable.app.system.SystemExit
import io.kotest.assertions.throwables.shouldNotThrow
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.shouldBe
import org.junit.After
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -60,7 +61,7 @@ internal class CliArgumentsTest {
@Test
fun `should throw error for empty scan path`() {

val args = arrayOf("--composablesReportsPath", "")
val args = arrayOf("--scanPaths", "")

shouldThrow<FakeSystemExitException> {

Expand All @@ -71,6 +72,38 @@ internal class CliArgumentsTest {
}
}

@Test
fun `should parse single scan path correctly`() {

val file = temporaryFolder.newFolder()
val args = arrayOf("--scanPaths", file.path)

val parsed = CliArguments(
args = args,
systemExit = systemExit,
)

parsed.scanPaths.size shouldBe 1
parsed.scanPaths.first() shouldBe file.path
}

@Test
fun `should parse multiple scan paths correctly`() {

val file1 = temporaryFolder.newFolder()
val file2 = temporaryFolder.newFolder()
val args = arrayOf("--scanPaths", "${file1.path} ${file2.path}")

val parsed = CliArguments(
args = args,
systemExit = systemExit,
)

parsed.scanPaths.size shouldBe 2
parsed.scanPaths[0] shouldBe file1.path
parsed.scanPaths[1] shouldBe file2.path
}

@Test
fun `should throw error for empty output path`() {

Expand Down
2 changes: 2 additions & 0 deletions mendable/api/mendable.api
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ public final class com/jayasuryat/mendable/MendableReportGenerator$Progress$Succ

public final class com/jayasuryat/mendable/MendableReportGeneratorRequest {
public fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$ExportType;Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$IncludeModules;)V
public fun <init> (Ljava/util/List;Ljava/lang/String;ZLjava/lang/String;Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$ExportType;Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$IncludeModules;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getExportType ()Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$ExportType;
public final fun getIncludeModules ()Lcom/jayasuryat/mendable/MendableReportGeneratorRequest$IncludeModules;
public final fun getOutputFileName ()Ljava/lang/String;
public final fun getOutputPath ()Ljava/lang/String;
public final fun getScanPath ()Ljava/lang/String;
public final fun getScanPaths ()Ljava/util/List;
public final fun getScanRecursively ()Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ import com.jayasuryat.mendable.parser.model.ComposableSignaturesReport
import com.jayasuryat.mendable.parser.model.ComposableSignaturesReport.ComposableDetails
import com.jayasuryat.mendable.scanner.scanForComposableSignaturesReportFiles
import dev.drewhamilton.poko.Poko
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.*
import java.io.File
import java.nio.file.Paths
import kotlin.io.path.absolutePathString
Expand Down Expand Up @@ -88,10 +85,14 @@ public class MendableReportGenerator(
progress(Progress.Initiated)

val metricsFiles: List<ComposableSignaturesReportFile> = withContext(ioDispatcher) {
scanForComposableSignaturesReportFiles(
directory = File(request.scanPath),
scanRecursively = request.scanRecursively,
)
request.scanPaths.map { scanPath ->
async {
scanForComposableSignaturesReportFiles(
directory = File(scanPath),
scanRecursively = request.scanRecursively,
)
}
}.awaitAll().flatten()
}

if (metricsFiles.isEmpty()) {
Expand Down Expand Up @@ -137,10 +138,12 @@ public class MendableReportGenerator(

private fun MendableReportGeneratorRequest.validate() {

require(scanPath.isNotEmpty()) { "scanPath cannot be empty" }
val input = File(scanPath)
require(input.exists()) { "$scanPath does not exist" }
require(input.isDirectory) { "$scanPath is not a directory" }
scanPaths.forEach { scanPath ->
require(scanPath.isNotEmpty()) { "scanPath cannot be empty" }
val input = File(scanPath)
require(input.exists()) { "$scanPath does not exist" }
require(input.isDirectory) { "$scanPath is not a directory" }
}

require(outputPath.isNotEmpty()) { "outputPath cannot be empty" }
val output = File(outputPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import dev.drewhamilton.poko.Poko
*
* This class encapsulates the parameters required for generating a mendable report.
*
* @property scanPath The path to the directory where metrics files will be scanned.
* @property scanPaths Paths to the directories where metrics files will be scanned from.
* @property outputPath The output path where the generated report will be saved.
* @property scanRecursively Whether to scan for metrics files recursively within the directory.
* @property outputFileName The name of the generated report file.
Expand All @@ -31,14 +31,46 @@ import dev.drewhamilton.poko.Poko
*/
@Poko
public class MendableReportGeneratorRequest(
public val scanPath: String,
public val scanPaths: List<String>,
public val outputPath: String,
public val scanRecursively: Boolean,
public val outputFileName: String,
public val exportType: ExportType,
public val includeModules: IncludeModules,
) {

@Deprecated(
message = "Property scanPath is deprecated and will be removed soon. Use scanPaths instead.",
level = DeprecationLevel.WARNING,
replaceWith = ReplaceWith(
expression = "scanPaths[0]",
)
)
public val scanPath: String by lazy(LazyThreadSafetyMode.NONE) { scanPaths.first() }

@Deprecated(
message = "Use the primary constructor with multiple scanPaths arg, this constructor will be removed soon.",
level = DeprecationLevel.WARNING,
replaceWith = ReplaceWith(
expression = "MendableReportGeneratorRequest(listOf(scanPath), outputPath, scanRecursively, outputFileName, exportType, includeModules)",
)
)
public constructor(
scanPath: String,
outputPath: String,
scanRecursively: Boolean,
outputFileName: String,
exportType: ExportType,
includeModules: IncludeModules,
) : this(
scanPaths = listOf(scanPath),
outputPath = outputPath,
scanRecursively = scanRecursively,
outputFileName = outputFileName,
exportType = exportType,
includeModules = includeModules
)

/** Represents the type of export for the mendable report. */
public enum class ExportType {

Expand Down
Loading

0 comments on commit 1a27ecc

Please sign in to comment.