From d5484460d1ec2581d9263aa5ecf43cd122a7a864 Mon Sep 17 00:00:00 2001 From: Jonas Tobias Hopusch Date: Wed, 1 Dec 2021 14:36:07 +0100 Subject: [PATCH 1/3] Port waituntil from Kotlin to Java --- README.md | 4 +- build.gradle.kts | 33 +--------- gradle.properties | 1 - settings.gradle.kts | 2 +- .../java/de/jotoho/waituntil/GlobalConf.java | 10 +++ src/main/java/de/jotoho/waituntil/Main.java | 51 +++++++++++++++ src/main/java/de/jotoho/waituntil/Sleep.java | 32 ++++++++++ .../de/jotoho/waituntil/TimeCalculator.java | 40 ++++++++++++ src/main/kotlin/de/jotoho/waituntil/Start.kt | 64 ------------------- .../kotlin/de/jotoho/waituntil/sleeping.kt | 24 ------- .../kotlin/de/jotoho/waituntil/timecalc.kt | 41 ------------ 11 files changed, 139 insertions(+), 163 deletions(-) create mode 100644 src/main/java/de/jotoho/waituntil/GlobalConf.java create mode 100644 src/main/java/de/jotoho/waituntil/Main.java create mode 100644 src/main/java/de/jotoho/waituntil/Sleep.java create mode 100644 src/main/java/de/jotoho/waituntil/TimeCalculator.java delete mode 100644 src/main/kotlin/de/jotoho/waituntil/Start.kt delete mode 100644 src/main/kotlin/de/jotoho/waituntil/sleeping.kt delete mode 100644 src/main/kotlin/de/jotoho/waituntil/timecalc.kt diff --git a/README.md b/README.md index 0843e8e..eae89c9 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# waituntil +# de.jotoho.waituntil This simple tool doubles as a programming exercise for me, as I attempt to learn Kotlin from my perspective as a Java developer and a (hopefully) useful tool for personal use. I will expand this README with details as the project evolves. ## Copyright / Licensing ``` -waituntil - a tool for delaying command execution until the specified time +de.jotoho.waituntil - a tool for delaying command execution until the specified time Copyright (C) 2021 Jonas Tobias Hopusch This program is free software: you can redistribute it and/or modify diff --git a/build.gradle.kts b/build.gradle.kts index acb9f26..9dd27a7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,4 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { - // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - kotlin("jvm") version "latest.release" - // Apply the application plugin to add support for building a CLI application in Java. application @@ -19,44 +14,22 @@ repositories { mavenCentral() } -dependencies { - // Align versions of all Kotlin components - implementation(platform(kotlin("bom", "latest.release"))) - - // Use the Kotlin standard library. - implementation(kotlin("stdlib", "latest.release")) - - // Use the Kotlin test library. - testImplementation(kotlin("test", "latest.release")) - - // Use the Kotlin JUnit integration. - testImplementation(kotlin("test-junit", "latest.release")) -} - java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } -tasks.test { - useJUnitPlatform() -} - tasks.jar { manifest { attributes( - "Implementation-Title" to "waituntil", + "Implementation-Title" to "de.jotoho.waituntil", "Implementation-Version" to "${project.version}", - "Main-Class" to "de.jotoho.waituntil.StartKt" + "Main-Class" to "de.jotoho.waituntil.Main" ) } } -tasks.withType { - kotlinOptions.jvmTarget = "17" -} - application { // Define the main class for the application. - mainClass.set("de.jotoho.waituntil.StartKt") + mainClass.set("de.jotoho.waituntil.Main") } diff --git a/gradle.properties b/gradle.properties index 43d3784..6b1823d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1 @@ org.gradle.daemon=false -kotlin.code.style=official diff --git a/settings.gradle.kts b/settings.gradle.kts index 599ab7a..bfe2fb2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,4 +7,4 @@ * in the user manual at https://docs.gradle.org/7.2/userguide/multi_project_builds.html */ -rootProject.name = "waituntil" +rootProject.name = "de.jotoho.waituntil" diff --git a/src/main/java/de/jotoho/waituntil/GlobalConf.java b/src/main/java/de/jotoho/waituntil/GlobalConf.java new file mode 100644 index 0000000..bb90dc0 --- /dev/null +++ b/src/main/java/de/jotoho/waituntil/GlobalConf.java @@ -0,0 +1,10 @@ +package de.jotoho.waituntil; + +import java.util.Locale; + +public record GlobalConf() { + public static final String langGerman = "de"; + public static final String applicationOutputLanguage = (Locale.getDefault().getLanguage().equals(Locale.GERMAN.getLanguage())) + ? Locale.GERMAN.getLanguage() + : Locale.ENGLISH.getLanguage(); +} diff --git a/src/main/java/de/jotoho/waituntil/Main.java b/src/main/java/de/jotoho/waituntil/Main.java new file mode 100644 index 0000000..e53a147 --- /dev/null +++ b/src/main/java/de/jotoho/waituntil/Main.java @@ -0,0 +1,51 @@ +package de.jotoho.waituntil; + +import java.util.*; + +import static de.jotoho.waituntil.GlobalConf.applicationOutputLanguage; + +// This file contains the main function and other utility function necessary for interpreting the terminal arguments. +// See README.md and LICENSE.md for license information +// Author: Jonas Tobias Hopusch (@jotoho) + +public final class Main { + public static void main(final String[] args) { + final var optionDictionary = Map.of("-h", "--help", "-v", "--version"); + + final var options = new HashSet(); + final var words = new HashSet(); + + for (final String arg : args) { + if (arg.startsWith("--")) { + options.add(arg.substring(2)); + } else if (arg.startsWith("-")) { + if (optionDictionary.containsKey(arg)) + options.add(optionDictionary.get(arg).substring(2)); + else + System.err.println("Short-hand '$arg' does not exist. Ignoring!"); + } else { + words.add(arg); + } + } + + if (options.contains("help")) { + switch (applicationOutputLanguage) { + case GlobalConf.langGerman -> System.out.println("Hilfe kommt noch. (Nicht implementiert)"); + default -> System.out.println("Help is yet to come. (Not implemented)"); + } + } else if (options.contains("version")) { + final var thisPackage = Main.class.getPackage(); + final var appVersion = thisPackage.getImplementationVersion() != null ? thisPackage.getImplementationVersion() :"UNKNOWN"; + System.out.println("de.jotoho.waituntil version $appVersion"); + } else if (words.size() == 1) { + final var target = TimeCalculator.calculateAndAnnounceTargetTime(words.iterator().next()); + Sleep.waitUntilTimeStamp(target); + } else { + switch (applicationOutputLanguage) { + case GlobalConf.langGerman -> System.err.println("FATAL: Es wurde exact ein nicht-flag Argument erwartet. (" + words.size() + " erhalten)"); + default -> System.err.println("FATAL: Expected one non-flag argument. (Got " + words.size() + ")"); + } + System.exit(1); + } + } +} diff --git a/src/main/java/de/jotoho/waituntil/Sleep.java b/src/main/java/de/jotoho/waituntil/Sleep.java new file mode 100644 index 0000000..5dde075 --- /dev/null +++ b/src/main/java/de/jotoho/waituntil/Sleep.java @@ -0,0 +1,32 @@ +package de.jotoho.waituntil; + +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.time.temporal.ChronoUnit; +import java.util.*; + +import java.lang.Math; + +public final class Sleep { + public static void waitUntilTimeStamp(ZonedDateTime timestamp) { + try { + Thread.sleep(Math.max(0, Instant.now().until(timestamp, ChronoUnit.MILLIS))); + } catch (final InterruptedException ignored) { + } + + final String formattedTimeStamp = + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) + .withZone(TimeZone.getDefault().toZoneId()) + .format(Instant.now()); + + final String msg = switch (GlobalConf.applicationOutputLanguage) { + case GlobalConf.langGerman -> "Erfolgreich bis %s gewartet!"; + default -> "Successfully waited until %s"; + }; + + final String msgWithData = msg.formatted(formattedTimeStamp); + System.err.println(msgWithData); + } +} diff --git a/src/main/java/de/jotoho/waituntil/TimeCalculator.java b/src/main/java/de/jotoho/waituntil/TimeCalculator.java new file mode 100644 index 0000000..34ec750 --- /dev/null +++ b/src/main/java/de/jotoho/waituntil/TimeCalculator.java @@ -0,0 +1,40 @@ +package de.jotoho.waituntil; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.*; + +public final class TimeCalculator { + + public static ZonedDateTime calculateAndAnnounceTargetTime(final String userTimeInputRaw) { + final var userTimeInputRelative = LocalTime.parse(userTimeInputRaw); + final var userTimeInputAbsolute = + ZonedDateTime.of( + LocalDate.now(), + userTimeInputRelative, + TimeZone.getDefault().toZoneId() + ); + + final var userTimeInputFinal = (Instant.now().isBefore(userTimeInputAbsolute.toInstant())) + ? userTimeInputAbsolute + : userTimeInputAbsolute.plusDays(1); + + final var formattedTimeStamp = + userTimeInputFinal.format( + DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) + ); + + final String msg = switch (GlobalConf.applicationOutputLanguage) { + case GlobalConf.langGerman -> "Dieses Program wird bis zum %s warten." + .formatted(formattedTimeStamp); + default -> "WaitUntil will suspend until %s".formatted(formattedTimeStamp); + }; + System.out.println(msg); + + return userTimeInputFinal; + } +} diff --git a/src/main/kotlin/de/jotoho/waituntil/Start.kt b/src/main/kotlin/de/jotoho/waituntil/Start.kt deleted file mode 100644 index b87355b..0000000 --- a/src/main/kotlin/de/jotoho/waituntil/Start.kt +++ /dev/null @@ -1,64 +0,0 @@ -package de.jotoho.waituntil - -import java.util.* -import kotlin.system.exitProcess - -// This file contains the main function and other utility function necessary for interpreting the terminal arguments. -// See README.md and LICENSE.md for license information -// Author: Jonas Tobias Hopusch (@jotoho) - - -val langGerman: String = Locale.GERMAN.language -val applicationOutputLanguage: String = if (Locale.getDefault().language.equals(Locale.GERMAN.language)) - Locale.GERMAN.language - else Locale.ENGLISH.language - -// For accessing package information -object DummyClass - -fun main(args: Array) { - val optionDictionary = mapOf(Pair("-h", "--help"), Pair("-v", "--version")) - - val options = HashSet() - val words = HashSet() - - for (arg in args) { - if (arg.startsWith("--")) { - options.add(arg.substring(startIndex = 2)) - } else if (arg.startsWith('-')) { - if (optionDictionary.containsKey(arg)) - options.add(optionDictionary[arg]!!.substring(startIndex = 2)) - else - System.err.println("Short-hand '$arg' does not exist. Ignoring!") - } else - words.add(arg) - } - - if (options.contains("help")) { - when (applicationOutputLanguage) { - langGerman -> println("Hilfe kommt noch. (Nicht implementiert)") - else -> { - println("Help is yet to come. (Not implemented)") - } - } - } else if (options.contains("version")) { - when (applicationOutputLanguage) { - langGerman -> { - val thisPackage = DummyClass.javaClass.`package` - val appVersion = thisPackage.implementationVersion ?: "UNKNOWN" - println("waituntil version $appVersion") - } - } - } else if (words.size == 1) { - val target = calculateAndAnnounceTargetTime(words.iterator().next()) - waitUntilTimeStamp(target) - } else { - when (applicationOutputLanguage) { - langGerman -> System.err.println("FATAL: Es wurde exact ein nicht-flag Argument erwartet. (${words.size} erhalten)") - else -> { - System.err.println("FATAL: Expected one non-flag argument. (Got ${words.size})") - } - } - exitProcess(1) - } -} diff --git a/src/main/kotlin/de/jotoho/waituntil/sleeping.kt b/src/main/kotlin/de/jotoho/waituntil/sleeping.kt deleted file mode 100644 index ae031b7..0000000 --- a/src/main/kotlin/de/jotoho/waituntil/sleeping.kt +++ /dev/null @@ -1,24 +0,0 @@ -package de.jotoho.waituntil - -import java.time.Instant -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle -import java.time.temporal.ChronoUnit -import java.util.* - -fun waitUntilTimeStamp(timestamp: ZonedDateTime) { - Thread.sleep(Instant.now().until(timestamp, ChronoUnit.MILLIS).coerceAtLeast(0)) - - val formattedTimeStamp: String = - DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) - .withZone(TimeZone.getDefault().toZoneId()) - .format(Instant.now()) - - when (applicationOutputLanguage) { - langGerman -> System.err.println("Erfolgreich bis $formattedTimeStamp gewartet!") - else -> { - System.err.println("Successfully waited until $formattedTimeStamp") - } - } -} diff --git a/src/main/kotlin/de/jotoho/waituntil/timecalc.kt b/src/main/kotlin/de/jotoho/waituntil/timecalc.kt deleted file mode 100644 index f1b9036..0000000 --- a/src/main/kotlin/de/jotoho/waituntil/timecalc.kt +++ /dev/null @@ -1,41 +0,0 @@ -package de.jotoho.waituntil - -import java.time.Instant -import java.time.LocalDate -import java.time.LocalTime -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle -import java.util.* - -fun calculateAndAnnounceTargetTime(userTimeInputRaw: String): ZonedDateTime { - val userTimeInputRelative = LocalTime.parse(userTimeInputRaw) - val userTimeInputAbsolute = - ZonedDateTime.of( - LocalDate.now(), - userTimeInputRelative, - TimeZone.getDefault().toZoneId() - ) - - val userTimeInputFinal = - if (Instant.now().isBefore(userTimeInputAbsolute.toInstant())) - userTimeInputAbsolute - else userTimeInputAbsolute.plusDays(1) - - val formattedTimeStamp = - userTimeInputFinal.format( - DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG) - ) - - when (applicationOutputLanguage) { - langGerman -> - System.err.println( - "Dieses Program wird bis zum $formattedTimeStamp warten." - ) - else -> { - println("WaitUntil will suspend until $formattedTimeStamp") - } - } - - return userTimeInputFinal -} -- 2.45.2 From 7357b25104211c163947556f42de233b2946b753 Mon Sep 17 00:00:00 2001 From: Jonas Tobias Hopusch Date: Wed, 1 Dec 2021 14:46:00 +0100 Subject: [PATCH 2/3] Fix README --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eae89c9..fdf8128 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,23 @@ -# de.jotoho.waituntil +# waituntil -This simple tool doubles as a programming exercise for me, as I attempt to learn Kotlin from my perspective as a Java developer and a (hopefully) useful tool for personal use. I will expand this README with details as the project evolves. +A basic tool for delaying work in the terminal to a specific time. This software was originally +written in Kotlin and then recently ported to Java. + +Usage: + +```sh +java -jar ./waituntil.jar 10:30 ; reboot # Replace reboot with your command +``` + +The example above would make the program wait until half past ten AM before exiting and allowing +the next command to run. The timestamp can be passed in the formats `HH:MM` or `HH:MM:SS` and must +be in the 24-hour system. Passing dates is not supported but entering a time that has already passed +will make the software wait until that time on the following day. ## Copyright / Licensing ``` -de.jotoho.waituntil - a tool for delaying command execution until the specified time +waituntil - a tool for delaying command execution until the specified time Copyright (C) 2021 Jonas Tobias Hopusch This program is free software: you can redistribute it and/or modify -- 2.45.2 From 88b0acf69829d4b56d8b3ede02f5d805ef8080ab Mon Sep 17 00:00:00 2001 From: Jonas Tobias Hopusch Date: Wed, 1 Dec 2021 14:48:27 +0100 Subject: [PATCH 3/3] Delete obsolete compile and run scripts --- compile.sh | 5 ----- run.sh | 3 --- 2 files changed, 8 deletions(-) delete mode 100755 compile.sh delete mode 100755 run.sh diff --git a/compile.sh b/compile.sh deleted file mode 100755 index 21fb49b..0000000 --- a/compile.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -# shellcheck disable=SC2046 -# Word splitting in find results is intentional! -kotlinc $(find src/main -type f -iname '*.kt') -jvm-target 17 -include-runtime -d waituntil.jar diff --git a/run.sh b/run.sh deleted file mode 100755 index ece8c9a..0000000 --- a/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -java -jar waituntil.jar $* -- 2.45.2