Skip to content

Commit

Permalink
Add String.copyToClipboard() extension function
Browse files Browse the repository at this point in the history
This commit also adds the ability to run a list of strings as a command.
  • Loading branch information
LouisCAD committed Sep 11, 2022
1 parent c896a4c commit daaf89d
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lib_publisher_tools.clipboard

import lib_publisher_tools.process.execute

fun String.copyToClipboard() {
val escapedText = this.escape(charsToEscape = "\"`$")

val osName = System.getProperty("os.name").lowercase()
val isMacOs: Boolean = "mac" in osName
val isWindows: Boolean = "win" in osName
when {
isMacOs -> listOf("sh", "-c", "echo \"$escapedText\" | pbcopy")
isWindows -> listOf("cmd", "/C", "echo \"$escapedText\" | clip") //TODO: Test that
else -> listOf("sh", "-c", "echo \"$escapedText\" | xclip -sel clip") //TODO: Test that
}.execute()
}

private fun String.escape(charsToEscape: String): String = buildString {
append(this@escape)
for (i in lastIndex downTo 0) {
val c = this[i]
if (c in charsToEscape) insert(i, '\\')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,56 @@ class NonZeroExitCodeException(val value: Int) : Exception("Non zero exit value:
fun String.execute(
workingDir: File = executionDir,
timeout: Duration = 60.minutes
): String {
val proc = processBuilder(
rawCommand = this,
workingDir = workingDir
).start()
): String = processBuilder(
rawCommand = this,
workingDir = workingDir
).execute(timeout)

fun String.executeAndPrint(
workingDir: File = executionDir,
timeout: Duration = 60.minutes
) {
processBuilder(rawCommand = this, workingDir = workingDir).executeAndPrint(timeout)
}

fun List<String>.execute(
workingDir: File = executionDir,
timeout: Duration = 60.minutes
): String = processBuilder(
command = this,
workingDir = workingDir
).execute(timeout)

fun List<String>.executeAndPrint(
workingDir: File = executionDir,
timeout: Duration = 60.minutes
) {
processBuilder(command = this, workingDir = workingDir).executeAndPrint(timeout)
}

private val rawCommandPattern = Pattern.compile("\"([^\"]*)\"|(\\S+)")

private fun decodeRawCommand(rawCommand: String): List<String> {
return rawCommandPattern.matcher(rawCommand).let { m ->
generateSequence {
when {
m.find() -> if (m.group(1) != null) m.group(1) else m.group(2)
else -> null
}
}
}.toList()
}

private fun processBuilder(
rawCommand: String,
workingDir: File = executionDir
): ProcessBuilder = processBuilder(
command = decodeRawCommand(rawCommand),
workingDir = workingDir
)

private fun ProcessBuilder.execute(timeout: Duration): String {
val proc = start()
proc.waitFor(timeout.inWholeMilliseconds, TimeUnit.MILLISECONDS)
return proc.inputStream.use { it.bufferedReader().readText() }.also {
val exitValue = proc.exitValue()
Expand All @@ -27,12 +72,8 @@ fun String.execute(
}
}

fun String.executeAndPrint(
workingDir: File = executionDir,
timeout: Duration = 60.minutes
) {
val proc = processBuilder(rawCommand = this, workingDir = workingDir)
.redirectInput(ProcessBuilder.Redirect.INHERIT)
private fun ProcessBuilder.executeAndPrint(timeout: Duration) {
val proc = redirectInput(ProcessBuilder.Redirect.INHERIT)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start()
Expand All @@ -43,19 +84,10 @@ fun String.executeAndPrint(
}
}

private val rawCommandPattern = Pattern.compile("\"([^\"]*)\"|(\\S+)")

private fun processBuilder(rawCommand: String, workingDir: File = executionDir): ProcessBuilder {
val command = rawCommandPattern.matcher(rawCommand).let { m ->
generateSequence {
when {
m.find() -> if (m.group(1) != null) m.group(1) else m.group(2)
else -> null
}
}
}.toList()
return ProcessBuilder(command)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
}
private fun processBuilder(
command: List<String>,
workingDir: File = executionDir
): ProcessBuilder = ProcessBuilder(command)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)

0 comments on commit daaf89d

Please sign in to comment.