Compare commits

..

25 Commits
0.2.3 ... 0.3.2

Author SHA1 Message Date
1431c0cda2 fix for parser 2020-10-10 22:17:48 +06:00
66e75b4315 add "each" 2020-10-10 21:39:00 +06:00
5a13437c17 add last and first 2020-10-10 21:12:32 +06:00
6d612ce95d start 0.3.2 2020-10-10 20:03:52 +06:00
92f1ec03dd fix in github_release 2020-10-08 18:17:46 +06:00
f23740a6a5 fix of github_release files 2020-10-08 18:04:27 +06:00
16d8850ca7 fix of github_release files 2020-10-08 17:53:24 +06:00
f278361470 Merge pull request #6 from InsanusMokrassar/0.3.1
0.3.1
2020-10-08 17:13:28 +06:00
47d84751e3 update publication scripts 2020-10-08 17:09:08 +06:00
3aa658168d add changelog and github release tools 2020-10-08 15:26:07 +06:00
60458999b4 update version, dependencies 2020-10-08 15:26:07 +06:00
94573ecd43 update gradle files 2020-08-29 11:48:54 +06:00
241fb2ee51 KrontabTemplate typealias 2020-08-22 21:42:47 +06:00
cdeea96c54 update dependencies versions 2020-08-22 21:36:55 +06:00
4b310071d7 start 0.3.0 2020-08-22 21:22:42 +06:00
5ccebc5033 Merge pull request #2 from InsanusMokrassar/0.2.4
0.2.4
2020-07-26 00:12:15 +06:00
65477bb0bc Update gradle wrapper version 2020-07-24 23:52:46 +06:00
990b0d1011 fixes in docs and refactor 2020-07-24 15:23:44 +06:00
5cc9c8278e removing of unnecessary code 2020-07-24 14:25:30 +06:00
12d2d82c71 Update CHANGELOG.md 2020-07-24 14:18:57 +06:00
0d19d80d48 buildSchedule hotfix 2020-07-24 14:18:18 +06:00
5358bfdb47 add support of ranges in strings 2020-07-24 13:16:56 +06:00
5c452d58b7 update libraries 2020-07-24 11:50:17 +06:00
a36fd1a30a start 0.2.4 2020-07-24 11:43:45 +06:00
6dc85d7e18 Merge pull request #1 from InsanusMokrassar/0.2.3
0.2.3
2020-06-03 22:16:03 +06:00
17 changed files with 244 additions and 91 deletions

View File

@@ -1,5 +1,30 @@
# Changelog
## 0.3.0
* Versions:
* `Kotlin`: `1.3.72` -> `1.4.0`
* `Coroutines`: `1.3.8` -> `1.3.9`
* `Klock`: `1.11.14` -> `1.12.0`
* Typealias `KrontabTemplate` was added
* Extension `KrontabTemplate#toSchedule` was added
### 0.3.2
* Function `TimeBuilder#each` was added (works as `at`)
* Add opportunity to use `first` shortcuts:
* Value property `TimeBuilder#first` for including via functions like `TimeBuilder#at`
* Shortcut for kron string format `f` or `F`
* Add opportunity to use `last` shortcuts:
* Value property `TimeBuilder#last` for including via functions like `TimeBuilder#at`
* Shortcut for kron string format `l` or `L`
### 0.3.1
* Versions:
* `Kotlin`: `1.4.0` -> `1.4.10`
* `Klock`: `1.12.0` -> `1.12.1`
## 0.2.0
* Updated way of publishing (for more info look at the [git](https://git.insanusmokrassar.com/InsanusMokrassar/krontab))
@@ -7,6 +32,13 @@
* Coroutines `1.3.2` -> `1.3.3`
* Klock `1.7.3` -> `1.8.6`
### 0.2.4
* Updates in libraries:
* Klock `1.11.3` -> `1.11.14`
* Coroutines `1.3.7` -> `1.3.8`
* Ranges support were included. Now it is possible to correctly use syntax `0-5` in strings schedules
### 0.2.3
* Updates in libraries:

View File

@@ -7,21 +7,21 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
id "org.jetbrains.dokka" version "$dokka_version"
}
project.version = "0.2.3"
project.version = "0.3.2"
project.group = "com.insanusmokrassar"
apply from: "publish.gradle"
apply from: "github_release.gradle"
repositories {
mavenLocal()
@@ -34,13 +34,17 @@ apply from: './dokka.gradle'
kotlin {
jvm()
js()
js(BOTH) {
browser()
nodejs()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlin_coroutines_version"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
api "com.soywiz.korlibs.klock:klock:$klockVersion"
}
@@ -49,24 +53,20 @@ kotlin {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
}
}
jvmMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
}
}
jvmTest {
dependencies {
implementation kotlin('test-junit')
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
}
}
jsMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$kotlin_coroutines_version"
implementation kotlin('test-js')
}
}
}

