Skip to content
This repository has been archived by the owner on Jul 2, 2021. It is now read-only.

Commit

Permalink
Redesign commandline arguments to be easier to use
Browse files Browse the repository at this point in the history
Remove whitespace after the end of a comment
Update README
Upgrade Kotlin version to 1.4.10
Upgrade dependency versions
  • Loading branch information
ze committed Nov 6, 2020
1 parent 256c90d commit 0fece35
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 152 deletions.
16 changes: 16 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 26 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,48 @@
# V2 Format
A program formatter for Victoria 2
A program formatter for Victoria 2.

## Usage
Download `v2format.jar` from the latest release in the release tab.
Download `v2format.jar` from the latest release in the releases section.

A default configuration is provided as well.
It's recommended that formatting is only done in repositories in the chance that a reversion is desired.
It's recommended that formatting is only done in repositories to control reversions.

```
$ java -jar v2format.jar
$ java -jar v2format.jar --help
$ java -jar v2format.jar --config path/to/config
$ java -jar v2format.jar --folder path/to/mod
$ java -jar v2format.jar --file path/to/file
$ java -jar v2format.jar --mod path/to/mod
$ java -jar v2format.jar --file path/to/file --config path/to/config
$ java -jar v2format.jar --mod path/to/mod --file path/to/mod/file
$ java -jar v2format.jar --folder path/to/mod --file path/to/file
$ java -jar v2format.jar --config path/to/config
$ java -jar v2format.jar --folder path/to/mod --config path/to/config
$ java -jar v2format.jar --mod path/to/mod --config path/to/config
$ java -jar v2format.jar --folder path/to/mod --file path/to/file --config path/to/config
$ java -jar v2format.jar --mod path/to/mod --file path/to/mod/file --config path/to/config
```

### `--folder`
### `--mod`

The `--mod` argument specifies the directory to format, bypassing `.mod` file reading.
The program searches for a single `.mod` file in the current directory, acquiring the mod directory from it.

The `--folder` argument is by default the directory from which `v2format.jar` was executed,
also known as the current directory.
The program will then search for a single `.mod` file and open up the mod based off the file results.
If no `.mod` file is found or multiple are found, the program exits.
In those cases, `--folder` should be used.
If there is no `.mod` file or multiple exist, the program exits due to not knowing which mod to format.
In those cases, `--mod` should be used to specify which mod should be formatted.

### `--file`

The `--file` argument is an optional argument and has no default value.
If the argument is provided, the program will still search for a `.mod` file and configuration in the same directory.
The `--folder` argument still applies to defining the mod and configuration.
If no `.mod` file is found, the program exits.
If the file passed in as an argument cannot be formatted by way of its extension or exclusion configuration, the program will exit.
The `--mod` argument must be provided in order to use configurations.
It allows either files or directories to be formatted specifically without the rest of the mod being formatted with it.

If the file passed in as an argument cannot be formatted by way of its
extension, exclusion configuration, or read/write property, the program will exit.

Note that it is possible to use the `--folder` argument to indicate the mod to format while passing in an argument
Note: it is possible to use the `--mod` argument to indicate the mod to format while passing in an argument
to `--file` that is in a different directory.
It is important to know that excluding files is based off the relative path from the specified mod directory and not some pattern.
Excluding files is relative to the mod directory path, and not absolute.

### `--config`

Expand Down Expand Up @@ -77,18 +74,18 @@ Without any external configuration, the style used is:

#### Terminology

An `expression` is either an assignment or a braced expression.
An `expression` is either an assignment, or a braced expression.

An `assignment` looks can look like either `key = value` or `key = { ...values }`.

A `braced expression` is the latter form of an assignment.
It can also be the `{ ... values }` part of `key = { { ...values } }`,
however this use case is noticeably only used in `map/positions.txt` and can be ignored.
however this use case only has usage in `map/positions.txt` and can be ignored.

A string is a quoted section of text that looks like `"text"`.

An identifier is a unquoted contiguous piece of text that can look like `identifier`.
It can contain digits in it, but cannot be completely composed of digits, otherwise it would be a number.
It can contain digits in it, but cannot be solely composed of digits, otherwise it would be a number.

#### Keys

Expand Down Expand Up @@ -253,8 +250,8 @@ To override it, a negating entry must be put into `/map`.

---

