-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: cron compatibility to unix standard - 5 tokens (#3)
* chore: fix cronexp to more standart version * chore: readme * chore: scope * chore: naming * chore: bump junit * chore: bump junit * chore: refactoring and naming
- Loading branch information
1 parent
211b2c7
commit c9c1a27
Showing
41 changed files
with
1,362 additions
and
1,598 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/main/kotlin/io/github/yamilmedina/kron/ExpressionElementProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package io.github.yamilmedina.kron | ||
|
||
internal interface ExpressionElementProvider { | ||
/** | ||
* @param string | ||
* @return Boolean | ||
*/ | ||
fun matches(string: String): Boolean | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun canProvideMinute(): Boolean | ||
|
||
/** | ||
* @return String | ||
*/ | ||
fun getMinuteElement(): String? | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun isMinuteElementLocked(): Boolean | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun canProvideHour(): Boolean | ||
|
||
/** | ||
* @return String | ||
*/ | ||
fun getHourElement(): String? | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun isHourElementLocked(): Boolean | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun canProvideDayNumber(): Boolean | ||
|
||
/** | ||
* @return String | ||
*/ | ||
fun getDayNumberElement(): String? | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun isDayNumberElementLocked(): Boolean | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun canProvideMonth(): Boolean | ||
|
||
/** | ||
* @return String | ||
*/ | ||
fun getMonthElement(): String? | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun isMonthElementLocked(): Boolean | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun canProvideDayOfWeek(): Boolean | ||
|
||
/** | ||
* @return String | ||
*/ | ||
fun getDayOfWeekElement(): String? | ||
|
||
/** | ||
* @return Boolean | ||
*/ | ||
fun isDayOfWeekElementLocked(): Boolean | ||
} | ||
|
||
|
57 changes: 57 additions & 0 deletions
57
src/main/kotlin/io/github/yamilmedina/kron/KronExpression.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package io.github.yamilmedina.kron | ||
|
||
class KronExpression( | ||
var minute: String? = null, | ||
var hour: String? = null, | ||
var dayNumber: String? = null, | ||
var month: String? = null, | ||
var dayOfWeek: String? = null | ||
) { | ||
|
||
fun hasMinute(): Boolean = minute != null | ||
|
||
fun setMinute(minute: String): KronExpression { | ||
this.minute = minute | ||
return this | ||
} | ||
|
||
fun hasHour(): Boolean = hour != null | ||
|
||
fun setHour(hour: String): KronExpression { | ||
this.hour = hour | ||
return this | ||
} | ||
|
||
fun hasDayNumber(): Boolean = dayNumber != null | ||
|
||
fun setDayNumber(dayNumber: String): KronExpression { | ||
this.dayNumber = dayNumber | ||
return this | ||
} | ||
|
||
fun hasMonth(): Boolean = month != null | ||
|
||
fun setMonth(month: String): KronExpression { | ||
this.month = month | ||
return this | ||
} | ||
|
||
fun hasDayOfWeek(): Boolean = dayOfWeek != null | ||
|
||
fun setDayOfWeek(dayOfWeek: String): KronExpression { | ||
this.dayOfWeek = dayOfWeek | ||
return this | ||
} | ||
|
||
fun hasNothing(): Boolean = !hasMinute() && !hasHour() && !hasDayNumber() && !hasMonth() && !hasDayOfWeek() | ||
|
||
override fun toString(): String = "%s %s %s %s %s".format( | ||
if (hasMinute()) minute else "0", | ||
if (hasHour()) hour else "0", | ||
if (hasDayNumber()) dayNumber else "*", | ||
if (hasMonth()) month else "*", | ||
if (hasDayOfWeek()) dayOfWeek else "*" | ||
) | ||
} | ||
|
||
|
172 changes: 172 additions & 0 deletions
172
src/main/kotlin/io/github/yamilmedina/kron/NaturalKronParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package io.github.yamilmedina.kron | ||
|
||
import io.github.yamilmedina.kron.elementprovider.DayNumber | ||
import io.github.yamilmedina.kron.elementprovider.hour.Base12Hour | ||
import io.github.yamilmedina.kron.elementprovider.hour.Base12HourShort | ||
import io.github.yamilmedina.kron.elementprovider.hour.Base24Hour | ||
import io.github.yamilmedina.kron.elementprovider.hour.Midnight | ||
import io.github.yamilmedina.kron.elementprovider.hour.Noon | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryDay | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryDayNumber | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryHour | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryMinute | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryMonth | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryWeek | ||
import io.github.yamilmedina.kron.elementprovider.recurring.EveryYear | ||
import java.text.ParseException | ||
import java.util.regex.Pattern | ||
|
||
class NaturalKronParser { | ||
|
||
companion object { | ||
const val VALID_PATTERN = | ||
"^(@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly|((?:[1-9]?\\d|\\*)\\s*(?:(?:[\\/\\-][1-9]?\\d)|(?:,[1-9]?\\d)+)?\\s*){5})$" | ||
} | ||
|
||
private val elementProviders: List<ExpressionElementProvider> = listOf( | ||
EveryYear(), | ||
EveryMonth(), | ||
EveryWeek(), | ||
EveryDayNumber(), | ||
EveryDay(), | ||
EveryHour(), | ||
EveryMinute(), | ||
DayNumber(), | ||
Noon(), | ||
Midnight(), | ||
Base12Hour(), | ||
Base12HourShort(), | ||
Base24Hour() | ||
) | ||
|
||
/** | ||
* Parses a string to a KronExpression | ||
* | ||
* @param string the string to parse | ||
* @throws ParseException if the string is not a valid cron expression | ||
* @return a [KronExpression] instance | ||
*/ | ||
fun parse(string: String): KronExpression { | ||
val lowercaseString = string.toLowerCase() | ||
val mappings = mapOf( | ||
"@yearly" to KronExpression("0", "0", "1", "1", "*"), | ||
"@annually" to KronExpression("0", "0", "1", "1", "*"), | ||
"@monthly" to KronExpression("0", "0", "1", "*", "*"), | ||
"@weekly" to KronExpression("0", "0", "*", "*", "0"), | ||
"@midnight" to KronExpression("0", "0", "*", "*", "*"), | ||
"@daily" to KronExpression("0", "0", "*", "*", "*"), | ||
"@hourly" to KronExpression("0", "*", "*", "*", "*") | ||
) | ||
|
||
if (mappings.containsKey(lowercaseString)) { | ||
return mappings[lowercaseString]!! | ||
} | ||
|
||
val expression = KronExpression() | ||
var isMinuteElementLocked = false | ||
var isHourElementLocked = false | ||
var isDayNumberElementLocked = false | ||
var isMonthElementLocked = false | ||
var isDayOfWeekElementLocked = false | ||
|
||
val shouldUpdateMinute: (KronExpression, ExpressionElementProvider) -> Boolean = { expression, subParser -> | ||
subParser.canProvideMinute() && !isMinuteElementLocked | ||
} | ||
|
||
val shouldUpdateHour: (KronExpression, ExpressionElementProvider) -> Boolean = { expression, subParser -> | ||
subParser.canProvideHour() && !isHourElementLocked | ||
} | ||
|
||
val shouldUpdateDayNumber: (KronExpression, ExpressionElementProvider) -> Boolean = { expression, subParser -> | ||
subParser.canProvideDayNumber() && !isDayNumberElementLocked | ||
} | ||
|
||
val shouldUpdateMonth: (KronExpression, ExpressionElementProvider) -> Boolean = { expression, subParser -> | ||
subParser.canProvideMonth() && !isMonthElementLocked | ||
} | ||
|
||
val shouldUpdateDayOfWeek: (KronExpression, ExpressionElementProvider) -> Boolean = { expression, subParser -> | ||
subParser.canProvideDayOfWeek() && !isDayOfWeekElementLocked | ||
} | ||
|
||
for (elementProvider in elementProviders) { | ||
if (elementProvider.matches(lowercaseString)) { | ||
if (shouldUpdateMinute(expression, elementProvider)) { | ||
expression.minute = elementProvider.getMinuteElement() | ||
} | ||
|
||
if (shouldUpdateHour(expression, elementProvider)) { | ||
expression.hour = elementProvider.getHourElement() | ||
} | ||
|
||
if (shouldUpdateDayNumber(expression, elementProvider)) { | ||
expression.dayNumber = elementProvider.getDayNumberElement() | ||
} | ||
|
||
if (shouldUpdateMonth(expression, elementProvider)) { | ||
expression.month = elementProvider.getMonthElement() | ||
} | ||
|
||
if (shouldUpdateDayOfWeek(expression, elementProvider)) { | ||
expression.dayOfWeek = elementProvider.getDayOfWeekElement() | ||
} | ||
|
||
if (elementProvider.isMinuteElementLocked()) { | ||
isMinuteElementLocked = true | ||
} | ||
|
||
if (elementProvider.isHourElementLocked()) { | ||
isHourElementLocked = true | ||
} | ||
|
||
if (elementProvider.isDayNumberElementLocked()) { | ||
isDayNumberElementLocked = true | ||
} | ||
|
||
if (elementProvider.isMonthElementLocked()) { | ||
isMonthElementLocked = true | ||
} | ||
|
||
if (elementProvider.isDayOfWeekElementLocked()) { | ||
isDayOfWeekElementLocked = true | ||
} | ||
} | ||
} | ||
|
||
val validPattern = Pattern.compile(VALID_PATTERN) | ||
if (expression.hasNothing() || !validPattern.matcher(expression.toString()).matches()) { | ||
throw ParseException("Unable to parse \"$string\", expression is: $expression", Int.MIN_VALUE) | ||
} | ||
|
||
return expression | ||
} | ||
|
||
/** | ||
* Converts a string to a valid cron expression | ||
* | ||
* @param string the string to convert | ||
* @throws ParseException if the string is not a valid cron expression | ||
* @return a valid cron expression in string format | ||
*/ | ||
fun fromString(string: String): String { | ||
val parser = NaturalKronParser() | ||
return parser.parse(string).toString() | ||
} | ||
|
||
/** | ||
* Checks if a string is a valid cron expression | ||
*/ | ||
fun isValid(string: String): Boolean { | ||
if (string == "@reboot") { | ||
return true | ||
} | ||
return try { | ||
fromString(string) | ||
true | ||
} catch (e: ParseException) { | ||
false | ||
} | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.