summaryrefslogtreecommitdiff
path: root/support/arara/source/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'support/arara/source/src/main/kotlin')
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/Arara.kt115
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/CLI.kt171
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/AraraSpec.kt90
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/Configuration.kt101
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/ConfigurationUtils.kt157
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/LocalConfiguration.kt85
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/Database.kt24
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/DatabaseUtils.kt97
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileHandlingUtils.kt319
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileSearchingUtils.kt158
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Language.kt69
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/LanguageController.kt59
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Messages.kt106
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/AraraException.kt50
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Evaluator.kt122
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Extractor.kt50
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/FileType.kt110
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt375
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Session.kt119
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Argument.kt40
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Command.kt57
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Conditional.kt67
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Directive.kt32
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveAssembler.kt55
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveUtils.kt312
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Rule.kt48
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleCommand.kt33
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleUtils.kt140
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/ClassLoadingUtils.kt121
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/CommonUtils.kt422
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/DisplayUtils.kt415
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/Extensions.kt68
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/InterpreterUtils.kt164
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/LoggingUtils.kt70
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/MessageUtils.kt266
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/SystemCallUtils.kt105
-rw-r--r--support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/TeeOutputStream.kt66
37 files changed, 0 insertions, 4858 deletions
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/Arara.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/Arara.kt
deleted file mode 100644
index 2b4efbf8db..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/Arara.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara
-
-import com.github.ajalt.clikt.parameters.options.versionOption
-import com.uchuhimo.konf.Config
-import java.time.LocalDate
-import kotlin.time.ExperimentalTime
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.configuration.Configuration
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.model.Extractor
-import org.islandoftex.arara.model.Interpreter
-import org.islandoftex.arara.ruleset.DirectiveUtils
-import org.islandoftex.arara.utils.DisplayUtils
-
-/**
- * arara's main entry point
- *
- * @author Island of TeX
- * @version 5.0
- * @since 5.0
- */
-object Arara {
- // TODO: watch config files
- val baseconfig = Config { addSpec(AraraSpec) }
- .from.env()
- .from.systemProperties()
- var config = baseconfig.withLayer("initial")
-
- /**
- * Main method. This is the application entry point.
- * @param args A string array containing all command line arguments.
- */
- @ExperimentalTime
- @JvmStatic
- fun main(args: Array<String>) {
- // print the arara logo in the terminal; I just
- // hope people use this tool in a good terminal with
- // fixed-width fonts, otherwise the logo will be messed
- DisplayUtils.printLogo()
-
- val version = config[AraraSpec.Application.version]
- CLI().versionOption(version, names = setOf("-V", "--version"),
- message = {
- "arara $version\n" +
- "Copyright (c) ${LocalDate.now().year}, Island of TeX\n" +
- LanguageController.getMessage(Messages
- .INFO_PARSER_NOTES) + "\n\n" +
- "New features in version $version:\n" +
- Arara::class.java
- .getResource("/org/islandoftex/arara/configuration/release-notes")
- .readText()
- })
- .main(args)
- }
-
- @ExperimentalTime
- fun run() {
- try {
- // first of all, let's try to load a potential
- // configuration file located at the current
- // user's home directory; if there's a bad
- // configuration file, arara will panic and
- // end the execution
- Configuration.load()
-
- // let's print the current file information; it is a
- // basic display, just the file name, the size properly
- // formatted as a human readable format, and the last
- // modification date; also, in this point, the logging
- // feature starts to collect data (of course, if enabled
- // either through the configuration file or manually
- // in the command line)
- DisplayUtils.printFileInformation()
-
- // time to read the file and try to extract the directives;
- // extract() brings us a list of directives properly parsed
- // and almost ready to be handled; note that no directives
- // in the provided file will raise an exception; this is
- // by design and I opted to not include a default fallback
- // (although it wouldn't be so difficult to write one,
- // I decided not to take the risk)
- val extracted = Extractor.extract(config[AraraSpec.Execution
- .reference])
-
- // it is time to validate the directives (for example, we have
- // a couple of keywords that cannot be used as directive
- // parameters); another interesting feature of the validate()
- // method is to replicate a directive that has the 'files'
- // keyword on it, since it's the whole point of having 'files'
- // in the first place; if you check the log file, you will see
- // that the list of extracted directives might differ from
- // the final list of directives to be effectively processed
- // by arara
- val directives = DirectiveUtils.process(extracted)
-
- // time to shine, now the interpreter class will interpret
- // one directive at a time, get the corresponding rule,
- // set the parameters, evaluate it, get the tasks, run them,
- // evaluate the result and print the status; note that
- // arara, from this version on, will try to evaluate things
- // progressively, so in case of an error, the previous tasks
- // were already processed and potentially executed
- Interpreter(directives).execute()
- } catch (exception: AraraException) {
- // something bad just happened, so arara will print the proper
- // exception and provide details on it, if available; the idea
- // here is to propagate an exception throughout the whole
- // application and catch it here instead of a local treatment
- DisplayUtils.printException(exception)
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/CLI.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/CLI.kt
deleted file mode 100644
index 9de0f1bd3f..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/CLI.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara
-
-import com.github.ajalt.clikt.core.CliktCommand
-import com.github.ajalt.clikt.parameters.arguments.argument
-import com.github.ajalt.clikt.parameters.arguments.multiple
-import com.github.ajalt.clikt.parameters.options.default
-import com.github.ajalt.clikt.parameters.options.flag
-import com.github.ajalt.clikt.parameters.options.option
-import com.github.ajalt.clikt.parameters.types.int
-import com.github.ajalt.clikt.parameters.types.path
-import com.github.ajalt.clikt.parameters.types.restrictTo
-import kotlin.system.exitProcess
-import kotlin.time.ClockMark
-import kotlin.time.ExperimentalTime
-import kotlin.time.MonoClock
-import kotlin.time.milliseconds
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.filehandling.FileSearchingUtils
-import org.islandoftex.arara.localization.Language
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.model.Session
-import org.islandoftex.arara.utils.CommonUtils
-import org.islandoftex.arara.utils.DisplayUtils
-import org.islandoftex.arara.utils.LoggingUtils
-
-/**
- * arara's command line interface
- *
- * @author Island of TeX
- * @version 5.0
- * @since 5.0
- */
-class CLI : CliktCommand(name = "arara", printHelpOnEmptyArgs = true) {
- private val log by option("-l", "--log",
- help = "Generate a log output")
- .flag(default = AraraSpec.Execution.logging.default)
- private val verbose by option("-v", "--verbose",
- help = "Print the command output")
- .flag("-s", "--silent",
- default = AraraSpec.Execution.verbose.default)
- private val dryrun by option("-n", "--dry-run",
- help = "Go through all the motions of running a command, but " +
- "with no actual calls")
- .flag(default = AraraSpec.Execution.dryrun.default)
- private val onlyheader by option("-H", "--header",
- help = "Extract directives only in the file header")
- .flag(default = AraraSpec.Execution.onlyHeader.default)
- private val timeout by option("-t", "--timeout",
- help = "Set the execution timeout (in milliseconds)")
- .int().restrictTo(min = 1)
- private val language by option("-L", "--language",
- help = "Set the application language")
- .default(AraraSpec.Application.defaultLanguageCode.default)
- private val maxLoops by option("-m", "--max-loops",
- help = "Set the maximum number of loops (> 0)")
- .int().restrictTo(min = 1)
- .default(AraraSpec.Execution.maxLoops.default)
- private val preamble by option("-p", "--preamble",
- help = "Set the file preamble based on the configuration file")
- private val workingDirectory by option("-d", "--working-directory",
- help = "Set the working directory for all tools")
- .path(exists = true, fileOkay = false, readable = true)
- .default(AraraSpec.Execution.workingDirectory.default)
-
- private val reference by argument("file",
- help = "The file(s) to evaluate and process")
- .multiple(required = true)
-
- /**
- * Update the default configuration with the values parsed from the
- * command line.
- */
- @ExperimentalTime
- private fun updateConfigurationFromCommandLine() {
- Arara.config[AraraSpec.Execution.language] = Language(language)
- LanguageController.setLocale(Arara.config[AraraSpec.Execution.language]
- .locale)
-
- Arara.config[AraraSpec.Execution.logging] = log
- Arara.config[AraraSpec.Execution.verbose] = verbose
- Arara.config[AraraSpec.Execution.dryrun] = dryrun
- Arara.config[AraraSpec.Execution.onlyHeader] = onlyheader
- Arara.config[AraraSpec.Execution.maxLoops] = maxLoops
- Arara.config[AraraSpec.Execution.workingDirectory] = workingDirectory
- preamble?.let {
- val preambles = Arara.config[AraraSpec.Execution.preambles]
- if (preambles.containsKey(it)) {
- Arara.config[AraraSpec.Execution.preamblesActive] = true
- Arara.config[AraraSpec.Execution.preamblesContent] =
- // will never throw (see check above)
- preambles.getValue(it)
- } else {
- throw AraraException(
- LanguageController.getMessage(
- Messages.ERROR_PARSER_INVALID_PREAMBLE, it)
- )
- }
- }
- timeout?.let {
- Arara.config[AraraSpec.Execution.timeout] = true
- Arara.config[AraraSpec.Execution.timeoutValue] = it.milliseconds
- }
-
- Arara.config[AraraSpec.UserInteraction.displayTime] = true
- }
-
- /**
- * The actual main method of arara (when run in command-line mode)
- */
- @ExperimentalTime
- override fun run() {
- // the first component to be initialized is the
- // logging controller; note init() actually disables
- // the logging, so early exceptions won't generate
- // a lot of noise in the terminal
- LoggingUtils.init()
-
- // arara features a stopwatch, so we can see how much time has passed
- // since everything started; internally, this class makes use of
- // nano time, so we might get an interesting precision here
- // (although timing is not a serious business in here, it's
- // just a cool addition)
- val executionStart: ClockMark = MonoClock.markNow()
-
- // arara stores the environment variables accessible at the start
- // of the execution in the session object for the user
- Session.updateEnvironmentVariables()
-
- // logging has to be initialized only once and for all because
- // context resets lead to missing output
- LoggingUtils.enableLogging(log)
-
- try {
- // TODO: this will have to change for parallelization
- reference.forEach {
- // TODO: do we have to reset some more file-specific config?
- // especially the working directory will have to be set and
- // changed
- Arara.config = Arara.baseconfig.withLayer(it)
- // next, update the configuration
- updateConfigurationFromCommandLine()
- FileSearchingUtils.discoverFile(it)
- Arara.run()
- // add an empty line between file executions
- println()
- }
-
- // this is the last command from arara; once the execution time is
- // available, print it; note that this notification is suppressed
- // when the command line parsing returns false as result (it makes
- // no sense to print the execution time for a help message, I guess)
- DisplayUtils.printTime(executionStart.elapsedNow().inSeconds)
- } catch (ex: AraraException) {
- DisplayUtils.printException(ex)
- Arara.config[AraraSpec.Execution.status] = 2
- }
-
- // gets the application exit status; the rule here is:
- // 0 : everything went just fine (note that the dry-run mode always
- // makes arara exit with 0, unless it is an error in the directive
- // builder itself).
- // 1 : one of the tasks failed, so the execution ended abruptly. This
- // means the error relies on the command line call, not with arara.
- // 2 : arara just handled an exception, meaning that something bad
- // just happened and might require user intervention.
- exitProcess(CommonUtils.exitStatus)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/AraraSpec.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/AraraSpec.kt
deleted file mode 100644
index 14100ec98b..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/AraraSpec.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.configuration
-
-import com.uchuhimo.konf.ConfigSpec
-import java.io.File
-import java.nio.file.Paths
-import kotlin.time.ExperimentalTime
-import kotlin.time.milliseconds
-import org.islandoftex.arara.localization.Language
-
-/**
- * Configuration hierarchy for arara
- *
- * @author Island of TeX
- * @version 5.0
- * @since 5.0
- */
-@Suppress("MagicNumber")
-object AraraSpec : ConfigSpec() {
- object Application : ConfigSpec() {
- val defaultLanguageCode by optional("en")
- val version by optional(AraraSpec::class.java.`package`.implementationVersion
- ?: "DEVELOPMENT BUILD")
- val namePattern by optional("arara:\\s")
- val width by optional(65)
- }
-
- object Execution : ConfigSpec() {
- val maxLoops by optional(10)
- val timeout by optional(false)
- @ExperimentalTime
- val timeoutValue by optional(0.milliseconds)
- val haltOnErrors by optional(true)
-
- val databaseName by optional("arara")
- val logName by optional("arara")
-
- val verbose by optional(false)
- val language by optional(Language(Application.defaultLanguageCode.default))
- val logging by optional(false)
- val dryrun by optional(false)
- val status by optional(0)
- val fileTypes by optional(ConfigurationUtils.defaultFileTypes)
- val rulePaths by optional(setOf(
- ConfigurationUtils.applicationPath.resolve("rules")
- .toString()
- ))
- val preambles by optional(mapOf<String, String>())
- val preamblesActive by optional(false)
- val preamblesContent by optional("")
-
- val workingDirectory by optional(Paths.get(""))
- val configurationName by optional("[none]")
- val onlyHeader by optional(false)
-
- // TODO: these are runtime values, they should be properly
- // initialized and tested (maybe move them into their own
- // Spec or session)
- val reference by optional(File("/tmp/"))
- val file by optional(File("/tmp/"))
-
- object InfoSpec : ConfigSpec() {
- val ruleId by optional<String?>(null)
- val rulePath by optional<String?>(null)
- }
-
- object DirectiveSpec : ConfigSpec() {
- val lines by optional(listOf<Int>())
- }
-
- val filePattern by optional("")
- }
-
- object Directive : ConfigSpec() {
- val linebreakPattern by optional("^\\s*-->\\s(.*)$")
-
- private const val directivestart = """^\s*(\w+)\s*(:\s*(\{.*\})\s*)?"""
- private const val pattern = """(\s+(if|while|until|unless)\s+(\S.*))?$"""
- val directivePattern by optional(directivestart + pattern)
- }
-
- object UserInteraction : ConfigSpec() {
- val lookAndFeel by optional("none")
- val displayTime by optional(false)
- val displayLine by optional(true)
- val displayResult by optional(false)
- val displayRolling by optional(false)
- val displayException by optional(false)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/Configuration.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/Configuration.kt
deleted file mode 100644
index 06abeeb6db..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/Configuration.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.configuration
-
-import kotlin.time.ExperimentalTime
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.filehandling.FileHandlingUtils
-import org.islandoftex.arara.localization.Language
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-
-/**
- * Implements the configuration model, which holds the default settings and can
- * load the configuration file. The idea here is to provide a map that holds
- * all configuration settings used by model and utilitary classes throughout
- * the execution. This controller is implemented as a singleton.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object Configuration {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Loads the application configuration.
- *
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @ExperimentalTime
- @Throws(AraraException::class)
- fun load() {
- // initialize both file type and language models,
- // since we can track errors from there instead
- // of relying on a check on this level
-
- // get the configuration file, if any
- val file = ConfigurationUtils.configFile
- if (file != null) {
- // set the configuration file name for
- // logging purposes
- Arara.config[AraraSpec.Execution.configurationName] =
- FileHandlingUtils.getCanonicalPath(file)
-
- // then validate it and update the
- // configuration accordingly
- val resource = ConfigurationUtils.loadLocalConfiguration(file)
- update(resource)
- }
-
- // just to be sure, update the
- // current locale in order to
- // display localized messages
- val locale = Arara.config[AraraSpec.Execution.language].locale
- LanguageController.setLocale(locale)
- }
-
- /**
- * Update the configuration based on the provided map.
- *
- * @param resource Map containing the new configuration settings.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun update(resource: LocalConfiguration) {
- if (resource.paths.isNotEmpty())
- Arara.config[AraraSpec.Execution.rulePaths] =
- ConfigurationUtils.normalizePaths(resource.paths)
-
- if (resource.filetypes.isNotEmpty()) {
- Arara.config[AraraSpec.Execution.fileTypes] = ConfigurationUtils.normalizeFileTypes(resource.filetypes)
- }
-
- Arara.config[AraraSpec.Execution.verbose] = resource.isVerbose
- Arara.config[AraraSpec.Execution.logging] = resource.isLogging
- Arara.config[AraraSpec.Execution.onlyHeader] = resource.isHeader
- Arara.config[AraraSpec.Execution.language] =
- Language(resource.language)
- Arara.config[AraraSpec.UserInteraction.lookAndFeel] = resource.laf
-
- Arara.config[AraraSpec.Execution.databaseName] =
- ConfigurationUtils.cleanFileName(resource.dbname)
- Arara.config[AraraSpec.Execution.logName] =
- ConfigurationUtils.cleanFileName(resource.logname)
-
- val loops = resource.loops
- if (loops <= 0) {
- throw AraraException(messages.getMessage(Messages
- .ERROR_CONFIGURATION_LOOPS_INVALID_RANGE))
- } else {
- Arara.config[AraraSpec.Execution.maxLoops] = loops
- }
-
- if (resource.preambles.isNotEmpty())
- Arara.config[AraraSpec.Execution.preambles] = resource.preambles
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/ConfigurationUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/ConfigurationUtils.kt
deleted file mode 100644
index a48a6d0d3f..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/ConfigurationUtils.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.configuration
-
-import com.charleskorn.kaml.Yaml
-import java.io.File
-import java.io.UnsupportedEncodingException
-import java.net.URLDecoder
-import java.nio.file.Path
-import java.nio.file.Paths
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.model.FileType
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements configuration utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object ConfigurationUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * This map contains all file types that arara accepts
- * and their corresponding search patterns (for comments).
- */
- val defaultFileTypePatterns = mapOf(
- "tex" to "^\\s*%\\s+",
- "dtx" to "^\\s*%\\s+",
- "ltx" to "^\\s*%\\s+",
- "drv" to "^\\s*%\\s+",
- "ins" to "^\\s*%\\s+"
- )
-
- /**
- * Set of default file types provided by arara.
- * Initialization may throw AraraException if file types are wrong
- */
- val defaultFileTypes: Set<FileType> by lazy {
- defaultFileTypePatterns
- .map { (extension, pattern) -> FileType(extension, pattern) }
- .toSet()
- }
-
- /**
- * The configuration file in use.
- *
- * Look for configuration files in the user's working directory first
- * if no configuration files are found in the user's working directory,
- * try to look up in a global directory, that is, the user home.
- */
- val configFile: File?
- get() {
- val names = listOf(".araraconfig.yaml",
- "araraconfig.yaml", ".arararc.yaml", "arararc.yaml")
- Arara.config[AraraSpec.Execution.workingDirectory]
- .let { workingDir ->
- val first = names
- .map { workingDir.resolve(it).toFile() }
- .firstOrNull { it.exists() }
- if (first != null)
- return first
- }
- CommonUtils.getSystemPropertyOrNull("user.home")?.let { userHome ->
- return names.map { File(userHome).resolve(it) }
- .firstOrNull { it.exists() }
- }
- return null
- }
-
- /**
- * The canonical absolute application path.
- *
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- val applicationPath: Path
- @Throws(AraraException::class)
- get() {
- try {
- var path = Arara::class.java.protectionDomain.codeSource
- .location.path
- path = URLDecoder.decode(path, "UTF-8")
- return Paths.get(File(path).toURI()).parent.toAbsolutePath()
- } catch (exception: UnsupportedEncodingException) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_GETAPPLICATIONPATH_ENCODING_EXCEPTION
- ),
- exception
- )
- }
- }
-
- /**
- * Validates the configuration file.
- *
- * @param file The configuration file.
- * @return The configuration file as a resource.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun loadLocalConfiguration(file: File): LocalConfiguration {
- return file.runCatching {
- val text = readText()
- if (!text.startsWith("!config"))
- throw Exception("Configuration should start with !config")
- Yaml.default.parse(LocalConfiguration.serializer(),
- text)
- }.getOrElse {
- throw AraraException(messages.getMessage(
- Messages.ERROR_CONFIGURATION_GENERIC_ERROR), it)
- }
- }
-
- /**
- * Normalize a list of rule paths, removing all duplicates.
- *
- * @param paths The list of rule paths.
- * @return A list of normalized paths, without duplicates.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun normalizePaths(paths: Iterable<String>): Set<String> =
- paths.union(AraraSpec.Execution.rulePaths.default)
-
- /**
- * Normalize a list of file types, removing all duplicates.
- *
- * @param types The list of file types.
- * @return A list of normalized file types, without duplicates.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun normalizeFileTypes(types: Iterable<FileType>): Set<FileType> =
- types.union(defaultFileTypes)
-
- /**
- * Cleans the file name to avoid invalid entries.
- *
- * @param name The file name.
- * @return A cleaned file name.
- */
- fun cleanFileName(name: String): String {
- val result = File(name).name.trim()
- return if (result.isEmpty()) "arara" else result.trim()
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/LocalConfiguration.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/LocalConfiguration.kt
deleted file mode 100644
index 959f2a9ab8..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/configuration/LocalConfiguration.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.configuration
-
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.model.FileType
-import org.islandoftex.arara.utils.CommonUtils
-import org.mvel2.templates.TemplateRuntime
-
-/**
- * A local configuration which resembles configuration files in the working
- * directory.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-class LocalConfiguration {
- // rule paths
- var paths: List<String> = listOf()
- get() {
- val user = mapOf(
- "home" to (CommonUtils.getSystemPropertyOrNull("user.home")
- ?: ""),
- "name" to (CommonUtils.getSystemPropertyOrNull("user.name")
- ?: ""))
- val application = mapOf(
- "workingDirectory" to Arara.config[AraraSpec.Execution.workingDirectory].toAbsolutePath().toString()
- )
-
- return field.map { input ->
- var path = CommonUtils.removeKeywordNotNull(input)
- try {
- path = TemplateRuntime.eval(path, mapOf(
- "user" to user, "application" to application
- )) as String
- } catch (_: RuntimeException) {
- // do nothing, gracefully fallback to
- // the default, unparsed path
- }
- path
- }
- }
-
- // file types
- var filetypes: List<FileType> = listOf()
-
- // the application language
- // default to English
- var language: String = Arara.config[AraraSpec.Application.defaultLanguageCode]
- get() = CommonUtils.removeKeywordNotNull(field)
-
- // maximum number of loops
- var loops: Int = Arara.config[AraraSpec.Execution.maxLoops]
-
- // verbose flag
- @SerialName("verbose")
- var isVerbose: Boolean = Arara.config[AraraSpec.Execution.verbose]
-
- // logging flag
- @SerialName("logging")
- var isLogging: Boolean = Arara.config[AraraSpec.Execution.logging]
-
- // header flag
- @SerialName("header")
- var isHeader: Boolean = Arara.config[AraraSpec.Execution.onlyHeader]
-
- // database name
- var dbname: String = Arara.config[AraraSpec.Execution.databaseName]
- get() = CommonUtils.removeKeywordNotNull(field)
-
- // log name
- var logname: String = Arara.config[AraraSpec.Execution.logName]
- get() = CommonUtils.removeKeywordNotNull(field)
-
- // map of preambles
- var preambles: Map<String, String> = Arara.config[AraraSpec.Execution.preambles]
-
- // look and feel
- // default to none
- var laf: String = Arara.config[AraraSpec.UserInteraction.lookAndFeel]
- get() = CommonUtils.removeKeywordNotNull(field)
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/Database.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/Database.kt
deleted file mode 100644
index e4b98cd194..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/Database.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.filehandling
-
-import kotlinx.serialization.Serializable
-
-/**
- * The database model, which keeps track on file changes.
- *
- * This database is a map because it maps files to hashes. So the key will
- * always be a file representation and the value always a string.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-data class Database(
- /**
- * The whole database is implemented as a map, where
- * the key is the absolute canonical file and the value
- * is its corresponding CRC32 hash.
- */
- val map: MutableMap<String, String> = mutableMapOf()
-) : MutableMap<String, String> by map
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/DatabaseUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/DatabaseUtils.kt
deleted file mode 100644
index f4728c9366..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/DatabaseUtils.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.filehandling
-
-import com.charleskorn.kaml.Yaml
-import java.io.File
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-
-/**
- * Implements database utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object DatabaseUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Gets the file representing the YAML file (database).
- *
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- private val file: File
- @Throws(AraraException::class)
- get() {
- val reference = Arara.config[AraraSpec.Execution.reference]
- val name = "${Arara.config[AraraSpec.Execution.databaseName]}.yaml"
- val path = FileHandlingUtils.getParentCanonicalFile(reference)
- return path.resolve(name)
- }
-
- /**
- * Loads the YAML file representing the database.
- *
- * @return The database object.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun load(): Database {
- return if (!exists()) {
- Database()
- } else {
- file.runCatching {
- val text = readText()
- if (!text.startsWith("!database"))
- throw Exception("Database should start with !database")
- Yaml.default.parse(Database.serializer(), text)
- }.getOrElse {
- it.printStackTrace()
- throw AraraException(messages.getMessage(Messages
- .ERROR_LOAD_COULD_NOT_LOAD_XML, file.name), it)
- }
- }
- }
-
- /**
- * Saves the database on a YAML file.
- *
- * @param database The database object.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun save(database: Database) {
- file.runCatching {
- val content = "!database\n" +
- Yaml.default.stringify(Database.serializer(), database)
- writeText(content)
- }.getOrElse {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_SAVE_COULD_NOT_SAVE_XML,
- file.name
- ), it)
- }
- }
-
- /**
- * Checks if the YAML file representing the database exists.
- *
- * @return A boolean value indicating if the YAML file exists.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun exists(): Boolean {
- return file.exists()
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileHandlingUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileHandlingUtils.kt
deleted file mode 100644
index 07f1ecfab9..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileHandlingUtils.kt
+++ /dev/null
@@ -1,319 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.filehandling
-
-import java.io.File
-import java.io.IOException
-import java.text.SimpleDateFormat
-import java.util.zip.CRC32
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-
-/**
- * Implements file handling utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object FileHandlingUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Gets the reference of the current file in execution. Note that this
- * method might return a value different than the main file provided in
- * the command line.
- *
- * @return A reference of the current file in execution. Might be different
- * than the main file provided in the command line.
- */
- private val currentFile: File
- get() = Arara.config[AraraSpec.Execution.file]
-
- /**
- * Writes the string to a file, using UTF-8 as default encoding.
- * @param file The file.
- * @param text The string to be written.
- * @param append A flag whether to append the content.
- * @return A logical value indicating whether it was successful.
- */
- fun writeToFile(file: File, text: String, append: Boolean): Boolean {
- return try {
- // try to write the provided
- // string to the file, with
- // UTF-8 as encoding
- if (append)
- file.appendText(text, Charsets.UTF_8)
- else
- file.writeText(text, Charsets.UTF_8)
- true
- } catch (_: IOException) {
- // if something bad happens,
- // gracefully fallback to
- // reporting the failure
- false
- }
- }
-
- /**
- * Writes the string list to a file, using UTF-8 as default encoding.
- * @param file The file.
- * @param lines The string list to be written.
- * @param append A flag whether to append the content.
- * @return A logical value indicating whether it was successful.
- */
- fun writeToFile(
- file: File,
- lines: List<String>,
- append: Boolean
- ): Boolean =
- try {
- writeToFile(file, lines.joinToString(System.lineSeparator()),
- append)
- } catch (_: IOException) {
- false
- }
-
- /**
- * Reads the provided file (UTF-8) into a list of strings.
- * @param file The file.
- * @return A list of strings.
- */
- fun readFromFile(file: File): List<String> {
- return try {
- // returns the contents of
- // the provided file as
- // a list of strings
- file.readLines(Charsets.UTF_8)
- } catch (_: IOException) {
- // if something bad happens,
- // gracefully fallback to
- // an empty file list
- listOf()
- }
- }
-
- /**
- * Checks if a file exists based on its extension.
- *
- * @param extension The extension.
- * @return A boolean value indicating if the file exists.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun exists(extension: String): Boolean {
- val file = File(getPath(extension))
- return file.exists()
- }
-
- /**
- * Gets the parent canonical path of a file.
- *
- * @param file The file.
- * @return The parent canonical path of a file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun getParentCanonicalPath(file: File): String {
- return getParentCanonicalFile(file).toString()
- }
-
- /**
- * Gets the parent canonical file of a file.
- *
- * @param file The file.
- * @return The parent canonical file of a file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun getParentCanonicalFile(file: File): File {
- return file.runCatching {
- this.canonicalFile.parentFile
- }.getOrElse {
- // it is IOException || is is SecurityException
- throw AraraException(messages.getMessage(
- Messages.ERROR_GETPARENTCANONICALPATH_IO_EXCEPTION), it)
- }
- }
-
- /**
- * Gets the full file path based on the provided extension.
- *
- * @param extension The extension.
- * @return A string containing the full file path.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun getPath(extension: String): String {
- val name = currentFile.nameWithoutExtension + ".$extension"
- val path = getParentCanonicalFile(currentFile)
- return path.resolve(name).toString()
- }
-
- /**
- * Gets the canonical path from the provided file.
- *
- * @param file The file.
- * @return The canonical path from the provided file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun getCanonicalPath(file: File): String {
- return getCanonicalFile(file).toString()
- }
-
- /**
- * Gets the canonical file from the provided file.
- *
- * @param file The file.
- * @return The canonical file from the provided file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun getCanonicalFile(file: File): File {
- try {
- return file.canonicalFile
- } catch (exception: IOException) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_GETCANONICALFILE_IO_EXCEPTION
- ),
- exception
- )
- }
- }
-
- /**
- * Gets the date the provided file was last modified.
- *
- * @param file The file.
- * @return A string representation of the date the provided file was last
- * modified.
- */
- fun getLastModifiedInformation(file: File): String {
- return SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
- .format(file.lastModified())
- }
-
- /**
- * Calculates the CRC32 checksum of the provided file.
- *
- * @param file The file.
- * @return A string containing the CRC32 checksum of the provided file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun calculateHash(file: File): String {
- try {
- return String.format("%08x", CRC32().run {
- update(file.readBytes())
- value
- })
- } catch (exception: IOException) {
- throw AraraException(messages.getMessage(Messages
- .ERROR_CALCULATEHASH_IO_EXCEPTION), exception)
- }
- }
-
- /**
- * Gets the extension of a file.
- *
- * @param file The file.
- * @return The corresponding file type.
- */
- fun getFileExtension(file: File): String = file.extension
-
- /**
- * Gets the base name of a file.
- *
- * @param file The file.
- * @return The corresponding base name.
- */
- fun getBasename(file: File): String = file.nameWithoutExtension
-
- /**
- * Checks if a file has changed since the last verification.
- *
- * @param file The file.
- * @return A boolean value indicating if the file has changed since the last
- * verification.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun hasChanged(file: File): Boolean {
- val database = DatabaseUtils.load()
- val path = getCanonicalPath(file)
- return if (!file.exists()) {
- if (database.containsKey(path)) {
- database.remove(path)
- DatabaseUtils.save(database)
- true
- } else {
- false
- }
- } else {
- val hash = calculateHash(file)
- if (database.containsKey(path)) {
- val value = database[path]
- if (hash == value) {
- false
- } else {
- database[path] = hash
- DatabaseUtils.save(database)
- true
- }
- } else {
- database[path] = hash
- DatabaseUtils.save(database)
- true
- }
- }
- }
-
- /**
- * Checks if the file has changed since the last verification based on the
- * provided extension.
- *
- * @param extension The provided extension.
- * @return A boolean value indicating if the file has changed since the last
- * verification.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun hasChanged(extension: String): Boolean =
- hasChanged(File(getPath(extension)))
-
- /**
- * Checks whether a directory is under a root directory.
- *
- * @param child Directory to be inspected.
- * @param parent Root directory.
- * @return Logical value indicating whether the directoy is under root.
- * @throws AraraException There was a problem with path retrieval.
- */
- @Throws(AraraException::class)
- fun isSubDirectory(child: File, parent: File): Boolean {
- return if (child.isDirectory && parent.isDirectory) {
- getCanonicalPath(child).startsWith(
- getParentCanonicalPath(parent) + File.separator
- )
- } else {
- throw AraraException(messages.getMessage(
- Messages.ERROR_ISSUBDIRECTORY_NOT_A_DIRECTORY,
- child.name))
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileSearchingUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileSearchingUtils.kt
deleted file mode 100644
index 5c61bdb2db..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/filehandling/FileSearchingUtils.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.filehandling
-
-import java.io.File
-import java.io.FileFilter
-import java.nio.file.FileSystems
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements file searching utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object FileSearchingUtils {
- /**
- * List all files from the provided directory according to the list of
- * extensions. The leading dot must be omitted, unless it is part of the
- * extension.
- * @param directory The provided directory.
- * @param extensions The list of extensions.
- * @param recursive A flag indicating whether the search is recursive.
- * @return A list of files.
- */
- fun listFilesByExtensions(
- directory: File,
- extensions: List<String>,
- recursive: Boolean
- ):
- List<File> = try {
- // return the result of the
- // provided search
- if (recursive)
- directory.walkTopDown().asSequence()
- .filter { !it.isDirectory }
- .filter { extensions.contains(it.extension) }
- .toList()
- else
- directory.listFiles(
- FileFilter { extensions.contains(it.extension) })!!
- .toList()
- } catch (_: Exception) {
- // if something bad happens,
- // gracefully fallback to
- // an empty file list
- listOf()
- }
-
- /**
- * List all files from the provided directory matching the list of file
- * name patterns. Such list can contain wildcards.
- * @param directory The provided directory.
- * @param patterns The list of file name patterns.
- * @param recursive A flag indicating whether the search is recursive.
- * @return A list of files.
- */
- fun listFilesByPatterns(
- directory: File,
- patterns: List<String>,
- recursive: Boolean
- ):
- List<File> = try {
- // return the result of the provided
- // search, with the wildcard filter
- // and a potential recursive search
- val pathMatcher = patterns.map {
- FileSystems.getDefault().getPathMatcher("glob:$it")
- }
- if (recursive)
- directory.walkTopDown().asSequence()
- .filter { !it.isDirectory }
- .filter { file ->
- pathMatcher.any { it.matches(file.toPath().fileName) }
- }.toList()
- else
- directory.listFiles { file: File ->
- pathMatcher.any { it.matches(file.toPath().fileName) }
- }!!.toList()
- } catch (_: Exception) {
- // if something bad happens,
- // gracefully fallback to
- // an empty file list
- listOf()
- }
-
- /**
- * Discovers the file through string reference lookup and sets the
- * configuration accordingly.
- *
- * @param reference The string reference.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun discoverFile(reference: String) {
- lookupFile(reference)
- ?: throw AraraException(
- LanguageController.getMessage(
- Messages.ERROR_DISCOVERFILE_FILE_NOT_FOUND,
- reference,
- CommonUtils.fileTypesList
- )
- )
- }
-
- /**
- * Performs a file lookup based on a string reference.
- *
- * @param reference The file reference as a string.
- * @return The file as result of the lookup operation.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun lookupFile(reference: String): File? {
- val types = Arara.config[AraraSpec.Execution.fileTypes]
- val file = Arara.config[AraraSpec.Execution.workingDirectory]
- .resolve(reference).toFile()
- val name = file.name
- val parent = FileHandlingUtils.getParentCanonicalFile(file)
-
- // direct search, so we are considering
- // the reference as a complete name
- val testFile = parent.resolve(name)
- if (testFile.exists() && testFile.isFile) {
- types.firstOrNull {
- testFile.toString().endsWith("." + it.extension)
- }?.let {
- Arara.config[AraraSpec.Execution.filePattern] =
- it.pattern
- Arara.config[AraraSpec.Execution.reference] = testFile
- return testFile
- }
- }
-
- // indirect search; in this case, we are considering
- // that the file reference has an implicit extension,
- // so we need to add it and look again
- // TODO: disable this step in safe mode
- return types.map { parent.resolve("$name.${it.extension}") to it }
- .union(types.map {
- parent.resolve("${name.removeSuffix(".").trim()}.${it.extension}") to it
- })
- .firstOrNull { it.first.exists() && it.first.isFile }
- ?.let {
- Arara.config[AraraSpec.Execution.filePattern] =
- it.second.pattern
- Arara.config[AraraSpec.Execution.reference] = it.first
- file
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Language.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Language.kt
deleted file mode 100644
index 2afa77c41e..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Language.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.localization
-
-import java.util.Locale
-import org.islandoftex.arara.model.AraraException
-
-/**
- * Implements the language model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class Language(code: String) {
- // the language code, based on
- // ISO 639-1 and language variants
- private val code: String
-
- /**
- * Gets the language name.
- *
- * @return A string representing the language name.
- */
- val name: String
- get() = languages.getValue(code).first
-
- /**
- * Gets the language locale.
- *
- * @return The language locale.
- */
- val locale: Locale
- get() = languages.getValue(code).second
-
- // throws an exception on invalid language
- init {
- if (languages.containsKey(code)) {
- this.code = code
- } else {
- throw AraraException(
- LanguageController.getMessage(
- Messages.ERROR_LANGUAGE_INVALID_CODE,
- languagesList
- )
- )
- }
- }
-
- companion object {
- // map containing all languages
- // supported by arara
- private val languages = mapOf(
- "en" to Pair("English", Locale("en")),
- "de" to Pair("German", Locale("de")),
- "nl" to Pair("Dutch", Locale("nl")),
- "qn" to Pair("Broad Norfolk", Locale("en", "QN")),
- "ptbr" to Pair("Brazilian Portuguese", Locale("pt", "BR")),
- "it" to Pair("Italian", Locale("it"))
- )
-
- /**
- * String representing the list of available languages
- * because they don't change initialized with the string
- */
- val languagesList: String = "(" + languages.map { (key, value) ->
- value.first + ": " + key
- }.joinToString(", ") + ")"
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/LanguageController.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/LanguageController.kt
deleted file mode 100644
index e000ab4d63..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/LanguageController.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.localization
-
-import ch.qos.cal10n.IMessageConveyor
-import ch.qos.cal10n.MessageConveyor
-import java.util.Locale
-import org.islandoftex.arara.configuration.AraraSpec
-
-/**
- * Implements the language controller. This controller provides a singleton
- * object that holds the application messages, easily available to all model
- * and utilitary classes.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object LanguageController {
- // the message conveyor helps us to get localized messages
- // according to the provided locale
- // The fallback language is set to English for all
- // messages in arara.
- private var conveyor: IMessageConveyor = MessageConveyor(Locale(
- AraraSpec.Application.defaultLanguageCode.default))
-
- /**
- * Sets the current locale. This method actually resets the language
- * conveyor in order to use the new locale. It's quite simple.
- * @param locale The new locale for localized messages through the language
- * conveyor.
- */
- fun setLocale(locale: Locale) {
- conveyor = MessageConveyor(locale)
- }
-
- /**
- * Gets the localized message indexed by the provided enumeration key,
- * applying an array of objects as parameters. This method is a wrapper to
- * the conveyor's method of the same name.
- * @param E Enumeration type that represents the conveyor messages.
- * @param key Key set in the provided enumeration type.
- * @param parameters Array of objects to be used as parameters.
- * @return A string containing a localized message indexed by the provided
- * enumeration key and applied the array of objects as parameters.
- */
- @Suppress("SpreadOperator")
- fun <E : Enum<*>> getMessage(key: E, vararg parameters: Any): String =
- conveyor.getMessage(key, *parameters)
-
- /**
- * Gets the localized message indexed by the provided enumeration key. This
- * method is a wrapper to the conveyor's method of the same name.
- * @param E Enumeration type that represents the conveyor messages.
- * @param key Key set in the provided enumeration type.
- * @return A string containing a localized message indexed by the provided
- * enumeration key.
- */
- fun <E : Enum<*>> getMessage(key: E): String = conveyor.getMessage(key)
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Messages.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Messages.kt
deleted file mode 100644
index 75d957e1df..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/localization/Messages.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.localization
-
-import ch.qos.cal10n.BaseName
-import ch.qos.cal10n.Locale
-import ch.qos.cal10n.LocaleData
-
-/**
- * This enumeration contains all application messages.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@BaseName("org.islandoftex.arara.localization.messages")
-@LocaleData(Locale(value = "de", charset = "UTF-8"),
- Locale(value = "en", charset = "UTF-8"),
- Locale(value = "en_QN", charset = "UTF-8"),
- Locale(value = "it", charset = "UTF-8"),
- Locale(value = "nl", charset = "UTF-8"),
- Locale(value = "pt_BR", charset = "UTF-8"))
-enum class Messages {
- ERROR_BASENAME_NOT_A_FILE,
- ERROR_CALCULATEHASH_IO_EXCEPTION,
- ERROR_CHECKBOOLEAN_NOT_VALID_BOOLEAN,
- ERROR_CHECKOS_INVALID_OPERATING_SYSTEM,
- ERROR_CHECKREGEX_IO_EXCEPTION,
- ERROR_CONFIGURATION_GENERIC_ERROR,
- ERROR_CONFIGURATION_LOOPS_INVALID_RANGE,
- ERROR_DISCOVERFILE_FILE_NOT_FOUND,
- ERROR_EVALUATE_COMPILATION_FAILED,
- ERROR_EVALUATE_NOT_BOOLEAN_VALUE,
- ERROR_EXTRACTOR_IO_ERROR,
- ERROR_FILETYPE_NOT_A_FILE,
- ERROR_FILETYPE_UNKNOWN_EXTENSION,
- ERROR_GETAPPLICATIONPATH_ENCODING_EXCEPTION,
- ERROR_GETCANONICALFILE_IO_EXCEPTION,
- ERROR_GETPARENTCANONICALPATH_IO_EXCEPTION,
- ERROR_INTERPRETER_ARGUMENT_IS_REQUIRED,
- ERROR_INTERPRETER_COMMAND_RUNTIME_ERROR,
- ERROR_INTERPRETER_DEFAULT_VALUE_RUNTIME_ERROR,
- ERROR_INTERPRETER_EXIT_RUNTIME_ERROR,
- ERROR_INTERPRETER_FLAG_RUNTIME_EXCEPTION,
- ERROR_INTERPRETER_RULE_NOT_FOUND,
- ERROR_INTERPRETER_UNKNOWN_KEYS,
- ERROR_INTERPRETER_WRONG_EXIT_CLOSURE_RETURN,
- ERROR_ISSUBDIRECTORY_NOT_A_DIRECTORY,
- ERROR_LANGUAGE_INVALID_CODE,
- ERROR_LOAD_COULD_NOT_LOAD_XML,
- ERROR_PARSER_INVALID_PREAMBLE,
- ERROR_PARSERULE_GENERIC_ERROR,
- ERROR_REPLICATELIST_MISSING_FORMAT_ARGUMENTS_EXCEPTION,
- ERROR_RULE_IDENTIFIER_AND_PATH,
- ERROR_RUN_GENERIC_EXCEPTION,
- ERROR_RUN_INTERRUPTED_EXCEPTION,
- ERROR_RUN_INVALID_EXIT_VALUE_EXCEPTION,
- ERROR_RUN_IO_EXCEPTION,
- ERROR_RUN_TIMEOUT_EXCEPTION,
- ERROR_RUN_TIMEOUT_INVALID_RANGE,
- ERROR_SAVE_COULD_NOT_SAVE_XML,
- ERROR_SESSION_OBTAIN_UNKNOWN_KEY,
- ERROR_SESSION_REMOVE_UNKNOWN_KEY,
- ERROR_VALIDATE_EMPTY_FILES_LIST,
- ERROR_VALIDATE_FILES_IS_NOT_A_LIST,
- ERROR_VALIDATE_INVALID_DIRECTIVE_FORMAT,
- ERROR_VALIDATE_NO_DIRECTIVES_FOUND,
- ERROR_VALIDATE_ORPHAN_LINEBREAK,
- ERROR_VALIDATE_REFERENCE_IS_RESERVED,
- ERROR_VALIDATE_YAML_EXCEPTION,
- ERROR_VALIDATEBODY_ARGUMENT_ID_IS_RESERVED,
- ERROR_VALIDATEBODY_DUPLICATE_ARGUMENT_IDENTIFIERS,
- ERROR_VALIDATEBODY_MISSING_KEYS,
- ERROR_VALIDATEBODY_NULL_ARGUMENT_ID,
- ERROR_VALIDATEBODY_NULL_COMMAND,
- ERROR_VALIDATEHEADER_NULL_ID,
- ERROR_VALIDATEHEADER_NULL_NAME,
- ERROR_VALIDATEHEADER_WRONG_IDENTIFIER,
- INFO_DISPLAY_EXCEPTION_MORE_DETAILS,
- INFO_DISPLAY_EXECUTION_TIME,
- INFO_DISPLAY_FILE_INFORMATION,
- INFO_INTERPRETER_DRYRUN_MODE_BOOLEAN_MODE,
- INFO_INTERPRETER_DRYRUN_MODE_SYSTEM_COMMAND,
- INFO_LABEL_AUTHOR,
- INFO_LABEL_AUTHORS,
- INFO_LABEL_CONDITIONAL,
- INFO_LABEL_NO_AUTHORS,
- INFO_LABEL_ON_DETAILS,
- INFO_LABEL_ON_ERROR,
- INFO_LABEL_ON_FAILURE,
- INFO_LABEL_ON_SUCCESS,
- INFO_LABEL_UNNAMED_TASK,
- INFO_PARSER_NOTES,
- LOG_INFO_BEGIN_BUFFER,
- LOG_INFO_BOOLEAN_MODE,
- LOG_INFO_DIRECTIVES_BLOCK,
- LOG_INFO_END_BUFFER,
- LOG_INFO_INTERPRET_RULE,
- LOG_INFO_INTERPRET_TASK,
- LOG_INFO_POTENTIAL_DIRECTIVE_FOUND,
- LOG_INFO_POTENTIAL_PATTERN_FOUND,
- LOG_INFO_RULE_LOCATION,
- LOG_INFO_SYSTEM_COMMAND,
- LOG_INFO_TASK_RESULT,
- LOG_INFO_VALIDATED_DIRECTIVES,
- LOG_INFO_WELCOME_MESSAGE
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/AraraException.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/AraraException.kt
deleted file mode 100644
index 6bf2d1e617..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/AraraException.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-/**
- * Implements the specific exception model for arara.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class AraraException : Exception {
- /**
- * The underlying exception, used to hold more details
- * on what really happened
- */
- val exception: Exception?
-
- /**
- * Constructor. Takes the exception message.
- * @param message The exception message.
- */
- constructor(message: String) : super(message) {
- this.exception = null
- }
-
- /**
- * Constructor. Takes the exception message and the underlying exception.
- * @param message The exception message.
- * @param exception The underlying exception object.
- */
- constructor(message: String, exception: Exception) : super(message) {
- this.exception = exception
- }
-
- /**
- * Constructor. Takes the exception message and the underlying exception.
- * @param message The exception message.
- * @param throwable The underlying exception as generic throwable.
- */
- constructor(message: String, throwable: Throwable) : super(message) {
- this.exception = RuntimeException(throwable)
- }
-
- /**
- * Checks if there is an underlying exception defined in the current object.
- * @return A boolean value indicating if the current object has an
- * underlying exception.
- */
- fun hasException(): Boolean = exception?.message != null
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Evaluator.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Evaluator.kt
deleted file mode 100644
index 78b98e709a..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Evaluator.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.ruleset.Conditional
-import org.islandoftex.arara.utils.Methods
-import org.mvel2.templates.TemplateRuntime
-
-/**
- * Implements the evaluator model, on which a conditional can be analyzed and
- * processed.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class Evaluator {
- // this attribute holds the maximum number of
- // loops arara will accept; it's like
- // reaching infinity
- private val loops: Int = Arara.config[AraraSpec.Execution.maxLoops]
-
- // the counter for the current execution, it
- // helps us keep track of the number of times
- // this evaluation has happened, and also to
- // prevent potential infinite loops
- private var counter: Int = 0
-
- // a flag that indicates the
- // evaluation to halt regardless
- // of the the result
- private var halt: Boolean = false
-
- /**
- * Check if a condition is of type if or unless and whether halt
- * is set.
- * @param type The type to check.
- * @param haltCheck The value [halt] should have.
- * @return `(type == if || type == unless) && haltCheck`
- */
- private fun isIfUnlessAndHalt(
- type: Conditional.ConditionalType,
- haltCheck: Boolean = true
- ): Boolean =
- (type == Conditional.ConditionalType.IF ||
- type == Conditional.ConditionalType.UNLESS) &&
- halt == haltCheck
-
- /**
- * Only run the evaluation of the conditional including a check whether
- * the result needs to be inverted.
- * @param conditional The conditional.
- * @return The result of the evaluation.
- */
- @Throws(AraraException::class, RuntimeException::class)
- private fun evaluateCondition(conditional: Conditional): Boolean {
- val result = TemplateRuntime.eval("@{ " + conditional.condition + " }",
- Methods.getConditionalMethods())
- return if (result is Boolean) {
- if (conditional.type == Conditional.ConditionalType.UNLESS ||
- conditional.type == Conditional.ConditionalType.UNTIL)
- !result
- else
- result
- } else {
- throw AraraException(messages.getMessage(
- Messages.ERROR_EVALUATE_NOT_BOOLEAN_VALUE))
- }
- }
-
- /**
- * Evaluate the provided conditional.
- *
- * @param conditional The conditional object.
- * @return A boolean value indicating if the conditional holds.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- @Suppress("TooGenericExceptionCaught")
- fun evaluate(conditional: Conditional): Boolean {
- // when in dry-run mode or not evaluating a
- // conditional, arara always ignores conditional
- // evaluations
- if (conditional.type == Conditional.ConditionalType.NONE ||
- Arara.config[AraraSpec.Execution.dryrun] ||
- isIfUnlessAndHalt(conditional.type, true))
- return false
- else if (isIfUnlessAndHalt(conditional.type, false)) {
- halt = true
- }
-
- // check counters and see if the execution
- // has reached our concept of infinity,
- // thus breaking the cycles
- counter++
- return when {
- conditional.type === Conditional.ConditionalType.WHILE
- && counter > loops -> false
- conditional.type === Conditional.ConditionalType.UNTIL
- && counter >= loops -> false
- else -> {
- try {
- evaluateCondition(conditional)
- } catch (exception: RuntimeException) {
- throw AraraException(messages.getMessage(Messages
- .ERROR_EVALUATE_COMPILATION_FAILED),
- exception)
- }
- }
- }
- }
-
- companion object {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Extractor.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Extractor.kt
deleted file mode 100644
index ed4d811d22..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Extractor.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-import java.io.File
-import java.io.IOException
-import java.nio.charset.Charset
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.ruleset.Directive
-import org.islandoftex.arara.ruleset.DirectiveUtils
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Extractor for directives from the provided main file.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object Extractor {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Extracts a list of directives from the provided main file, obtained from
- * the configuration controller.
- * @param file The file to extract the directives from.
- * @param charset The charset of the file.
- * @return A list of directives.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun extract(file: File, charset: Charset = Charsets.UTF_8):
- List<Directive> {
- try {
- val content = CommonUtils.preambleContent.toMutableList()
- content.addAll(file.readLines(charset))
- return DirectiveUtils.extractDirectives(content)
- } catch (ioexception: IOException) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_EXTRACTOR_IO_ERROR
- ),
- ioexception
- )
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/FileType.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/FileType.kt
deleted file mode 100644
index e6ed27d51a..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/FileType.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-import java.util.regex.PatternSyntaxException
-import kotlinx.serialization.Serializable
-import org.islandoftex.arara.configuration.ConfigurationUtils
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements the file type model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-class FileType {
- // string representing the
- // file extension
- var extension: String = INVALID_EXTENSION
- get() = CommonUtils.removeKeywordNotNull(field)
- private set
- // string representing the
- // file pattern to be used
- // as directive lookup
- var pattern: String = INVALID_PATTERN
- @Throws(AraraException::class)
- get() {
- CommonUtils.removeKeywordNotNull(field)
- if (field == INVALID_PATTERN) {
- field = ConfigurationUtils.defaultFileTypePatterns[extension]
- ?: throw AraraException(
- LanguageController.getMessage(
- Messages.ERROR_FILETYPE_UNKNOWN_EXTENSION,
- extension,
- CommonUtils.fileTypesList
- )
- )
- }
- return field
- }
- private set
-
- constructor(extension: String, pattern: String) {
- this.extension = extension
- this.pattern = pattern
-
- try {
- pattern.toPattern()
- } catch (e: PatternSyntaxException) {
- if (!ConfigurationUtils.defaultFileTypePatterns.containsKey(extension))
- throw AraraException(
- LanguageController.getMessage(
- Messages.ERROR_FILETYPE_UNKNOWN_EXTENSION,
- extension,
- CommonUtils.fileTypesList
- )
- )
- }
- }
-
- companion object {
- /**
- * This constant identifies an invalid extension. As unices do not
- * allow a forward and Windows does not allow a backward slash, this
- * should suffice.
- */
- const val INVALID_EXTENSION = "/\\"
- /**
- * This constant identifies an invalid pattern. This is a opening
- * character class which is invalid.
- */
- const val INVALID_PATTERN = "["
- }
-
- /**
- * Provides a textual representation of the current file type object.
- * @return A string containing a textual representation of the current file
- * type object.
- */
- override fun toString(): String {
- return ".$extension"
- }
-
- /**
- * Implements the file type equals method, checking if one file type is
- * equal to another. Note that only the file extension is considered.
- * @param other The object to be analyzed.
- * @return A boolean value indicating if those two objects are equal.
- */
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as FileType
- if (extension != other.extension) return false
- return true
- }
-
- /**
- * Implements the file type hash code. Note that only the file extension is
- * considered.
- * @return An integer representing the file type hash code.
- */
- override fun hashCode(): Int {
- return extension.hashCode()
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt
deleted file mode 100644
index 49cf40f1a2..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt
+++ /dev/null
@@ -1,375 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-import java.io.File
-import kotlin.time.ExperimentalTime
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.ruleset.Argument
-import org.islandoftex.arara.ruleset.Command
-import org.islandoftex.arara.ruleset.Conditional
-import org.islandoftex.arara.ruleset.Directive
-import org.islandoftex.arara.ruleset.Rule
-import org.islandoftex.arara.ruleset.RuleCommand
-import org.islandoftex.arara.ruleset.RuleUtils
-import org.islandoftex.arara.utils.CommonUtils
-import org.islandoftex.arara.utils.DisplayUtils
-import org.islandoftex.arara.utils.InterpreterUtils
-import org.islandoftex.arara.utils.Methods
-import org.mvel2.templates.TemplateRuntime
-import org.slf4j.LoggerFactory
-
-/**
- * Interprets the list of directives.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class Interpreter(
- /**
- * The list of directives to be interpreted and evaluated.
- */
- val directives: List<Directive>
-) {
- /**
- * Exception class to represent that the interpreter should stop for some
- * reason
- */
- private class HaltExpectedException(msg: String) : Exception(msg)
-
- /**
- * Gets the rule according to the provided directive.
- *
- * @param directive The provided directive.
- * @return The absolute canonical path of the rule, given the provided
- * directive.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun getRule(directive: Directive): File {
- return InterpreterUtils.buildRulePath(directive.identifier)
- ?: throw AraraException(
- messages.getMessage(
- Messages.ERROR_INTERPRETER_RULE_NOT_FOUND,
- directive.identifier,
- "(" + CommonUtils.allRulePaths
- .joinToString("; ") + ")"
- )
- )
- }
-
- // TODO: in the following, extract the printing into the higher level
- // function
- /**
- * "Run" a boolean return value
- * @param value The boolean.
- * @param conditional The conditional to print in dry-run mode.
- * @param authors The authors of the rule.
- * @return Returns [value]
- */
- private fun runBoolean(
- value: Boolean,
- conditional: Conditional,
- authors: List<String>
- ): Boolean {
- logger.info(messages.getMessage(Messages.LOG_INFO_BOOLEAN_MODE,
- value.toString()))
-
- if (Arara.config[AraraSpec.Execution.dryrun]) {
- DisplayUtils.printAuthors(authors)
- DisplayUtils.wrapText(messages.getMessage(Messages
- .INFO_INTERPRETER_DRYRUN_MODE_BOOLEAN_MODE,
- value))
- DisplayUtils.printConditional(conditional)
- }
-
- return value
- }
-
- /**
- * Run a command
- * @param command The command to run.
- * @param conditional The conditional applied to the run (only for printing).
- * @param authors The rule authors (only for printing).
- * @param ruleCommandExitValue The exit value of the rule command.
- * @return Success of the execution.
- * @throws AraraException Execution failed.
- */
- @ExperimentalTime
- @Throws(AraraException::class)
- @Suppress("TooGenericExceptionCaught")
- private fun runCommand(
- command: Command,
- conditional: Conditional,
- authors: List<String>,
- ruleCommandExitValue: String?
- ): Boolean {
- logger.info(messages.getMessage(Messages.LOG_INFO_SYSTEM_COMMAND,
- command))
- var success = true
-
- if (!Arara.config[AraraSpec.Execution.dryrun]) {
- val code = InterpreterUtils.run(command)
- val check: Any = try {
- val context = mapOf<String, Any>("value" to code)
- TemplateRuntime.eval(
- "@{ " + (ruleCommandExitValue ?: "value == 0") + " }",
- context)
- } catch (exception: RuntimeException) {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(Messages
- .ERROR_INTERPRETER_EXIT_RUNTIME_ERROR),
- exception)
- }
-
- success = if (check is Boolean) {
- check
- } else {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_INTERPRETER_WRONG_EXIT_CLOSURE_RETURN
- )
- )
- }
- } else {
- DisplayUtils.printAuthors(authors)
- DisplayUtils.wrapText(messages.getMessage(
- Messages.INFO_INTERPRETER_DRYRUN_MODE_SYSTEM_COMMAND,
- command))
- DisplayUtils.printConditional(conditional)
- }
-
- return success
- }
-
- /**
- * Converts the command evaluation result to a flat list.
- * @param result The result
- * @return A flat list.
- */
- private fun resultToList(result: Any) = if (result is List<*>) {
- CommonUtils.flatten(result)
- } else {
- listOf(result)
- }
-
- /**
- * Execute a command.
- * @param command The command to evaluate.
- * @param conditional Under which condition to execute.
- * @param rule The rule (only passed for output purposes).
- * @param parameters The parameters for evaluation
- * @throws AraraException Running the command failed.
- */
- @ExperimentalTime
- @Throws(AraraException::class)
- @Suppress("TooGenericExceptionCaught", "ThrowsCount")
- private fun executeCommand(
- command: RuleCommand,
- conditional: Conditional,
- rule: Rule,
- parameters: Map<String, Any>
- ) {
- val result: Any = try {
- TemplateRuntime.eval(command.command!!, parameters)
- } catch (exception: RuntimeException) {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(Messages
- .ERROR_INTERPRETER_COMMAND_RUNTIME_ERROR),
- exception)
- }
-
- // TODO: check nullability
- resultToList(result).filter { it.toString().isNotBlank() }
- .forEach { current ->
- DisplayUtils.printEntry(rule.name, command.name
- ?: messages.getMessage(Messages
- .INFO_LABEL_UNNAMED_TASK))
-
- val success = when (current) {
- is Boolean -> runBoolean(current, conditional,
- rule.authors)
- is Command -> runCommand(current, conditional,
- rule.authors, command.exit)
- else -> TODO("error: this should not happen" +
- "we are only supporting boolean + command")
- }
-
- DisplayUtils.printEntryResult(success)
-
- if (Arara.config[AraraSpec.Execution.haltOnErrors] && !success)
- // TODO: localize
- throw HaltExpectedException("Command failed")
-
- // TODO: document this key
- val haltKey = "arara:${Arara.config[AraraSpec
- .Execution.reference].name}:halt"
- if (Session.contains(haltKey)) {
- Arara.config[AraraSpec.Execution.status] =
- Session[haltKey].toString().toInt()
- // TODO: localize
- throw HaltExpectedException("User requested halt")
- }
- }
- }
-
- /**
- * Executes each directive, throwing an exception if something bad has
- * happened.
- *
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @ExperimentalTime
- @Throws(AraraException::class)
- @Suppress("NestedBlockDepth")
- fun execute() {
- for (directive in directives) {
- logger.info(messages.getMessage(Messages.LOG_INFO_INTERPRET_RULE,
- directive.identifier))
-
- Arara.config[AraraSpec.Execution.file] =
- directive.parameters.getValue("reference") as File
- val file = getRule(directive)
-
- logger.info(messages.getMessage(Messages.LOG_INFO_RULE_LOCATION,
- file.parent))
-
- Arara.config[AraraSpec.Execution.InfoSpec.ruleId] =
- directive.identifier
- Arara.config[AraraSpec.Execution.InfoSpec.rulePath] =
- file.parent
- Arara.config[AraraSpec.Execution.DirectiveSpec.lines] =
- directive.lineNumbers
-
- // parse the rule identified by the directive
- // (may throw an exception)
- val rule = RuleUtils.parseRule(file, directive.identifier)
- val parameters = parseArguments(rule, directive)
- .plus(Methods.getRuleMethods())
-
- val evaluator = Evaluator()
-
- var available = true
- if (InterpreterUtils.runPriorEvaluation(directive.conditional)) {
- available = evaluator.evaluate(directive.conditional)
- }
-
- // if this directive is conditionally disabled, skip
- if (!available) continue
- // if not execute the commands associated with the directive
- do {
- rule.commands.forEach { command ->
- try {
- executeCommand(command, directive.conditional, rule, parameters)
- } catch (_: HaltExpectedException) {
- // if the user uses the halt rule to trigger
- // a halt, this will be raised
- return
- }
- }
- } while (evaluator.evaluate(directive.conditional))
- }
- }
-
- /**
- * Parses the rule arguments against the provided directive.
- *
- * @param rule The rule object.
- * @param directive The directive.
- * @return A map containing all arguments resolved according to the
- * directive parameters.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun parseArguments(rule: Rule, directive: Directive):
- Map<String, Any> {
- val arguments = rule.arguments
- val unknown = CommonUtils.getUnknownKeys(directive.parameters,
- arguments).minus("reference")
- if (unknown.isNotEmpty())
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(
- Messages.ERROR_INTERPRETER_UNKNOWN_KEYS,
- "(" + unknown.joinToString(", ") + ")"))
-
- val resolvedArguments = mutableMapOf<String, Any>()
- resolvedArguments["reference"] = directive.parameters
- .getValue("reference")
-
- val context = mapOf(
- "parameters" to directive.parameters,
- "reference" to directive.parameters.getValue("reference")
- ).plus(Methods.getRuleMethods())
-
- arguments.forEach { argument ->
- resolvedArguments[argument.identifier!!] = processArgument(argument,
- directive.parameters.containsKey(argument.identifier!!),
- context)
- }
-
- return resolvedArguments
- }
-
- /**
- * Process a single argument and return the evaluated result.
- * @param argument The argument to process.
- * @param idInDirectiveParams Whether the argument's identifier is
- * contained in the directive's parameters field.
- * @param context The context for the evaluation.
- * @return The result of the evaluation.
- * @throws AraraException The argument could not be processed.
- */
- @Throws(AraraException::class)
- @Suppress("TooGenericExceptionCaught", "ThrowsCount")
- private fun processArgument(
- argument: Argument,
- idInDirectiveParams: Boolean,
- context: Map<String, Any>
- ): Any {
- if (argument.isRequired && !idInDirectiveParams)
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(
- Messages.ERROR_INTERPRETER_ARGUMENT_IS_REQUIRED,
- argument.identifier!!))
-
- var ret = argument.default?.let {
- try {
- TemplateRuntime.eval(it, context)
- } catch (exception: RuntimeException) {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(Messages
- .ERROR_INTERPRETER_DEFAULT_VALUE_RUNTIME_ERROR),
- exception)
- }
- } ?: ""
-
- if (argument.flag != null && idInDirectiveParams) {
- ret = try {
- TemplateRuntime.eval(argument.flag!!, context)
- } catch (exception: RuntimeException) {
- throw AraraException(CommonUtils.ruleErrorHeader + messages
- .getMessage(Messages
- .ERROR_INTERPRETER_FLAG_RUNTIME_EXCEPTION),
- exception)
- }
- }
-
- return ret
- }
-
- companion object {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- // the class logger obtained from
- // the logger factory
- private val logger = LoggerFactory.getLogger(Interpreter::class.java)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Session.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Session.kt
deleted file mode 100644
index c2093429e1..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Session.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.model
-
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-
-/**
- * Implements the session.
- *
- * This class wraps a map that holds the execution session, that is, a dirty
- * maneuver to exchange pretty much any data between commands and even rules.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object Session {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- // the session map which holds the execution session;
- // the idea here is to provide wrappers to the map
- // methods, so it could be easily manipulated
- private val map = mutableMapOf<String, Any>()
-
- /**
- * Gets the object indexed by the provided key from the session. This method
- * holds the map method of the very same name.
- *
- * @param key The provided key.
- * @return The object indexed by the provided key.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- operator fun get(key: String): Any {
- return if (contains(key)) {
- map.getValue(key)
- } else {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_SESSION_OBTAIN_UNKNOWN_KEY,
- key
- )
- )
- }
- }
-
- /**
- * Inserts (or overwrites) the object indexed by the provided key into the
- * session. This method holds the map method of the very same name.
- *
- * @param key The provided key.
- * @param value The value to be inserted.
- */
- fun put(key: String, value: Any) {
- map[key] = value
- }
-
- /**
- * Removes the entry indexed by the provided key from the session. This method
- * holds the map method of the same name.
- *
- * @param key The provided key.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun remove(key: String) {
- if (contains(key)) {
- map.remove(key)
- } else {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_SESSION_REMOVE_UNKNOWN_KEY,
- key
- )
- )
- }
- }
-
- /**
- * Checks if the provided key exists in the session.
- *
- * @param key The provided key.
- * @return A boolean value indicating if the provided key exists in the
- * session.
- */
- operator fun contains(key: String): Boolean = map.containsKey(key)
-
- /**
- * Clears the session (map). This method, as usual, holds the map method of
- * the same name.
- */
- fun clear() = map.clear()
-
- /**
- * Update the environment variables stored in the session.
- *
- * @param additionFilter Which environment variables to include. You can
- * filter their names (the string parameter) but not their values. By
- * default all values will be added.
- * @param removalFilter Which environment variables to remove beforehand.
- * By default all values will be removed.
- */
- fun updateEnvironmentVariables(
- additionFilter: (String) -> Boolean = { true },
- removalFilter: (String) -> Boolean = { true }
- ) {
- // remove all current environment variables to clean up the session
- map.filterKeys { it.startsWith("environment:") }
- .filterKeys(removalFilter)
- .forEach { remove(it.key) }
- // add all relevant new environment variables
- System.getenv().filterKeys(additionFilter)
- .forEach { map["environment:${it.key}"] = it.value }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Argument.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Argument.kt
deleted file mode 100644
index dfd2b99403..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Argument.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * The rule argument model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-class Argument {
- /**
- * The argument identifier
- */
- var identifier: String? = null
- get() = CommonUtils.removeKeyword(field)
-
- /**
- * Boolean indicating if the current argument is required
- */
- @SerialName("required")
- var isRequired: Boolean = false
-
- /**
- * Flag to hold the argument value manipulation
- */
- var flag: String? = null
- get() = CommonUtils.removeKeyword(field)
-
- /**
- * The argument fallback if it is not defined in the directive
- */
- var default: String? = null
- get() = CommonUtils.removeKeyword(field)
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Command.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Command.kt
deleted file mode 100644
index df1ce802f5..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Command.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import java.io.File
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements a command model, containing a list of strings.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class Command {
- /**
- * A list of elements which are components
- * of a command and represented as strings
- */
- val elements: List<String>
-
- /**
- * An optional file acting as a reference for
- * the default working directory
- */
- var workingDirectory: File = Arara.config[AraraSpec.Execution
- .workingDirectory].toFile()
-
- /**
- * Constructor.
- * @param values An array of objects.
- */
- constructor(vararg values: Any) {
- elements = mutableListOf()
- val result = CommonUtils.flatten(values.toList())
- result.map { it.toString() }.filter { it.isNotEmpty() }
- .forEach { elements.add(it) }
- }
-
- /**
- * Constructor.
- * @param elements A list of strings.
- */
- constructor(elements: List<String>) {
- this.elements = elements
- }
-
- /**
- * Provides a textual representation of the current command.
- * @return A string representing the current command.
- */
- override fun toString(): String {
- return "[ " + elements.joinToString(", ") + " ]" +
- " @ $workingDirectory"
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Conditional.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Conditional.kt
deleted file mode 100644
index 8a4ec6cb35..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Conditional.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-/**
- * The conditional class, it represents the type of conditional available
- * for a directive and its corresponding expression to be evaluated.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-data class Conditional(
- /**
- * The type of the condition indicates the meaning when evaluated.
- * Defaults to [ConditionalType.NONE].
- */
- val type: ConditionalType = ConditionalType.NONE,
- /**
- * The expression to be evaluated according to its type. Defaults
- * to no evaluation (empty string).
- */
- val condition: String = ""
-) {
- /**
- * The types of conditionals arara is able to recognize.
- */
- enum class ConditionalType {
- /**
- * Evaluated beforehand, directive is interpreted if and only if the
- * result is true.
- */
- IF,
- /**
- * There is no evaluation, directive is interpreted, no extra effort is
- * needed.
- */
- NONE,
- /**
- * Evaluated beforehand, directive is interpreted if and only if the
- * result is false.
- */
- UNLESS,
- /**
- * Directive is interpreted the first time, then the evaluation is
- * done; while the result is false, the directive is interpreted again
- * and again.
- */
- UNTIL,
- /**
- * Evaluated beforehand, directive is interpreted if and only if the
- * result is true, and the process is repeated while the result still
- * holds true.
- */
- WHILE
- }
-
- /**
- * Provides a textual representation of the conditional object.
- * @return A string representation of this object.
- */
- override fun toString(): String {
- return "{ $type" +
- if (type != ConditionalType.NONE)
- ", expression: ${condition.trim()}"
- else "" + " }"
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Directive.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Directive.kt
deleted file mode 100644
index 33f8431744..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Directive.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-/**
- * Implements the directive model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-data class Directive(
- /**
- * The directive identifier, it is resolved to the rule identifier
- * later on.
- */
- val identifier: String,
- /**
- * A map containing the parameters; they are validated later on in
- * order to ensure they are valid.
- */
- val parameters: Map<String, Any>,
- /**
- * A conditional containing the type and the expression to be evaluated
- * later on.
- */
- val conditional: Conditional,
- /**
- * A list contained all line numbers from the main file which built the
- * current directive.
- */
- val lineNumbers: List<Int>
-)
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveAssembler.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveAssembler.kt
deleted file mode 100644
index a431df6ae2..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveAssembler.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-/**
- * Implements a directive assembler in order to help build a directive from a
- * list of strings.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class DirectiveAssembler {
- // this variable holds a list of
- // line numbers indicating which
- // lines composed the resulting
- // potential directive
- private val lineNumbers = mutableListOf<Int>()
-
- // this variable holds the textual
- // representation of the directive
- private var text: String = ""
-
- /**
- * Checks if an append operation is allowed.
- * @return A boolean value indicating if an append operation is allowed.
- */
- val isAppendAllowed: Boolean
- get() = lineNumbers.isNotEmpty()
-
- /**
- * Adds a line number to the assembler.
- * @param line An integer representing the line number.
- */
- fun addLineNumber(line: Int) = lineNumbers.add(line)
-
- /**
- * Appends the provided line to the assembler text.
- * @param line The provided line.
- */
- fun appendLine(line: String) {
- text = text + " " + line.trim()
- }
-
- /**
- * Gets the list of line numbers.
- * @return The list of line numbers.
- */
- fun getLineNumbers(): List<Int> = lineNumbers
-
- /**
- * Gets the text.
- * @return The assembler text, properly trimmed.
- */
- fun getText(): String = text.trim()
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveUtils.kt
deleted file mode 100644
index e901e25fcf..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/DirectiveUtils.kt
+++ /dev/null
@@ -1,312 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
-import com.fasterxml.jackson.module.kotlin.readValue
-import com.fasterxml.jackson.module.kotlin.registerKotlinModule
-import java.io.File
-import java.util.regex.Pattern
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.filehandling.FileHandlingUtils
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.utils.DisplayUtils
-import org.slf4j.LoggerFactory
-
-/**
- * Implements directive utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@UseExperimental(kotlinx.serialization.ImplicitReflectionSerializer::class)
-object DirectiveUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- // get the logger context from a factory
- private val logger = LoggerFactory.getLogger(DirectiveUtils::class.java)
-
- /**
- * This function filters the lines of a file to identify the potential
- * directives.
- *
- * @param lines The lines of the file.
- * @return A map containing the line number and the line's content.
- */
- private fun getPotentialDirectiveLines(lines: List<String>):
- Map<Int, String> {
- val header = Arara.config[AraraSpec.Execution.onlyHeader]
- val validLineRegex = Arara.config[AraraSpec.Execution.filePattern]
- val validLinePattern = validLineRegex.toPattern()
- val validLineStartPattern = (validLineRegex + Arara.config[AraraSpec
- .Application.namePattern]).toPattern()
- val map = mutableMapOf<Int, String>()
- for ((i, text) in lines.withIndex()) {
- val validLineMatcher = validLineStartPattern.matcher(text)
- if (validLineMatcher.find()) {
- val line = text.substring(validLineMatcher.end())
- map[i + 1] = line
-
- logger.info(messages.getMessage(
- Messages.LOG_INFO_POTENTIAL_PATTERN_FOUND,
- i + 1, line.trim()))
- } else if (header && !checkLinePattern(validLinePattern, text)) {
- // if we should only look within the file's header and reached
- // a point where the line pattern does not match anymore, we
- // assume we have left the header and break
- break
- }
- }
- return map
- }
-
- /**
- * Extracts a list of directives from a list of strings.
- *
- * @param lines List of strings.
- * @return A list of directives.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- @Suppress("MagicNumber")
- fun extractDirectives(lines: List<String>): List<Directive> {
- val pairs = getPotentialDirectiveLines(lines)
- .takeIf { it.isNotEmpty() }
- ?: throw AraraException(messages.getMessage(
- Messages.ERROR_VALIDATE_NO_DIRECTIVES_FOUND))
-
- val assemblers = mutableListOf<DirectiveAssembler>()
- var assembler = DirectiveAssembler()
- val linebreakPattern = Arara.config[AraraSpec.Directive
- .linebreakPattern].toPattern()
- for ((lineno, content) in pairs) {
- val linebreakMatcher = linebreakPattern.matcher(content)
- if (linebreakMatcher.find()) {
- if (!assembler.isAppendAllowed) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_VALIDATE_ORPHAN_LINEBREAK,
- lineno
- )
- )
- } else {
- assembler.addLineNumber(lineno)
- assembler.appendLine(linebreakMatcher.group(1))
- }
- } else {
- if (assembler.isAppendAllowed) {
- assemblers.add(assembler)
- }
- assembler = DirectiveAssembler()
- assembler.addLineNumber(lineno)
- assembler.appendLine(content)
- }
- }
- if (assembler.isAppendAllowed) {
- assemblers.add(assembler)
- }
-
- return assemblers.map { generateDirective(it) }
- }
-
- /**
- * Generates a directive from a directive assembler.
- *
- * @param assembler The directive assembler.
- * @return The corresponding directive.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- @Suppress("MagicNumber")
- fun generateDirective(assembler: DirectiveAssembler): Directive {
- val matcher = Arara.config[AraraSpec.Directive.directivePattern]
- .toPattern().matcher(assembler.getText())
- if (matcher.find()) {
- val directive = Directive(
- identifier = matcher.group(1)!!,
- parameters = getParameters(matcher.group(3),
- assembler.getLineNumbers()),
- conditional = Conditional(
- type = getType(matcher.group(5)),
- condition = matcher.group(6) ?: ""
- ),
- lineNumbers = assembler.getLineNumbers()
- )
-
- logger.info(messages.getMessage(
- Messages.LOG_INFO_POTENTIAL_DIRECTIVE_FOUND, directive))
-
- return directive
- } else {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_VALIDATE_INVALID_DIRECTIVE_FORMAT,
- "(" + assembler.getLineNumbers()
- .joinToString(", ") + ")"
- )
- )
- }
- }
-
- /**
- * Gets the conditional type based on the input string.
- *
- * @param text The input string.
- * @return The conditional type.
- */
- private fun getType(text: String?): Conditional.ConditionalType {
- return when (text) {
- null -> Conditional.ConditionalType.NONE
- "if" -> Conditional.ConditionalType.IF
- "while" -> Conditional.ConditionalType.WHILE
- "until" -> Conditional.ConditionalType.UNTIL
- else -> Conditional.ConditionalType.UNLESS
- }
- }
-
- /**
- * Gets the parameters from the input string.
- *
- * @param text The input string.
- * @param numbers The list of line numbers.
- * @return A map containing the directive parameters.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- private fun getParameters(
- text: String?,
- numbers: List<Int>
- ): Map<String, Any> {
- if (text == null)
- return mapOf()
-
- /* Before using kotlinx.serialization, there has been a dedicated
- * directive resolver which instructed SnakeYAML to do the following:
- *
- * addImplicitResolver(Tag.MERGE, MERGE, "<")
- * addImplicitResolver(Tag.NULL, NULL, "~nN\u0000")
- * addImplicitResolver(Tag.NULL, EMPTY, null)
- *
- * This has been removed.
- */
- return ObjectMapper(YAMLFactory()).registerKotlinModule().runCatching {
- readValue<Map<String, Any>>(text)
- }.getOrElse {
- throw AraraException(messages.getMessage(
- Messages.ERROR_VALIDATE_YAML_EXCEPTION,
- "(" + numbers.joinToString(", ") + ")"),
- it)
- }
- }
-
- /**
- * Replicate a directive for given files.
- *
- * @param holder The list of files.
- * @param parameters The parameters for the directive.
- * @param directive The directive to clone.
- * @return List of cloned directives.
- * @throws AraraException If there is an error validating the [holder]
- * object.
- */
- @Throws(AraraException::class)
- private fun replicateDirective(
- holder: Any,
- parameters: Map<String, Any>,
- directive: Directive
- ): List<Directive> {
- return if (holder is List<*>) {
- // we received a file list, so we map that list to files
- holder.filterIsInstance<Any>()
- .asSequence()
- .map { File(it.toString()) }
- .map(FileHandlingUtils::getCanonicalFile)
- // and because we want directives, we replicate our
- // directive to be applied to that file
- .map { reference ->
- directive.copy(parameters = parameters
- .plus("reference" to reference))
- }
- .toList()
- // we take the result if and only if we have at least one
- // file and we did not filter out any invalid argument
- .takeIf { it.isNotEmpty() && holder.size == it.size }
- // TODO: check exception according to condition
- ?: throw AraraException(
- messages.getMessage(
- Messages.ERROR_VALIDATE_EMPTY_FILES_LIST,
- "(" + directive.lineNumbers
- .joinToString(", ") + ")"
- )
- )
- } else {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_VALIDATE_FILES_IS_NOT_A_LIST,
- "(" + directive.lineNumbers.joinToString(", ") + ")"
- )
- )
- }
- }
-
- /**
- * Validates the list of directives, returning a new list.
- *
- * @param directives The list of directives.
- * @return A new list of directives.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun process(directives: List<Directive>): List<Directive> {
- val result = mutableListOf<Directive>()
- directives.forEach { directive ->
- val parameters = directive.parameters
-
- if (parameters.containsKey("reference"))
- throw AraraException(messages.getMessage(
- Messages.ERROR_VALIDATE_REFERENCE_IS_RESERVED,
- "(" + directive.lineNumbers.joinToString(", ") + ")"))
-
- if (parameters.containsKey("files")) {
- result.addAll(replicateDirective(parameters.getValue("files"),
- parameters.minus("files"), directive))
- } else {
- result.add(directive.copy(parameters = parameters
- .plus("reference" to
- Arara.config[AraraSpec.Execution.reference])))
- }
- }
-
- logger.info(messages.getMessage(
- Messages.LOG_INFO_VALIDATED_DIRECTIVES))
- logger.info(DisplayUtils.displayOutputSeparator(
- messages.getMessage(Messages.LOG_INFO_DIRECTIVES_BLOCK)))
- result.forEach { logger.info(it.toString()) }
- logger.info(DisplayUtils.displaySeparator())
-
- return result
- }
-
- /**
- * Checks if the provided line contains the corresponding pattern, based on
- * the file type, or an empty line.
- *
- * @param pattern Pattern to be matched, based on the file type.
- * @param line Provided line.
- * @return Logical value indicating if the provided line contains the
- * corresponding pattern, based on the file type, or an empty line.
- */
- private fun checkLinePattern(pattern: Pattern, line: String): Boolean {
- return line.isBlank() || pattern.matcher(line).find()
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Rule.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Rule.kt
deleted file mode 100644
index 53ac2aa8b1..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/Rule.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import kotlinx.serialization.Serializable
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements the rule model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-class Rule {
- /**
- * The rule identifier
- */
- var identifier: String = INVALID_RULE_IDENTIFIER
- get() = CommonUtils.removeKeywordNotNull(field)
-
- /**
- * The rule name
- */
- var name: String = INVALID_RULE_NAME
- get() = CommonUtils.removeKeywordNotNull(field)
-
- /**
- * The list of authors
- */
- var authors: List<String> = listOf()
- get() = field.mapNotNull { CommonUtils.removeKeyword(it) }
-
- /**
- * The list of commands
- */
- var commands: List<RuleCommand> = listOf()
-
- /**
- * The list of arguments
- */
- var arguments: List<Argument> = listOf()
-
- companion object {
- const val INVALID_RULE_IDENTIFIER = "INVALID_RULE"
- const val INVALID_RULE_NAME = "INVALID_RULE"
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleCommand.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleCommand.kt
deleted file mode 100644
index 901718d412..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleCommand.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import kotlinx.serialization.Serializable
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements the rule command model.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-@Serializable
-class RuleCommand {
- /**
- * The command name
- */
- var name: String? = null
- get() = CommonUtils.removeKeyword(field)
-
- /**
- * The command instruction
- */
- var command: String? = null
- get() = CommonUtils.removeKeyword(field)
-
- /**
- * The exit status expression
- */
- var exit: String? = null
- get() = CommonUtils.removeKeyword(field)
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleUtils.kt
deleted file mode 100644
index e823e4e598..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/ruleset/RuleUtils.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.ruleset
-
-import com.charleskorn.kaml.Yaml
-import java.io.File
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.utils.CommonUtils
-
-/**
- * Implements rule utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object RuleUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Parses the provided file, checks the identifier and returns a rule
- * representation.
- *
- * @param file The rule file.
- * @param identifier The directive identifier.
- * @return The rule object.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun parseRule(file: File, identifier: String): Rule {
- val rule = file.runCatching {
- val text = readText()
- if (!text.startsWith("!config"))
- throw Exception("Rule should start with !config")
- Yaml.default.parse(Rule.serializer(), text)
- }.getOrElse {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_PARSERULE_GENERIC_ERROR
- ), it)
- }
-
- validateHeader(rule, identifier)
- validateBody(rule)
- return rule
- }
-
- /**
- * Validates the rule header according to the directive identifier.
- *
- * @param rule The rule object.
- * @param identifier The directive identifier.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- @Suppress("ThrowsCount")
- private fun validateHeader(rule: Rule, identifier: String) {
- if (rule.identifier != Rule.INVALID_RULE_IDENTIFIER) {
- if (rule.identifier != identifier) {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(
- Messages.ERROR_VALIDATEHEADER_WRONG_IDENTIFIER,
- rule.identifier,
- identifier))
- }
- } else {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(Messages.ERROR_VALIDATEHEADER_NULL_ID))
- }
- if (rule.name == Rule.INVALID_RULE_NAME) {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_VALIDATEHEADER_NULL_NAME
- )
- )
- }
- }
-
- /**
- * Validates the rule body.
- *
- * @param rule The rule object.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- @Suppress("ThrowsCount")
- private fun validateBody(rule: Rule) {
- if (rule.commands.any { it.command == null }) {
- throw AraraException(CommonUtils.ruleErrorHeader +
- messages.getMessage(
- Messages.ERROR_VALIDATEBODY_NULL_COMMAND))
- }
-
- val arguments = mutableListOf<String>()
- for (argument in rule.arguments) {
- if (argument.identifier != null) {
- if (argument.flag != null || argument.default != null) {
- arguments.add(argument.identifier!!)
- } else {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_VALIDATEBODY_MISSING_KEYS
- )
- )
- }
- } else {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_VALIDATEBODY_NULL_ARGUMENT_ID
- )
- )
- }
- }
-
- arguments.intersect(listOf("files", "reference")).forEach {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_VALIDATEBODY_ARGUMENT_ID_IS_RESERVED,
- it
- )
- )
- }
-
- val expected = arguments.size
- val found = arguments.toSet().size
- if (expected != found) {
- throw AraraException(
- CommonUtils.ruleErrorHeader + messages.getMessage(
- Messages.ERROR_VALIDATEBODY_DUPLICATE_ARGUMENT_IDENTIFIERS
- )
- )
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/ClassLoadingUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/ClassLoadingUtils.kt
deleted file mode 100644
index 05a1031a8a..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/ClassLoadingUtils.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import java.io.File
-import java.lang.reflect.InvocationTargetException
-import java.net.MalformedURLException
-import java.net.URLClassLoader
-
-/**
- * Implements utilitary methods for classloading and object instantiation.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object ClassLoadingUtils {
- /**
- * Indicator of success or failure of class loading.
- */
- enum class ClassLoadingStatus {
- SUCCESS,
- FILE_NOT_FOUND,
- MALFORMED_URL,
- CLASS_NOT_FOUND,
- ILLEGAL_ACCESS,
- INSTANTIATION_EXCEPTION
- }
-
- /**
- * Loads a class from the provided file, potentially a Java archive.
- * @param file File containing the Java bytecode (namely, a JAR).
- * @param name The canonical name of the class.
- * @return A pair representing the status and the class.
- */
- fun loadClass(file: File, name: String):
- Pair<ClassLoadingStatus, Class<*>> {
- // status and class to be returned,
- // it defaults to an object class
- var value: Class<*> = Any::class.java
-
- // if file does not exist, nothing
- // can be done, status is changed
- val status = if (!file.exists()) {
- ClassLoadingStatus.FILE_NOT_FOUND
- } else {
- // classloading involves defining
- // a classloader and fetching the
- // desired class from it, based on
- // the provided file archive
- try {
- // creates a new classloader with
- // the provided file (potentially
- // a JAR file)
- val classloader = URLClassLoader(arrayOf(file.toURI().toURL()),
- ClassLoadingUtils::class.java.classLoader)
-
- // fetches the class from the
- // instantiated classloader
- value = Class.forName(name, true, classloader)
- ClassLoadingStatus.SUCCESS
- } catch (_: MalformedURLException) {
- ClassLoadingStatus.MALFORMED_URL
- } catch (_: ClassNotFoundException) {
- ClassLoadingStatus.CLASS_NOT_FOUND
- }
- }
-
- // return a new pair based on the
- // current status and class holder
- return status to value
- }
-
- /**
- * Loads a class from the provided file, instantiating it.
- * @param file File containing the Java bytecode (namely, a JAR).
- * @param name The canonical name of the class.
- * @return A pair representing the status and the class object.
- */
- fun loadObject(file: File, name: String): Pair<ClassLoadingStatus, Any> {
- // load the corresponding class
- // based on the qualified name
- val pair = loadClass(file, name)
-
- // status and object to be returned,
- // it defaults to an object
- var status = pair.first
- var value = Any()
-
- // checks if the class actually
- // exists, otherwise simply
- // ignore instantiation
- if (status == ClassLoadingStatus.SUCCESS) {
- // object instantiation relies
- // on the default constructor
- // (without arguments), class
- // must implement it
-
- // OBS: constructors with arguments
- // must be invoked through reflection
- try {
- // get the class reference from
- // the pair and instantiate it
- // by invoking the default
- // constructor (without arguments)
- value = pair.second.getDeclaredConstructor().newInstance()
- } catch (_: IllegalAccessException) {
- status = ClassLoadingStatus.ILLEGAL_ACCESS
- } catch (_: InstantiationException) {
- // the user wanted to instantiate an abstract class
- status = ClassLoadingStatus.INSTANTIATION_EXCEPTION
- } catch (_: InvocationTargetException) {
- // the underlying constructor caused an exception
- status = ClassLoadingStatus.INSTANTIATION_EXCEPTION
- }
- }
-
- // return a new pair based on the
- // current status and object holder
- return status to value
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/CommonUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/CommonUtils.kt
deleted file mode 100644
index 6887cd4e84..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/CommonUtils.kt
+++ /dev/null
@@ -1,422 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import java.io.File
-import java.io.IOException
-import java.util.MissingFormatArgumentException
-import java.util.regex.Pattern
-import kotlin.math.ln
-import kotlin.math.pow
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.filehandling.FileHandlingUtils
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.ruleset.Argument
-
-/**
- * Implements common utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object CommonUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- /**
- * Gets the list of file types as string, in order.
- *
- * @return A string representation of the list of file types, in order.
- */
- val fileTypesList: String
- get() = "[ " + Arara.config[AraraSpec.Execution.fileTypes]
- .joinToString(" | ") + " ]"
-
- /**
- * Gets the rule error header, containing the identifier and the path, if
- * any.
- *
- * @return A string representation of the rule error header, containing the
- * identifier and the path, if any.
- */
- val ruleErrorHeader: String
- get() {
- return if (Arara.config[AraraSpec.Execution.InfoSpec.ruleId] != null &&
- Arara.config[AraraSpec.Execution.InfoSpec.rulePath] != null) {
- val id = Arara.config[AraraSpec.Execution.InfoSpec.ruleId]!!
- val path = Arara.config[AraraSpec.Execution.InfoSpec.rulePath]!!
- messages.getMessage(
- Messages.ERROR_RULE_IDENTIFIER_AND_PATH,
- id,
- path
- ) + " "
- } else {
- ""
- }
- }
-
- /**
- * Gets a list of all rule paths.
- *
- * @return A list of all rule paths.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- val allRulePaths: List<String>
- @Throws(AraraException::class)
- get() = Arara.config[AraraSpec.Execution.rulePaths].map {
- val location = File(InterpreterUtils.construct(it, "quack"))
- FileHandlingUtils.getParentCanonicalPath(location)
- }
-
- /**
- * Returns the exit status of the application.
- *
- * @return An integer representing the exit status of the application.
- */
- val exitStatus: Int
- get() = Arara.config[AraraSpec.Execution.status]
-
- /**
- * Gets the preamble content, converting a single string into a list of
- * strings, based on new lines.
- *
- * @return A list of strings representing the preamble content.
- */
- val preambleContent: List<String>
- get() = if (Arara.config[AraraSpec.Execution.preamblesActive]) {
- Arara.config[AraraSpec.Execution.preamblesContent]
- .split("\n")
- .dropLastWhile { it.isEmpty() }
- .toList()
- } else {
- listOf()
- }
-
- /**
- * Checks if the input string is equal to a valid boolean value.
- *
- * @param value The input string.
- * @return A boolean value represented by the provided string.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun checkBoolean(value: String): Boolean {
- val yes = listOf("yes", "true", "1", "on")
- val no = listOf("no", "false", "0", "off")
- return if (!yes.union(no).contains(value.toLowerCase())) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_CHECKBOOLEAN_NOT_VALID_BOOLEAN,
- value
- )
- )
- } else {
- yes.contains(value.toLowerCase())
- }
- }
-
- /**
- * Removes the keyword from the beginning of the provided string.
- *
- * @param line A string to be analyzed.
- * @return The provided string without the keyword.
- */
- fun removeKeyword(line: String?): String? {
- return if (line == null) null
- else removeKeywordNotNull(line)
- }
-
- /**
- * Removes the keyword from the beginning of the provided string.
- *
- * @param line A string to be analyzed.
- * @return The provided string without the keyword.
- */
- fun removeKeywordNotNull(line: String): String {
- var tempLine = line
- val pattern = "^(\\s)*<arara>\\s".toPattern()
- val matcher = pattern.matcher(tempLine)
- if (matcher.find()) {
- tempLine = tempLine.substring(matcher.end())
- }
- return tempLine.trim()
- }
-
- /**
- * Flattens a potential list of lists into a list of objects.
- *
- * @param list The list to be flattened.
- * @return The flattened list.
- */
- // TODO: check nullity
- fun flatten(list: List<*>): List<Any> {
- val result = mutableListOf<Any>()
- list.forEach { item ->
- if (item is List<*>)
- result.addAll(flatten(item))
- else
- result.add(item as Any)
- }
- return result
- }
-
- /**
- * Gets a set of strings containing unknown keys from a map and a list. It
- * is a set difference from the keys in the map and the entries in the list.
- *
- * @param parameters The map of parameters.
- * @param arguments The list of arguments.
- * @return A set of strings representing unknown keys from a map and a list.
- */
- fun getUnknownKeys(
- parameters: Map<String, Any>,
- arguments: List<Argument>
- ): Set<String> {
- val found = parameters.keys
- val expected = arguments.mapNotNull { it.identifier }
- return found.subtract(expected)
- }
-
- /**
- * Gets a human readable representation of a size.
- *
- * @param size The byte size to be converted.
- * @return A string representation of the size.
- */
- @Suppress("MagicNumber")
- fun byteSizeToString(size: Long): String {
- val language = Arara.config[AraraSpec.Execution.language]
- val conversionFactor = 1000.0
- return if (size < conversionFactor) "$size B"
- else
- (ln(size.toDouble()) / ln(conversionFactor)).toInt().let { exp ->
- "%.1f %sB".format(language.locale,
- size / conversionFactor.pow(exp.toDouble()),
- "kMGTPE"[exp - 1])
- }
- }
-
- /**
- * Generates a string based on a list of objects, separating each one of
- * them by one space.
- *
- * @param objects A list of objects.
- * @return A string based on the list of objects, separating each one of
- * them by one space. Empty values are not considered.
- */
- fun generateString(vararg objects: Any): String = objects
- .map { it.toString() }.filter { it.isNotEmpty() }
- .joinToString(" ")
-
- /**
- * Checks if the file based on the provided extension contains the provided
- * regex.
- *
- * @param extension The file extension.
- * @param regex The regex.
- * @return A boolean value indicating if the file contains the provided
- * regex.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun checkRegex(extension: String, regex: String): Boolean {
- val file = File(FileHandlingUtils.getPath(extension))
- return checkRegex(file, regex)
- }
-
- /**
- * Checks if the file contains the provided regex.
- *
- * As we use [File.readText] this should not be called on files > 2GB.
- *
- * @param file The file.
- * @param regex The regex.
- * @return A boolean value indicating if the file contains the provided
- * regex.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun checkRegex(file: File, regex: String): Boolean {
- try {
- val text = file.readText()
- val pattern = Pattern.compile(regex)
- val matcher = pattern.matcher(text)
- return matcher.find()
- } catch (exception: IOException) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_CHECKREGEX_IO_EXCEPTION,
- file.name
- ),
- exception
- )
- }
- }
-
- /**
- * Replicates a string pattern based on a list of objects, generating a list
- * as result.
- *
- * @param pattern The string pattern.
- * @param values The list of objects to be merged with the pattern.
- * @return A list containing the string pattern replicated to each object
- * from the list.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun replicateList(
- pattern: String,
- values: List<Any>
- ): List<Any> {
- return try {
- values.map { String.format(pattern, it) }
- } catch (exception: MissingFormatArgumentException) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_REPLICATELIST_MISSING_FORMAT_ARGUMENTS_EXCEPTION
- ),
- exception
- )
- }
- }
-
- /**
- * Checks if the provided operating system string holds according to the
- * underlying operating system.
- *
- * Supported operating systems:
- *
- * * Windows
- * * Linux
- * * Mac OS X
- * * Unix (Linux || Mac OS)
- * * Cygwin
- *
- * @param value A string representing an operating system.
- * @return A boolean value indicating if the provided string refers to the
- * underlying operating system.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun checkOS(value: String): Boolean {
- fun checkOSProperty(key: String): Boolean =
- getSystemPropertyOrNull("os.name")
- ?.toLowerCase()?.startsWith(key.toLowerCase()) ?: false
-
- val values = mutableMapOf<String, Boolean>()
- values["windows"] = checkOSProperty("Windows")
- values["linux"] = checkOSProperty("Linux")
- values["mac"] = checkOSProperty("Mac OS X")
- values["unix"] = checkOSProperty("Mac OS X") ||
- checkOSProperty("Linux")
- values["cygwin"] = SystemCallUtils["cygwin"] as Boolean
- if (!values.containsKey(value.toLowerCase())) {
- throw AraraException(
- messages.getMessage(
- Messages.ERROR_CHECKOS_INVALID_OPERATING_SYSTEM,
- value
- )
- )
- }
- // will never throw, see check above
- return values.getValue(value.toLowerCase())
- }
-
- /**
- * Gets the system property according to the provided key, or resort to the
- * fallback value if an exception is thrown or if the key is invalid.
- *
- * @param key The system property key.
- * @param fallback The fallback value.
- * @return A string containing the system property value or the fallback.
- */
- fun getSystemProperty(key: String, fallback: String): String =
- System.getProperties().runCatching {
- getOrDefault(key, fallback).toString().takeIf { it != "" }
- }.getOrNull() ?: fallback
-
- /**
- * Access a system property.
- *
- * @param key The key of the property.
- * @return The value of the system property or null if there is an
- * exception.
- */
- fun getSystemPropertyOrNull(key: String): String? =
- System.getProperties().runCatching { getValue(key).toString() }
- .getOrNull()
-
- /**
- * Generates a list of filenames from the provided command based on a list
- * of extensions for each underlying operating system.
- *
- * @param command A string representing the command.
- * @return A list of filenames.
- */
- private fun appendExtensions(command: String): List<String> {
- // list of extensions, specific for
- // each operating system (in fact, it
- // is more Windows specific)
- val extensions = if (checkOS("windows")) {
- // the application is running on
- // Windows, so let's look for the
- // following extensions in order
-
- // this list is actually a sublist from
- // the original Windows PATHEXT environment
- // variable which holds the list of executable
- // extensions that Windows supports
- listOf(".com", ".exe", ".bat", ".cmd")
- } else {
- // no Windows, so the default
- // extension will be just an
- // empty string
- listOf("")
- }
-
- // return the resulting list holding the
- // filenames generated from the
- // provided command
- return extensions.map { "$command$it" }
- }
-
- /**
- * Checks if the provided command name is reachable from the system path.
- *
- * @param command A string representing the command.
- * @return A logic value.
- */
- fun isOnPath(command: String): Boolean {
- // first and foremost, let's build the list
- // of filenames based on the underlying
- // operating system
- val filenames = appendExtensions(command)
- return kotlin.runCatching {
- // break the path into several parts
- // based on the path separator symbol
- System.getenv("PATH").split(File.pathSeparator)
- .asSequence()
- .mapNotNull { File(it).listFiles() }
- // if the search does not return an empty
- // list, one of the filenames got a match,
- // and the command is available somewhere
- // in the system path
- .firstOrNull {
- it.any { file ->
- filenames.contains(file.name) && !file.isDirectory
- }
- }?.let { true }
- }.getOrNull() ?: false
- // otherwise (and in case of an exception) it is not in the path
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/DisplayUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/DisplayUtils.kt
deleted file mode 100644
index 213a9a21c3..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/DisplayUtils.kt
+++ /dev/null
@@ -1,415 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.configuration.ConfigurationUtils
-import org.islandoftex.arara.filehandling.FileHandlingUtils
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.ruleset.Conditional
-import org.slf4j.LoggerFactory
-
-/**
- * Implements display utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object DisplayUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- // get the logger context from a factory
- private val logger = LoggerFactory.getLogger(DisplayUtils::class.java)
-
- /**
- * The length of the longest result match as integer.
- */
- private val longestMatch: Int = listOf(
- messages.getMessage(Messages.INFO_LABEL_ON_SUCCESS),
- messages.getMessage(Messages.INFO_LABEL_ON_FAILURE),
- messages.getMessage(Messages.INFO_LABEL_ON_ERROR))
- .map { it.length }.max()!!
- /**
- * If the longest match is longer than the width, then it will be truncated
- * to this length.
- */
- private const val shortenedLongestMatch = 10
-
- /**
- * The default terminal width defined in the settings.
- */
- private val width: Int
- get() = Arara.config[AraraSpec.Application.width]
-
- /**
- * Checks if the execution is in dry-run mode.
- */
- private val isDryRunMode: Boolean
- get() = Arara.config[AraraSpec.Execution.dryrun]
-
- /**
- * Checks if the execution is in verbose mode.
- */
- private val isVerboseMode: Boolean
- get() = Arara.config[AraraSpec.Execution.verbose]
-
- /**
- * The application path.
- */
- private val applicationPath: String
- get() = try {
- ConfigurationUtils.applicationPath.toString()
- } catch (ae: AraraException) {
- "[unknown application path]"
- }
-
- /**
- * Displays the short version of the current entry in the terminal.
- *
- * @param name Rule name.
- * @param task Task name.
- */
- private fun buildShortEntry(name: String, task: String) {
- val result = if (longestMatch >= width)
- shortenedLongestMatch
- else
- longestMatch
- val space = width - result - 1
- val line = "($name) $task ".abbreviate(space - "... ".length)
- print(line.padEnd(space, '.') + " ")
- }
-
- /**
- * Displays the short version of the current entry result in the terminal.
- *
- * @param value The boolean value to be displayed.
- */
- private fun buildShortResult(value: Boolean) {
- val result = longestMatch
- println(getResult(value).padStart(result))
- }
-
- /**
- * Displays the current entry result in the terminal.
- *
- * @param value The boolean value to be displayed.
- */
- fun printEntryResult(value: Boolean) {
- Arara.config[AraraSpec.UserInteraction.displayLine] = false
- Arara.config[AraraSpec.UserInteraction.displayResult] = true
- Arara.config[AraraSpec.Execution.status] = if (value) 0 else 1
- logger.info(
- messages.getMessage(
- Messages.LOG_INFO_TASK_RESULT
- ) + " " + getResult(value)
- )
- if (!isDryRunMode) {
- if (!isVerboseMode) {
- buildShortResult(value)
- } else {
- buildLongResult(value)
- }
- }
- }
-
- /**
- * Displays a long version of the current entry result in the terminal.
- *
- * @param value The boolean value to be displayed
- */
- private fun buildLongResult(value: Boolean) {
- val width = width
- println("\n" + (" " + getResult(value)).padStart(width, '-'))
- }
-
- /**
- * Displays the current entry in the terminal.
- *
- * @param name The rule name.
- * @param task The task name.
- */
- fun printEntry(name: String, task: String) {
- logger.info(
- messages.getMessage(
- Messages.LOG_INFO_INTERPRET_TASK,
- task,
- name
- )
- )
- Arara.config[AraraSpec.UserInteraction.displayLine] = true
- Arara.config[AraraSpec.UserInteraction.displayResult] = false
- if (!isDryRunMode) {
- if (!isVerboseMode) {
- buildShortEntry(name, task)
- } else {
- buildLongEntry(name, task)
- }
- } else {
- buildDryRunEntry(name, task)
- }
- }
-
- /**
- * Displays a long version of the current entry in the terminal.
- *
- * @param name Rule name.
- * @param task Task name.
- */
- private fun buildLongEntry(name: String, task: String) {
- if (Arara.config[AraraSpec.UserInteraction.displayRolling]) {
- addNewLine()
- } else {
- Arara.config[AraraSpec.UserInteraction.displayRolling] = true
- }
- println(displaySeparator())
- println("($name) $task".abbreviate(width))
- println(displaySeparator())
- }
-
- /**
- * Displays a dry-run version of the current entry in the terminal.
- *
- * @param name The rule name.
- * @param task The task name.
- */
- private fun buildDryRunEntry(name: String, task: String) {
- if (Arara.config[AraraSpec.UserInteraction.displayRolling]) {
- addNewLine()
- } else {
- Arara.config[AraraSpec.UserInteraction.displayRolling] = true
- }
- println("[DR] ($name) $task".abbreviate(width))
- println(displaySeparator())
- }
-
- /**
- * Displays the exception in the terminal.
- *
- * @param exception The exception object.
- */
- fun printException(exception: AraraException) {
- Arara.config[AraraSpec.UserInteraction.displayException] = true
- Arara.config[AraraSpec.Execution.status] = 2
-
- val display = Arara.config[AraraSpec.UserInteraction.displayLine]
- if (Arara.config[AraraSpec.UserInteraction.displayResult])
- addNewLine()
- if (display) {
- if (!isDryRunMode) {
- if (!isVerboseMode) {
- buildShortError()
- } else {
- buildLongError()
- }
- addNewLine()
- }
- }
- val text = (if (exception.hasException())
- exception.message + " " + messages.getMessage(
- Messages.INFO_DISPLAY_EXCEPTION_MORE_DETAILS)
- else
- exception.message) ?: "EXCEPTION PROVIDES NO MESSAGE"
- // TODO: check null handling
- logger.error(text)
- wrapText(text)
- if (exception.hasException()) {
- addNewLine()
- displayDetailsLine()
- val details = exception.exception!!.message!!
- logger.error(details)
- wrapText(details)
- }
- }
-
- /**
- * Gets the string representation of the provided boolean value.
- *
- * @param value The boolean value.
- * @return The string representation.
- */
- private fun getResult(value: Boolean): String {
- return if (value)
- messages.getMessage(
- Messages.INFO_LABEL_ON_SUCCESS
- )
- else
- messages.getMessage(Messages.INFO_LABEL_ON_FAILURE)
- }
-
- /**
- * Displays the short version of an error in the terminal.
- */
- private fun buildShortError() {
- val result = longestMatch
- println(messages.getMessage(Messages.INFO_LABEL_ON_ERROR)
- .padStart(result))
- }
-
- /**
- * Displays the long version of an error in the terminal.
- */
- private fun buildLongError() {
- println((" " + messages.getMessage(Messages.INFO_LABEL_ON_ERROR))
- .padStart(width, '-'))
- }
-
- /**
- * Displays the provided text wrapped nicely according to the default
- * terminal width.
- *
- * @param text The text to be displayed.
- */
- fun wrapText(text: String) = println(text.wrap(width))
-
- /**
- * Displays the rule authors in the terminal.
- *
- * @param authors The list of authors.
- */
- fun printAuthors(authors: List<String>) {
- val line = if (authors.size == 1)
- messages.getMessage(Messages.INFO_LABEL_AUTHOR)
- else
- messages.getMessage(Messages.INFO_LABEL_AUTHORS)
- val text = if (authors.isEmpty())
- messages.getMessage(Messages.INFO_LABEL_NO_AUTHORS)
- else
- authors.joinToString(", ") { it.trim() }
- wrapText("$line $text")
- }
-
- /**
- * Displays the current conditional in the terminal.
- *
- * @param conditional The conditional object.
- */
- fun printConditional(conditional: Conditional) {
- if (conditional.type !== Conditional.ConditionalType.NONE) {
- wrapText(messages.getMessage(Messages.INFO_LABEL_CONDITIONAL) +
- " (" + conditional.type + ") " +
- conditional.condition)
- }
- }
-
- /**
- * Displays the file information in the terminal.
- */
- fun printFileInformation() {
- val file = Arara.config[AraraSpec.Execution.reference]
- val version = Arara.config[AraraSpec.Application.version]
- val line = messages.getMessage(
- Messages.INFO_DISPLAY_FILE_INFORMATION,
- file.name,
- CommonUtils.byteSizeToString(file.length()),
- FileHandlingUtils.getLastModifiedInformation(file)
- )
- logger.info(messages.getMessage(
- Messages.LOG_INFO_WELCOME_MESSAGE,
- version
- ))
- logger.info(displaySeparator())
- logger.debug("::: arara @ $applicationPath")
- logger.debug("::: Java %s, %s".format(
- CommonUtils.getSystemProperty("java.version",
- "[unknown version]"),
- CommonUtils.getSystemProperty("java.vendor",
- "[unknown vendor]")
- ))
- logger.debug("::: %s".format(
- CommonUtils.getSystemProperty("java.home",
- "[unknown location]")
- ))
- logger.debug("::: %s, %s, %s".format(
- CommonUtils.getSystemProperty("os.name",
- "[unknown OS name]"),
- CommonUtils.getSystemProperty("os.arch",
- "[unknown OS arch]"),
- CommonUtils.getSystemProperty("os.version",
- "[unknown OS version]")
- ))
- logger.debug("::: user.home @ %s".format(
- CommonUtils.getSystemProperty("user.home",
- "[unknown user's home directory]")
- ))
- logger.debug("::: CF @ %s".format(Arara.config[AraraSpec.Execution
- .configurationName]))
- logger.debug(displaySeparator())
- logger.info(line)
- wrapText(line)
- addNewLine()
- }
-
- /**
- * Displays the elapsed time in the terminal.
- *
- * @param seconds The elapsed seconds.
- */
- fun printTime(seconds: Double) {
- val language = Arara.config[AraraSpec.Execution.language]
-
- if (Arara.config[AraraSpec.UserInteraction.displayTime]) {
- if (Arara.config[AraraSpec.UserInteraction.displayLine] ||
- Arara.config[AraraSpec.UserInteraction.displayException])
- addNewLine()
-
- val text = messages.getMessage(
- Messages.INFO_DISPLAY_EXECUTION_TIME,
- "%1.2f".format(language.locale, seconds))
- logger.info(text)
- wrapText(text)
- }
- }
-
- /**
- * Displays the application logo in the terminal.
- */
- fun printLogo() {
- println("""
- __ _ _ __ __ _ _ __ __ _
- / _` | '__/ _` | '__/ _` |
- | (_| | | | (_| | | | (_| |
- \__,_|_| \__,_|_| \__,_|
- """.trimIndent())
- addNewLine()
- }
-
- /**
- * Adds a new line in the terminal.
- */
- private fun addNewLine() {
- println()
- }
-
- /**
- * Displays a line containing details.
- */
- private fun displayDetailsLine() {
- val line = messages.getMessage(
- Messages.INFO_LABEL_ON_DETAILS) + " "
- println(line.abbreviate(width).padEnd(width, '-'))
- }
-
- /**
- * Gets the output separator with the provided text.
- *
- * @param message The provided text.
- * @return A string containing the output separator with the provided text.
- */
- fun displayOutputSeparator(message: String): String {
- return " $message ".center(width, '-')
- }
-
- /**
- * Gets the line separator.
- *
- * @return A string containing the line separator.
- */
- fun displaySeparator(): String {
- return "-".repeat(width)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/Extensions.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/Extensions.kt
deleted file mode 100644
index 10ace0b7f1..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/Extensions.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import kotlin.math.ceil
-
-/**
- * Abbreviate a String to a maximal width.
- *
- * @param maxWidth The maximal width to truncate to.
- * @param ellipsis The string to use to indicate an ellipsis.
- * @throws IllegalArgumentException If the string would consist only of the
- * ellipsis after shortening.
- * @return The abbreviated string.
- */
-@Throws(IllegalArgumentException::class)
-fun String.abbreviate(maxWidth: Int, ellipsis: String = "…"): String {
- return when {
- maxWidth < ellipsis.length + 1 ->
- throw IllegalArgumentException("Can't abbreviate text further")
- this.length < maxWidth -> this
- else -> this.substring(0, maxWidth - ellipsis.length) + ellipsis
- }
-}
-
-/**
- * Center a string within a specified number of columns.
- *
- * This does not center anything if the string is longer than the specified
- * width.
- *
- * @param width The number of columns.
- * @param padChar The char to pad with.
- * @return The padded string.
- */
-fun String.center(width: Int, padChar: Char): String {
- return if (this.length > width) this
- else {
- val charsLeft = width - this.length
- padChar.toString().repeat(charsLeft / 2) + this +
- padChar.toString().repeat(ceil(charsLeft.toDouble() / 2.0).toInt())
- }
-}
-
-/**
- * Wrap text at a specified width.
- *
- * Algorithm from Wikipedia:
- * https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Minimum_number_of_lines
- *
- * @param width The width to wrap at.
- * @return Wrapped text.
- */
-fun String.wrap(width: Int): String {
- val words = this.split(" ")
- var wrapped = words[0]
- var spaceLeft = width - wrapped.length
- words.drop(1).forEach {
- val len = it.length
- wrapped += if (len + 1 > spaceLeft) {
- spaceLeft = width - len
- "\n$it"
- } else {
- spaceLeft -= len + 1
- " $it"
- }
- }
- return wrapped
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/InterpreterUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/InterpreterUtils.kt
deleted file mode 100644
index 00313a7714..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/InterpreterUtils.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.io.IOException
-import java.io.OutputStream
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import kotlin.time.Duration
-import kotlin.time.ExperimentalTime
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.islandoftex.arara.localization.LanguageController
-import org.islandoftex.arara.localization.Messages
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.ruleset.Command
-import org.islandoftex.arara.ruleset.Conditional
-import org.slf4j.LoggerFactory
-import org.zeroturnaround.exec.InvalidExitValueException
-import org.zeroturnaround.exec.ProcessExecutor
-import org.zeroturnaround.exec.listener.ShutdownHookProcessDestroyer
-
-/**
- * Implements interpreter utilitary methods.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object InterpreterUtils {
- // the application messages obtained from the
- // language controller
- private val messages = LanguageController
-
- // get the logger context from a factory
- private val logger = LoggerFactory.getLogger(InterpreterUtils::class.java)
-
- /**
- * Checks if the current conditional has a prior evaluation.
- *
- * @param conditional The current conditional object.
- * @return A boolean value indicating if the current conditional has a prior
- * evaluation.
- */
- fun runPriorEvaluation(conditional: Conditional): Boolean {
- return if (Arara.config[AraraSpec.Execution.dryrun]) {
- false
- } else {
- when (conditional.type) {
- Conditional.ConditionalType.IF,
- Conditional.ConditionalType.WHILE,
- Conditional.ConditionalType.UNLESS -> true
- else -> false
- }
- }
- }
-
- @ExperimentalTime
- private fun getProcessExecutorForCommand(
- command: Command,
- buffer: OutputStream
- ):
- ProcessExecutor {
- val timeOutValue = Arara.config[AraraSpec.Execution.timeoutValue]
- var executor = ProcessExecutor().command((command).elements)
- .directory(command.workingDirectory.absoluteFile)
- .addDestroyer(ShutdownHookProcessDestroyer())
- if (Arara.config[AraraSpec.Execution.timeout]) {
- if (timeOutValue == Duration.ZERO) {
- throw AraraException(messages.getMessage(Messages
- .ERROR_RUN_TIMEOUT_INVALID_RANGE))
- }
- executor = executor.timeout(timeOutValue.toLongNanoseconds(),
- TimeUnit.NANOSECONDS)
- }
- val tee = if (Arara.config[AraraSpec.Execution.verbose]) {
- executor = executor.redirectInput(System.`in`)
- TeeOutputStream(System.out, buffer)
- } else {
- TeeOutputStream(buffer)
- }
- executor = executor.redirectOutput(tee).redirectError(tee)
- return executor
- }
-
- /**
- * Runs the command in the underlying operating system.
- *
- * @param command An object representing the command.
- * @return An integer value representing the exit code.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @ExperimentalTime
- @Throws(AraraException::class)
- fun run(command: Command): Int {
- val buffer = ByteArrayOutputStream()
- val executor = getProcessExecutorForCommand(command, buffer)
- return executor.runCatching {
- val exit = execute().exitValue
- logger.info(DisplayUtils.displayOutputSeparator(
- messages.getMessage(Messages.LOG_INFO_BEGIN_BUFFER)))
- logger.info(buffer.toString())
- logger.info(DisplayUtils.displayOutputSeparator(
- messages.getMessage(Messages.LOG_INFO_END_BUFFER)))
- exit
- }.getOrElse {
- throw AraraException(messages.getMessage(
- when (it) {
- is IOException -> Messages.ERROR_RUN_IO_EXCEPTION
- is InterruptedException ->
- Messages.ERROR_RUN_INTERRUPTED_EXCEPTION
- is InvalidExitValueException ->
- Messages.ERROR_RUN_INVALID_EXIT_VALUE_EXCEPTION
- is TimeoutException ->
- Messages.ERROR_RUN_TIMEOUT_EXCEPTION
- else -> Messages.ERROR_RUN_GENERIC_EXCEPTION
- }), it)
- }
- }
-
- /**
- * Builds the rule path based on the rule name and returns the corresponding
- * file location.
- *
- * @param name The rule name.
- * @return The rule file.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun buildRulePath(name: String): File? {
- Arara.config[AraraSpec.Execution.rulePaths].forEach { path ->
- val location = File(construct(path, name))
- if (location.exists())
- return location
- }
- return null
- }
-
- /**
- * Constructs the path given the current path and the rule name.
- *
- * @param path The current path.
- * @param name The rule name.
- * @return The constructed path.
- * @throws AraraException Something wrong happened, to be caught in the
- * higher levels.
- */
- @Throws(AraraException::class)
- fun construct(path: String, name: String): String {
- val fileName = "$name.yaml"
- val location = File(path)
- return if (location.isAbsolute) {
- location.resolve(fileName).toString()
- } else {
- Arara.config[AraraSpec.Execution.workingDirectory]
- // first resolve the path (rule path) against the working
- // directory, then the rule name we want to resolve
- .resolve(path).resolve(fileName).toAbsolutePath().toString()
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/LoggingUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/LoggingUtils.kt
deleted file mode 100644
index f9719fa31f..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/LoggingUtils.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import ch.qos.logback.classic.LoggerContext
-import ch.qos.logback.classic.joran.JoranConfigurator
-import ch.qos.logback.core.joran.spi.JoranException
-import java.io.InputStream
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-import org.slf4j.LoggerFactory
-
-/**
- * Implements the logging controller. This class actually sets the logging
- * configuration in order to allow appending results to a file.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object LoggingUtils {
- // configuration resource as an input stream
- // the configuration is actually a XML file.
- private val resource: InputStream by lazy {
- LoggingUtils::class.java
- .getResourceAsStream("/org/islandoftex/arara/configuration/logback.xml")
- }
-
- /**
- * Sets the logging configuration according to the provided boolean value.
- * If the value is set to true, the log entries will be appended to a file,
- * otherwise the logging feature will keep silent.
- * @param enable A boolean value that indicates the logging behaviour
- * throughout the application.
- */
- fun enableLogging(enable: Boolean) {
- // get the logger context from a factory, set a
- // new context and reset it
- val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext
-
- try {
- // get a new configuration and set
- // the context
- val configurator = JoranConfigurator()
- configurator.context = loggerContext
- loggerContext.reset()
-
- // if enabled, the log entries will be
- // appended to a file, otherwise it will
- // remain silent
- if (enable) {
- // set the file name and configure
- // the logging controller to append
- // entries to the file
- val name = Arara.config[AraraSpec.Execution.logName]
- loggerContext.putProperty("name", name)
- configurator.doConfigure(resource)
- }
- } catch (_: JoranException) {
- // quack, quack, quack!
- }
- }
-
- /**
- * Initializes the logging controller by disabling it. I don't want an odd
- * behaviour out of the box.
- */
- fun init() {
- enableLogging(false)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/MessageUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/MessageUtils.kt
deleted file mode 100644
index ae695c44fb..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/MessageUtils.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import javax.swing.JOptionPane
-import javax.swing.UIManager
-import org.islandoftex.arara.Arara
-import org.islandoftex.arara.configuration.AraraSpec
-
-/**
- * Implements utilitary methods for displaying messages.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object MessageUtils {
- // holds the default width for the
- // message body, in pixels
- private const val WIDTH = 250
-
- // let's start the UI manager and set
- // the default look and feel to be as
- // close as possible to the system
- init {
- // get the current look and feel
- var laf = Arara.config[AraraSpec.UserInteraction.lookAndFeel]
-
- // check if one is actually set
- if (laf != "none") {
- // use a special keyword to indicate
- // the use of a system look and feel
- if (laf == "system") {
- laf = UIManager.getSystemLookAndFeelClassName()
- }
-
- // let's try it, in case it fails,
- // rely to the default look and feel
- try {
- // get the system look and feel name
- // and try to set it as default
- UIManager.setLookAndFeel(laf)
- } catch (_: Exception) {
- // quack, quack, quack
- }
- }
- }
-
- /**
- * Normalizes the icon type to one of the five available icons.
- * @param value An integer value.
- * @return The normalized integer value.
- */
- @Suppress("MagicNumber")
- private fun normalizeIconType(value: Int): Int {
- // do the normalization according to the available
- // icons in the underlying message implementation
- return when (value) {
- 1 -> JOptionPane.ERROR_MESSAGE
- 2 -> JOptionPane.INFORMATION_MESSAGE
- 3 -> JOptionPane.WARNING_MESSAGE
- 4 -> JOptionPane.QUESTION_MESSAGE
- else -> JOptionPane.PLAIN_MESSAGE
- }
- }
-
- /**
- * Normalizes the message width, so only valid nonzero values are accepted.
- * @param value An integer value corresponding to the message width.
- * @return The normalized width.
- */
- private fun normalizeMessageWidth(value: Int): Int {
- return if (value > 0) value else WIDTH
- }
-
- /**
- * Shows the message.
- * @param width Integer value, in pixels.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- */
- fun showMessage(
- width: Int,
- type: Int,
- title: String,
- text: String
- ) {
- // effectively shows the message based
- // on the provided parameters
- JOptionPane.showMessageDialog(null,
- String.format(
- "<html><body style=\"width:%dpx\">%s</body></html>",
- normalizeMessageWidth(width),
- text),
- title,
- normalizeIconType(type)
- )
- }
-
- /**
- * Shows the message. It relies on the default width.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- */
- fun showMessage(type: Int, title: String, text: String) {
- showMessage(WIDTH, type, title, text)
- }
-
- /**
- * Shows a message with options presented as an array of buttons.
- * @param width Integer value, in pixels.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @param buttons An array of objects to be presented as buttons.
- * @return The index of the selected button, starting from 1.
- */
- fun showOptions(
- width: Int,
- type: Int,
- title: String,
- text: String,
- vararg buttons: Any
- ): Int {
- // returns the index of the selected button,
- // zero if nothing is selected
- return JOptionPane.showOptionDialog(null,
- String.format(
- "<html><body style=\"width:%dpx\">%s</body></html>",
- normalizeMessageWidth(width),
- text),
- title,
- JOptionPane.DEFAULT_OPTION,
- normalizeIconType(type), null,
- buttons,
- buttons[0]
- ) + 1
- }
-
- /**
- * Shows a message with options presented as an array of buttons. It relies
- * on the default width.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @param buttons An array of objects to be presented as buttons.
- * @return The index of the selected button, starting from 1.
- */
- @Suppress("SpreadOperator")
- fun showOptions(
- type: Int,
- title: String,
- text: String,
- vararg buttons: Any
- ): Int {
- return showOptions(WIDTH, type, title, text, *buttons)
- }
-
- /**
- * Shows a message with a text input.
- * @param width Integer value, in pixels.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @return The string representing the input text.
- */
- fun showInput(
- width: Int,
- type: Int,
- title: String,
- text: String
- ): String {
- // get the string from the
- // input text, if any
- val input = JOptionPane.showInputDialog(null,
- String.format(
- "<html><body style=\"width:%dpx\">%s</body></html>",
- normalizeMessageWidth(width),
- text),
- title,
- normalizeIconType(type))
-
- // if the input is not null, that is,
- // the user actually typed something
- // return the trimmed string otherwise
- // an empty string
- return input?.trim() ?: ""
- }
-
- /**
- * Shows a message with a text input. It relies on the default width.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @return The string representing the input text.
- */
- fun showInput(type: Int, title: String, text: String): String {
- return showInput(WIDTH, type, title, text)
- }
-
- /**
- * Shows a message with options presented as a dropdown list of elements.
- * @param width Integer value, in pixels.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @param elements An array of objects representing the elements.
- * @return The index of the selected element, starting from 1.
- */
- fun showDropdown(
- width: Int,
- type: Int,
- title: String,
- text: String,
- vararg elements: Any
- ): Int {
- // show the dropdown list and get
- // the selected object, if any
- val index = JOptionPane.showInputDialog(null,
- String.format(
- "<html><body style=\"width:%dpx\">%s</body></html>",
- normalizeMessageWidth(width),
- text),
- title,
- normalizeIconType(type), null,
- elements,
- elements[0])
-
- // if it's not a null object, let's
- // find the corresponding index
- if (index != null) {
- elements.forEachIndexed { i, value ->
- // if the element is found, simply
- // return the index plus 1, as zero
- // corresponds to no selection at all
- if (value == index) {
- return i + 1
- }
- }
- }
-
- // nothing was selected,
- // simply return zero
- return 0
- }
-
- /**
- * Shows a message with options presented as a dropdown list of elements. It
- * relies on the default width.
- * @param type Type of message.
- * @param title Title of the message.
- * @param text Text of the message.
- * @param elements An array of objects representing the elements.
- * @return The index of the selected element, starting from 1.
- */
- @Suppress("SpreadOperator")
- fun showDropdown(
- type: Int,
- title: String,
- text: String,
- vararg elements: Any
- ): Int {
- return showDropdown(WIDTH, type, title, text, *elements)
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/SystemCallUtils.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/SystemCallUtils.kt
deleted file mode 100644
index 9b443736a1..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/SystemCallUtils.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import org.islandoftex.arara.model.AraraException
-import org.islandoftex.arara.ruleset.Command
-import org.zeroturnaround.exec.ProcessExecutor
-
-/**
- * Implements a system call controller.
- *
- * This class wraps a map that holds the result of system specific variables
- * not directly available at runtime and makes unsafe calling of system
- * commands available to rules.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-object SystemCallUtils {
- /**
- * When executing a system call goes wrong, this status code is returned.
- */
- const val errorExitStatus = -99
- /**
- * When executing a system call goes wrong and the caller asked for output,
- * this output will be returned.
- */
- const val errorCommandOutput = ""
-
- // the system call map which holds the result of
- // system specific variables not directly available
- // at runtime; the idea here is to provide wrappers
- // to the map getter, so it could be easily manipulated
- // create the new map instance to be
- // populated on demand
- private val map: MutableMap<String, Any> = mutableMapOf()
-
- // the commands map will allow the system call map being
- // populated only on demand, that is, if the key is not
- // found, this map will provide the corresponding method
- // and update the value
- // create the new map of commands and
- // add the corresponding system calls
- private val commands: MutableMap<String, () -> Any> = mutableMapOf(
- "cygwin" to {
- // Implements the body of the command. In this particular
- // instance, it checks if we are inside a Cygwin environment.
- // Returns a boolean value indicating if we are inside a Cygwin
- // environment.
-
- // execute a new system call to 'uname -s', read the output
- // as an UTF-8 string, lowercase it and check if it starts
- // with the 'cygwin' string; if so, we are inside Cygwin
- executeSystemCommand(Command("uname", "-s"))
- .second.toLowerCase().startsWith("cygwin")
- })
-
- /**
- * Gets the object indexed by the provided key. This method actually holds
- * the map method of the very same name.
- *
- * @param key The provided map key.
- * @return The object indexed by the provided map key.
- */
- @Throws(NoSuchElementException::class, AraraException::class)
- operator fun get(key: String): Any {
- // if key is not found, meaning that
- // the value wasn't required before
- if (!map.containsKey(key)) {
- if (commands.containsKey(key))
- // perform the system call and
- // populate the corresponding value
- map[key] = commands[key]!!.invoke()
- else
- throw AraraException("The requested key could not be " +
- "translated into a command to get the call value.")
- }
-
- // simply return the corresponding
- // value based on the provided key
- return map.getValue(key)
- }
-
- /**
- * Executes a system command from the underlying operating system and
- * returns a pair containing the exit status and the command output as a
- * string.
- * @param command The system command to be executed.
- * @return A pair containing the exit status and the system command output
- * as a string.
- */
- fun executeSystemCommand(command: Command): Pair<Int, String> {
- return ProcessExecutor(command.elements).runCatching {
- directory(command.workingDirectory)
- readOutput(true)
- execute().run {
- exitValue to outputUTF8()
- }
- }.getOrElse {
- // quack, quack, do nothing, just
- // return a default error code
- errorExitStatus to errorCommandOutput
- }
- }
-}
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/TeeOutputStream.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/TeeOutputStream.kt
deleted file mode 100644
index dee15176f2..0000000000
--- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/utils/TeeOutputStream.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.arara.utils
-
-import java.io.IOException
-import java.io.OutputStream
-
-/**
- * Implements a stream splitter.
- *
- * @author Island of TeX
- * @version 5.0
- * @since 4.0
- */
-class TeeOutputStream(
- /**
- * The array of output streams holds every output stream that will be
- * written to.
- */
- vararg outputStreams: OutputStream
-) : OutputStream() {
- /**
- * An array of streams in which an object of this class will split data.
- */
- private val streams: List<OutputStream> = outputStreams.toList()
-
- /**
- * Writes the provided integer to each stream.
- *
- * @param b The provided integer
- * @throws IOException An IO exception.
- */
- @Throws(IOException::class)
- override fun write(b: Int) = streams.forEach { it.write(b) }
-
- /**
- * Writes the provided byte array to each stream, with the provided offset
- * and length.
- *
- * @param b The byte array.
- * @param offset The offset.
- * @param length The length.
- * @throws IOException An IO exception.
- */
- @Throws(IOException::class)
- override fun write(b: ByteArray, offset: Int, length: Int) =
- streams.forEach { it.write(b, offset, length) }
-
- /**
- * Flushes every stream.
- *
- * @throws IOException An IO exception.
- */
- @Throws(IOException::class)
- override fun flush() = streams.forEach { it.flush() }
-
- /**
- * Closes every stream silently.
- */
- override fun close() = streams.forEach {
- try {
- it.close()
- } catch (ignored: IOException) {
- // do nothing on purpose
- }
- }
-}