If there are two identical keys defined for one path, the last defined entry is what is chosen.
However, the ordering of paths won't otherwise matter.
If there are two identical keys defined for one path, the latest defined entry is chosen.
The ordering of paths won't otherwise matter.

```json
{
Expand Down
13 changes: 5 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
kotlin("jvm") version "1.3.72"
kotlin("plugin.serialization") version "1.3.70"
kotlin("jvm") version "1.4.10"
kotlin("plugin.serialization") version "1.4.10"
antlr
idea
}
Expand All @@ -17,7 +17,6 @@ version = "1.0"

repositories {
mavenCentral()
jcenter()
}

val genDir = file("${project.buildDir}/generated-src/antlr/main/v2/format/antlr")
Expand All @@ -37,17 +36,15 @@ sourceSets {
}

dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlinxSerializationVersion")

implementation("com.github.ajalt:clikt:$cliktVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion")
implementation("com.github.ajalt.clikt:clikt:$cliktVersion")

antlr("org.antlr:antlr4:$antlrVersion")

testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
testImplementation("io.mockk:mockk:$mockkVersion")
testImplementation("org.jetbrains.kotlin:kotlin-reflect:1.3.72")
testImplementation("org.jetbrains.kotlin:kotlin-reflect:1.4.10")
}

configure<JavaPluginConvention> {
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
kotlin.code.style=official
kotlinxSerializationVersion=0.20.0
cliktVersion=2.7.1
commonsTextVersion=1.8
kotlinxSerializationVersion=1.0.1
cliktVersion=3.0.1
commonsTextVersion=1.9
antlrVersion=4.8
junitVersion=5.6.2
mockkVersion=1.10.0
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
4 changes: 2 additions & 2 deletions src/main/kotlin/v2/format/FileFormatter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import v2.format.config.FormatOptions
import java.io.File
import java.nio.charset.Charset

class FileFormatter(private val modFolder: File) {
class FileFormatter(private val modRootFolder: File) {
private val charset = Charset.forName("cp1252")

fun formatFile(file: File) {
try {
val relativeFile = file.relativeTo(modFolder)
val relativeFile = file.relativeTo(modRootFolder)
val options = Config[relativeFile.path]

val formattedProgram = formatProgram(file, options)
Expand Down
100 changes: 58 additions & 42 deletions src/main/kotlin/v2/format/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,41 @@ package v2.format
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.output.CliktHelpFormatter
import com.github.ajalt.clikt.parameters.groups.OptionGroup
import com.github.ajalt.clikt.parameters.groups.cooccurring
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.file
import v2.format.config.CONFIG_DEFAULT_NAME
import v2.format.config.Config
import java.io.File

class FormatOptions : OptionGroup() {
val modFile by option("--mod", help = "Specifies the mod folder to format").file(
mustExist = true,
canBeFile = false,
canBeDir = true,
mustBeReadable = true
).required()

val file by option("--file", help = "Specifies the file or folder to format").file(
mustExist = true,
mustBeReadable = true,
mustBeWritable = true
)
}

class Main : CliktCommand(help = "A program formatter for Victoria 2 mods.") {
private val folder by option(help = "Specifies the mod directory, otherwise it attempts to find the mod in the current directory")
.file(
mustExist = true,
canBeFile = false,
canBeDir = true,
mustBeReadable = true,
mustBeWritable = true
)

private val file by option(help = "Specifies the file to format relative to the mod directory")
.file(
mustExist = true,
canBeFile = true,
canBeDir = false,
mustBeReadable = true,
mustBeWritable = true
)

private val config by option(help = "Specifies the configuration file, otherwise it uses the file 'v2format.config.json'")
.file(
mustExist = true,
canBeFile = true,
canBeDir = false,
mustBeReadable = true
)
private val formatOptions by FormatOptions().cooccurring()

private val configOption by option(
help = "Specifies the configuration file, otherwise it uses the file '$CONFIG_DEFAULT_NAME'"
).file(
mustExist = true,
canBeFile = true,
canBeDir = false,
mustBeReadable = true
)

init {
context {
Expand All @@ -50,31 +54,43 @@ class Main : CliktCommand(help = "A program formatter for Victoria 2 mods.") {
}

private fun formatMod() {
val finder = ModFinder()
val modFolder = folder ?: finder.getModFolder(File("."))
val modConfig = config ?: modFolder.resolveSibling("v2format.config.json")
val modFinder = ModFinder()

val formatModRoot = formatOptions?.modFile ?: modFinder.getModFromDirectory(File("."))
val formatTarget = formatOptions?.file ?: formatModRoot
val formatConfig = resolveConfig(formatModRoot)

try {
Config.loadConfig(modConfig)
Config.loadConfig(formatConfig)
} catch (e: Exception) {
val cleanMessage = e.message.orEmpty()
.replace(" You can enable 'JsonConfiguration.ignoreUnknownKeys' property to ignore unknown keys.", "")
throw RuntimeException("Config file ${modConfig.name} is incorrect. \n$cleanMessage")
throw RuntimeException("Config file '${formatConfig.name}' is invalid. \n${e.message}")
}

val fileFormatter = FileFormatter(modFolder)
val modFormatter = ModFormatter(modFolder, fileFormatter)
val fileFormatter = FileFormatter(formatModRoot)
val modFormatter = ModFormatter(formatModRoot, fileFormatter)

if (file != null) {
if (modFormatter.isFormattable(file!!)) {
fileFormatter.formatFile(file!!)
} else {
throw RuntimeException("File ${file!!.name} cannot be formatted due to its extension or exclusion configuration.")
}
if (formatTarget.isDirectory && formatTarget.canRead() || modFormatter.isFormattable(formatTarget)) {
modFormatter.format(formatTarget)
} else {
modFormatter.format()
throw RuntimeException(
"Format target '${formatTarget.name}' cannot be formatted due to its " +
"extension, exclusion configuration, or read/write property."
)
}
}

private fun resolveConfig(formatModRoot: File): File {
if (configOption != null) {
return configOption!!
}

val targetConfig = formatModRoot.resolveSibling(CONFIG_DEFAULT_NAME)
if (targetConfig.exists()) {
return targetConfig
}

return File(CONFIG_DEFAULT_NAME)
}
}

fun main(args: Array<String>) = Main().main(args)
fun main(args: Array<String>) = Main().main(args)
14 changes: 7 additions & 7 deletions src/main/kotlin/v2/format/ModFinder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.io.IOException

class ModFinder {
@Throws(IOException::class)
fun getModFolder(file: File): File {
fun getModFromDirectory(file: File): File {
val modFiles = file.listFiles { pathName -> pathName.extension == "mod" }!!

if (modFiles.isEmpty()) {
Expand All @@ -17,15 +17,15 @@ class ModFinder {
}

val firstModFile = modFiles.first()
return file.resolve(getModDirectory(firstModFile))
return file.resolve(getModFromModFile(firstModFile))
}

private fun getModDirectory(modFile: File): File {
fun getModFromModFile(modFile: File): File {
val line = modFile.readLines().firstOrNull {
it.trimStart().startsWith("user_dir")
} ?: throw IOException("No entry named 'user_dir' for mod file '${modFile.name}'")
it.trimStart().startsWith("path")
} ?: throw IOException("No entry named 'path' for mod file '${modFile.name}'")

val modFolderName = line.substringAfter('=').trim().removeSurrounding("\"")
return File(modFolderName)
val modRootName = line.substringAfter('=').trim().removeSurrounding("\"").drop(4)
return File(modRootName)
}
}
20 changes: 13 additions & 7 deletions src/main/kotlin/v2/format/ModFormatter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,28 @@ import v2.format.config.Config
import java.io.File
import java.io.IOException

class ModFormatter(private val modFolder: File, private val fileFormatter: FileFormatter) {
private val goodExtensions = arrayOf("txt", "map")
class ModFormatter(private val modRootFolder: File, private val fileFormatter: FileFormatter) {
companion object {
private val goodExtensions = arrayOf("txt", "map")
}

init {
if (!modFolder.isDirectory) {
throw IOException("Mod folder '${modFolder.name}' is not a valid directory.")
if (!modRootFolder.isDirectory) {
throw IOException("Mod folder '${modRootFolder.name}' is not a valid directory.")
}
}

fun format() {
modFolder.walk()
fun format(file: File) {
file.walk()
.filter(::isFormattable)
.forEach(fileFormatter::formatFile)
}

fun isFormattable(file: File) = with(file) {
isFile && extension in goodExtensions && relativeTo(modFolder).path.asUnix() !in Config.excludeFiles
isFile &&
canWrite() &&
extension in goodExtensions &&
relativeTo(modRootFolder).path.asUnix() !in Config.excludeFiles &&
canRead()
}
}
Loading

0 comments on commit 0fece35

Please sign in to comment.