24
changelog_parser.sh Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
function parse() {
version=$1
while IFS= read -r line && [ -z "`echo $line | grep -e "^#\+ $version"`" ]
do
: # do nothing
done
while IFS= read -r line && [ -z "`echo $line | grep -e "^#\+"`" ]
do
echo "$line"
done
}
version=$1
file=$2
if [ -n "$file" ]; then
parse $version < "$file"
else
parse $version
fi

30
github_release.gradle Normal file
View File

@@ -0,0 +1,30 @@
private String getCurrentVersionChangelog(String version) {
OutputStream changelogDataOS = new ByteArrayOutputStream()
exec {
commandLine 'chmod', "+x", './changelog_parser.sh'
}
exec {
standardOutput = changelogDataOS
commandLine './changelog_parser.sh', "$version", 'CHANGELOG.md'
}
return changelogDataOS.toString().trim()
}
if (new File(projectDir, "secret.gradle").exists()) {
apply from: './secret.gradle'
apply plugin: "com.github.breadmoirai.github-release"
githubRelease {
token "${project.property('GITHUB_RELEASE_TOKEN')}"
owner "InsanusMokrassar"
repo "${rootProject.name}"
tagName "${project.version}"
releaseName "${project.version}"
targetCommitish "${project.version}"
body getCurrentVersionChangelog("${project.version}")
}
}

View File

@@ -1,11 +1,13 @@
kotlin.code.style=official
kotlin_version=1.3.72
kotlin_coroutines_version=1.3.7
kotlin_version=1.4.10
kotlin_coroutines_version=1.3.9
dokka_version=0.10.1
gradle_bintray_plugin_version=1.8.4
gradle_bintray_plugin_version=1.8.5
klockVersion=1.11.3
klockVersion=1.12.1
github_release_plugin_version=2.2.12
kotlin.incremental.multiplatform=true

View File

@@ -1,6 +1,6 @@
# Tue May 21 17:58:54 HKT 2019
# Fri Jul 24 23:52:00 +06 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip

View File

@@ -20,37 +20,33 @@ publishing {
publications.all {
artifact javadocsJar
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
pom {
description = "It is an analog of crontab util for Kotlin Coroutines"
name = "Krontab"
url = "https://git.insanusmokrassar.com/InsanusMokrassar/krontab"
description "It is an analog of crontab util for Kotlin Coroutines"
name "Krontab"
url "https://git.insanusmokrassar.com/InsanusMokrassar/krontab"
scm {
developerConnection = "scm:git:[fetch=]https://git.insanusmokrassar.com:8322/InsanusMokrassar/krontab.git[push=]https://git.insanusmokrassar.com:8322/InsanusMokrassar/krontab.git"
url = "https://git.insanusmokrassar.com:8322/InsanusMokrassar/krontab.git"
}
scm {
developerConnection "scm:git:[fetch=]https://git.insanusmokrassar.com/InsanusMokrassar/krontab.git[push=]https://git.insanusmokrassar.com/InsanusMokrassar/krontab.git"
url "https://git.insanusmokrassar.com/InsanusMokrassar/krontab.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
developers {
developer {
id "InsanusMokrassar"
name "Ovsiannikov Aleksei"
email "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name "Apache Software License 2.0"
url "https://git.insanusmokrassar.com/InsanusMokrassar/krontab/src/master/LICENSE"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://git.insanusmokrassar.com/InsanusMokrassar/krontab/src/master/LICENSE"
}
}
}
}

View File

@@ -1 +0,0 @@
{"bintrayConfig":{"repo":"InsanusMokrassar","packageName":"${project.name}","packageVcs":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab/src/master/LICENSE"}],"mavenConfig":{"name":"Krontab","description":"It is an analog of crontab util for Kotlin Coroutines","url":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab","vcsUrl":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

1
mpp_config.kpsb Normal file
View File

@@ -0,0 +1 @@
{"bintrayConfig":{"repo":"InsanusMokrassar","packageName":"${project.name}-mpp","packageVcs":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab/src/master/LICENSE"}],"mavenConfig":{"name":"Krontab","description":"It is an analog of crontab util for Kotlin Coroutines","url":"https://git.insanusmokrassar.com/InsanusMokrassar/krontab","vcsUrl":"https://git.insanusmokrassar.com:8322/InsanusMokrassar/krontab.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}

View File

@@ -25,12 +25,15 @@ bintray {
}
into "${project.group}".replace(".", "/")
}
publish = true
override = true
pkg {
repo = "InsanusMokrassar"
name = "${project.name}"
name = "${project.name}-mpp"
vcsUrl = "https://git.insanusmokrassar.com/InsanusMokrassar/krontab"
licenses = ["Apache-2.0"]
override=true
version {
name = "${project.version}"
released = new Date()

View File

@@ -7,7 +7,7 @@ import kotlinx.coroutines.delay
/**
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
*
* WARNING!!! If you want to launch it in parallel, you must do this explicit.
* WARNING!!! If you want to launch it in parallel, you must do this explicitly.
*/
suspend inline fun <T> KronScheduler.doOnce(noinline block: suspend () -> T): T {
delay((next() - DateTime.now()).millisecondsLong)
@@ -15,12 +15,13 @@ suspend inline fun <T> KronScheduler.doOnce(noinline block: suspend () -> T): T
}
/**
* Will [createSimpleScheduler] using [scheduleConfig] and call [doOnce] on it
* Will [buildSchedule] using [scheduleConfig] and call [doOnce] on it
* @see buildSchedule
*/
suspend inline fun <T> doOnce(
scheduleConfig: String,
noinline block: suspend () -> T
) = createSimpleScheduler(scheduleConfig).doOnce(block)
) = buildSchedule(scheduleConfig).doOnce(block)
/**
* Will execute [block] while it will return true as a result of its calculation
@@ -30,12 +31,14 @@ suspend inline fun KronScheduler.doWhile(noinline block: suspend () -> Boolean)
}
/**
* Will [createSimpleScheduler] using [scheduleConfig] and call [doWhile] with [block]
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
*
* @see buildSchedule
*/
suspend inline fun doWhile(
scheduleConfig: String,
noinline block: suspend () -> Boolean
) = createSimpleScheduler(scheduleConfig).doWhile(block)
) = buildSchedule(scheduleConfig).doWhile(block)
/**
* Will execute [block] without any checking of result
@@ -45,9 +48,11 @@ suspend inline fun KronScheduler.doInfinity(noinline block: suspend () -> Unit)
true
}
/**
* Will [createSimpleScheduler] using [scheduleConfig] and call [doInfinity] with [block]
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
*
* @see buildSchedule
*/
suspend inline fun doInfinity(
scheduleConfig: String,
noinline block: suspend () -> Unit
) = createSimpleScheduler(scheduleConfig).doInfinity(block)
) = buildSchedule(scheduleConfig).doInfinity(block)

View File

@@ -2,6 +2,12 @@ package com.insanusmokrassar.krontab
import com.insanusmokrassar.krontab.internal.*
/**
* @see createSimpleScheduler
* @see buildSchedule
*/
typealias KrontabTemplate = String
/**
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
*
@@ -13,7 +19,7 @@ import com.insanusmokrassar.krontab.internal.*
*
* And each one have next format:
*
* `{number},{number},...`
* `{number}[,{number},...]` or `*`
*
* and {number} here is one of
*
@@ -21,6 +27,8 @@ import com.insanusmokrassar.krontab.internal.*
* * {int}/{int}
* * *&#47;{int}
* * {int}
* * F
* * L
*
* Additional info about ranges can be found in follow accordance:
*
@@ -33,12 +41,13 @@ import com.insanusmokrassar.krontab.internal.*
* Examples:
*
* * "0/5 * * * *" for every five seconds triggering
* * "0/5,L * * * *" for every five seconds triggering and on 59 second
* * "0/15 30 * * *" for every 15th seconds in a half of each hour
* * "1 2 3 4 5" for triggering in near first second of second minute of third hour of fourth day of may
* * "1 2 3 F,4,L 5" for triggering in near first second of second minute of third hour of fourth day of may
*
* @see com.insanusmokrassar.krontab.internal.createKronScheduler
*/
fun createSimpleScheduler(incoming: String): KronScheduler {
fun createSimpleScheduler(incoming: KrontabTemplate): KronScheduler {
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = incoming.split(" ")
val secondsParsed = parseSeconds(secondsSource)
@@ -53,6 +62,11 @@ fun createSimpleScheduler(incoming: String): KronScheduler {
}
/**
*
* Shortcut for [createSimpleScheduler]
*/
fun buildSchedule(incoming: String): KronScheduler = createSimpleScheduler(incoming)
fun buildSchedule(incoming: KrontabTemplate): KronScheduler = createSimpleScheduler(incoming)
/**
* Shortcut for [buildSchedule]
*/
fun KrontabTemplate.toSchedule(): KronScheduler = buildSchedule(this)

View File

@@ -12,6 +12,17 @@ sealed class TimeBuilder (
) {
private var result: Set<Int>? = null
/**
* The first possible value of builder
*/
val first
get() = restrictionsRange.first
/**
* The last possible value of builder. Using of this variable equal to using "L" in strings
*/
val last
get() = restrictionsRange.last
/**
* After calling of this function this builder will allow any value of current time
*/
@@ -37,6 +48,13 @@ sealed class TimeBuilder (
result = (result ?: emptySet()) + value.clamp(restrictionsRange)
}
/**
* Shortcut for [at]. In fact will
*/
@Suppress("unused", "NOTHING_TO_INLINE")
inline infix fun each(value: Int) = at(value)
/**
* Just wrapper for more obvious writing something like "[from] 2 [every] 5". For example, for [SecondsBuilder] it
* will mean "[from] second second [every] 5 seconds", or "2, 7, 13, ..."
@@ -81,6 +99,25 @@ sealed class TimeBuilder (
*/
@Suppress("unused")
infix fun upTo(endIncluding: Int): Array<Int> = this from 0 upTo endIncluding
/**
* Will fill up this timeline from [this] up to [endIncluding]
*/
@Suppress("MemberVisibilityCanBePrivate")
infix operator fun Int.rangeTo(endIncluding: Int) = upTo(endIncluding)
/**
* Shortcut for "[from] 0 [rangeTo] [endIncluding]"
*/
@Suppress("MemberVisibilityCanBePrivate")
infix operator fun rangeTo(endIncluding: Int) = (this from 0) rangeTo endIncluding
/**
* Will include the last possible value
*/
fun includeLast() = at(restrictionsRange.last)
/**
* Will include the first possible value
*/
fun includeFirst() = at(restrictionsRange.first)
internal fun build() = result ?.map { it.toByte() } ?.toTypedArray()
}

View File

@@ -28,30 +28,6 @@ internal data class CronDateTime(
}
internal val klockDayOfMonth = dayOfMonth ?.plus(1)
companion object {
/**
* Using [clamp] extension for checking every parameter to be ensure that they are all correct
* @param month 0-11
* @param dayOfMonth 0-31
* @param hours 0-23
* @param minutes 0-59
* @param seconds 0-59
*/
fun create(
month: Int? = null,
dayOfMonth: Int? = null,
hours: Int? = null,
minutes: Int? = null,
seconds: Int? = null
) = CronDateTime(
month ?.clamp(monthRange) ?.toByte(),
dayOfMonth ?.clamp(dayOfMonthRange) ?.toByte(),
hours ?.clamp(hoursRange) ?.toByte(),
minutes ?.clamp(minutesRange) ?.toByte(),
seconds ?.clamp(secondsRange) ?.toByte()
)
}
}
/**
@@ -76,7 +52,13 @@ internal fun CronDateTime.toNearDateTime(relativelyTo: DateTime = DateTime.now()
}
klockDayOfMonth ?.let {
val left = it - current.dayOfMonth
val left = (it - current.dayOfMonth).let { diff ->
if (diff > 0 && current.endOfMonth.run { it > dayOfMonth && current.dayOfMonth == dayOfMonth }) {
0
} else {
diff
}
}
current += DateTimeSpan(months = if (left < 0) 1 else 0, days = left)
}

View File

@@ -26,7 +26,7 @@ internal data class CronDateTimeScheduler internal constructor(
* @see toNearDateTime
*/
override suspend fun next(relatively: DateTime): DateTime {
return cronDateTimes.map { it.toNearDateTime(relatively) }.min() ?: anyCronDateTime.toNearDateTime(relatively)
return cronDateTimes.map { it.toNearDateTime(relatively) }.minOrNull() ?: anyCronDateTime.toNearDateTime(relatively)
}
}

View File

@@ -6,9 +6,18 @@ private fun createSimpleScheduler(from: String, dataRange: IntRange): Array<Byte
val things = from.split(",")
val results = things.flatMap {
val currentToken = it.toLowerCase().replace(
"f", dataRange.first.toString()
).replace(
"l", dataRange.last.toString()
)
when {
it.contains("/") -> {
val (start, step) = it.split("/")
currentToken.contains("-") -> {
val splitted = currentToken.split("-")
(splitted.first().toInt().clamp(dataRange) .. splitted[1].toInt().clamp(dataRange)).toList()
}
currentToken.contains("/") -> {
val (start, step) = currentToken.split("/")
val startNum = (if (start.isEmpty() || start == "*") {
0
} else {
@@ -17,8 +26,8 @@ private fun createSimpleScheduler(from: String, dataRange: IntRange): Array<Byte
val stepNum = step.toInt().clamp(dataRange)
(startNum .. dataRange.last step stepNum).map { it }
}
it == "*" -> return null
else -> listOf(it.toInt().clamp(dataRange))
currentToken == "*" -> return null
else -> listOf(currentToken.toInt().clamp(dataRange))
}
}

View File

@@ -1,12 +1,12 @@
package com.insanusmokrassar.krontab.utils
import com.insanusmokrassar.krontab.buildSchedule
import com.insanusmokrassar.krontab.builder.buildSchedule
import com.insanusmokrassar.krontab.createSimpleScheduler
import com.soywiz.klock.DateTime
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.takeWhile
import kotlin.math.max
import kotlin.math.min
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -60,4 +60,23 @@ class StringParseTest {
}
}
}
@Test
fun testThatFlowIsCorrectlyWorkEverySeveralSecondsRangeBuiltOnString() {
val rangesEnds = listOf(0 to 5, 30 to 35)
val kronScheduler = buildSchedule("${rangesEnds.joinToString(",") { "${it.first}-${it.second}" }} * * * *")
val flow = kronScheduler.asFlow()
runTest {
val ranges = rangesEnds.map { it.first .. it.second }.flatten().toMutableList()
val expectedCollects = rangesEnds.sumBy { it.second - it.first + 1 }
var collected = 0
flow.takeWhile { ranges.isNotEmpty() }.collect {
ranges.remove(it.seconds)
collected++
}
assertEquals(expectedCollects, collected)
}
}
}