How to duplicate output of process to file and console (in Kotlin program) - kotlin

I have a simple snippet of Kotlin code
import java.io.*
import java.util.concurrent.TimeUnit.MINUTES
import java.util.concurrent.TimeUnit
val proc = ProcessBuilder("C:\\tools\\build\\maven\\3.6.1\\bin\\mvn.cmd")
.directory(null)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
println("Started")
proc.waitFor(60, TimeUnit.MINUTES)
println("Ended")
val output : String = proc.inputStream.bufferedReader().readText()
println("Output : " + output)
var log : File = File("cmd.log")
log.writeText(output)
This code run command then saves output in string then print output to console
But printing is occured when external program is completed.
My question is:
I would like to see program output in real time mode.
From other hands I would like to see output of external program while it works.
This code run as Kotlin script : kotlinc -script script.ktc
If place string
val output : String = proc.inputStream.bufferedReader().readText()
Before waitFor call. I observed that execution is blocked as expected

I'm sorry for this question, it was quite simple,I found simple answer today.
val proc = ProcessBuilder("ls", "-lR", "c:\\toolchains")
.directory(null)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
println("Started")
val output: BufferedReader = proc.inputStream.bufferedReader()
var line: String? = output.readLine()
val log: File = File("cmd.log")
while (line != null) {
println("Next Line " + line)
log.appendText(line.toString() + System.lineSeparator())
line = output.readLine()
}
proc.waitFor(60, TimeUnit.MINUTES)
println("Ended")

Related

The application and the screen stop when running the code

I am a beginner in programming, and I found it difficult to overcome this problem, which is represented in the Android application that runs the Python code
The code works fine. But when I add while Ture, the screen stops. What is the cause of the problem? Thank you
script python
Is there a suggestion about this problem?
def main(CodeAreaData):
file_dir = str(Python.getPlatform().getApplication().getFilesDir())
filename = join(dirname(file_dir), 'file.txt')
try:
original_stdout = sys.stdout
sys.stdout = open(filename, 'w', encoding = 'utf8', errors="ignore")
exec(CodeAreaData) # it will execute our code and save output in file
sys.stdout.close()
sys.stdout = original_stdout
output = open(filename, 'r').read()
sys.stdout.close()
except Exception as e:
sys.stdout = original_stdout
output = e
return str(output)
my code kotlin
```kotlin
val py = Python.getInstance()
//here we call our script with the name "myscirpt
//here we call our script with the name "myscirpt
val pyobj = py.getModule("myscript") //give python script name
//and call main method inside script...//pass data here
//and call main method inside script...//pass data here
val obj = pyobj.callAttr("main", editor.text.toString())
println(obj)
If you're adding a while true statement, then the screen should stop. That will lead to an infinite loop. A while loop runs until the condition evaluates to false. Here is more info about that:
https://www.geeksforgeeks.org/how-to-use-while-true-in-python/

Gatling feeder/parameter issue - Exception in thread "main" java.lang.UnsupportedOperationException

I just involved the new project for API test for our service by using Gatling. At this point, I want to search query, below is the code:
def chnSendToRender(testData: FeederBuilderBase[String]): ChainBuilder = {
feed(testData)
exec(api.AdvanceSearch.searchAsset(s"{\"all\":[{\"all:aggregate:text\":{\"contains\":\"#{edlAssetId}_Rendered\"}}]}", "#{authToken}")
.check(status.is(200).saveAs("searchStatus"))
.check(jsonPath("$..asset:id").findAll.optional.saveAs("renderedAssetList"))
)
.doIf(session => session("searchStatus").as[Int] == 200) {
exec { session =>
printConsoleLog("Rendered Asset ID List: " + session("renderedAssetList").as[String], "INFO")
session
}
}
}
I declared the feeder already in the simulation scala file:
class GVRERenderEditor_new extends Simulation {
private val edlToRender = csv("data/render/edl_asset_ids.csv").queue
private val chnPostRender = components.notifications.notice.JobsPolling_new.chnSendToRender(edlToRender)
private val scnSendEDLForRender = scenario("Search Post Render")
.exitBlockOnFail(exec(preSimAuth))
.exec(chnPostRender)
setUp(
scnSendEDLForRender.inject(atOnceUsers(1)).protocols(httpProtocol)
)
.maxDuration(sessionDuration.seconds)
.assertions(global.successfulRequests.percent.is(100))
}
But Gatling test failed to run, showing this error: Exception in thread "main" java.lang.UnsupportedOperationException: There were no requests sent during the simulation, reports won't be generated
If I hardcode the #{edlAssetId} (put the real edlAssetId in that query), I will get result. I think I passed the parameter wrongly in this case. I've tried to print the output in console log but no luck. What's wrong with this code? I would appreciate your help. Thanks!
feed(testData)
exec(api.AdvanceSearch.searchAsset(s"{\"all\":[{\"all:aggregate:text\":{\"contains\":\"#{edlAssetId}_Rendered\"}}]}", "#{authToken}")
.check(status.is(200).saveAs("searchStatus"))
.check(jsonPath("$..asset:id").findAll.optional.saveAs("renderedAssetList"))
)
You're missing a . (dot) before the exec to attach it to the feed.
As a result, your method is returning the last instruction, ie the exec only.

How to write a string to clipboard (Windows OS) with a Kotlin/Native application?

I'm very new to Kotlin and making a command line .exe, on Windows using Kotlin/Native. The application should read from a text file and print on screen, line by line. When it reaches the last line of the file, it should put it in the clipboard.
aFile.txt looks something like this:
one
two
three
...
...
the last line
and the code read.kt (Kotlin/Native) I have so far is this:
import kotlinx.cinterop.*
import platform.posix.*
fun main(args: Array<String>) {
if (args.size != 1) {
println("Usage: read.exe <file.txt>")
return
}
val fileName = args[0]
val file = fopen(fileName, "r")
if (file == null) {
perror("cannot open input file $fileName")
return
}
try {
memScoped {
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
do {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
print("${nextLine}")
} while (true)
}
} finally {
fclose(file)
}
}
The code above prints each line on the screen, but how do I write the string "the last line" in the computer's clipboard? I'm looking for a native (not Java) solution if that's possible.
Thank you very much.
Update:
Obviously, this is not the solution I was looking for, but I don't understand yet what are they talking about here (https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclipboarddata).
As a temporary fix, I was able to get what I needed using system(), echo and clip with code like this:
system("echo ${nextLine} | clip")
print("${nextLine}")
Try the following:
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.StringSelection
fun setClipboard(s: String) {
val selection = StringSelection(s)
val clipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(selection, selection)
}
In Windows, you can work with the Clipboard through WinAPI, as you can see there. The reference says, that you got to use functions from the winuser.h header. This header is included in windows.h, as far as I know, so it is in your platform.windows.* package. You can approve it by checking Kotlin/Native repository files.
To clarify, what I meant, I wrote this small example of platform.windows.* usage. You can add this function to your code, and call it when you got to copy some string.
import platform.windows.*
fun toClipboard(lastLine:String?){
val len = lastLine!!.length + 1
val hMem = GlobalAlloc(GMEM_MOVEABLE, len.toULong())
memcpy(GlobalLock(hMem), lastLine.cstr, len.toULong())
GlobalUnlock(hMem)
val hwnd = HWND_TOP
OpenClipboard(hwnd)
EmptyClipboard()
SetClipboardData(CF_TEXT, hMem)
CloseClipboard()
}

Read line and append something at the end

I'm new in kotlin. I'm trying to read file line by line and add something at the end to each of them.
My file before reading:
abcd;abcd;abcd;
bcda;bcda;bcda;
dacb;dacb;dacb;
My file after reading and appending:
abcd;abcd;abcd;smth1
bcda;bcda;bcda;smth2
dacb;dacb;dacb;smth3
I have code for reading file line by line but could you tell me how to add string to each of them?
val pathToFile = "abc.txt"
val scan = Scanner(File(pathToFile))
while (scan.hasNextLine()) {
val line = scan.nextLine()
var lista = ArrayList<String>()
lista = line.split(";") as ArrayList<String>
println(lista.get(0) + " and " + lista.get(1) + " and " + lista.get(2))
}
Januson has the right idea. Here is some Kotlin code to do the job:
inline fun File.mapLines(crossinline transform: (line: String) -> String) {
val tempFile = createTempFile(prefix = "transform", suffix = ".txt")
tempFile.printWriter().use { writer ->
this.forEachLine { line -> writer.println(transform(line)) }
}
check(this.delete() && tempFile.renameTo(this)) { "failed to replace file" }
}
Example usage:
val pathToFile = "abc.txt"
var index = 0
File(pathToFile).mapLines { line -> "${line}smth${++index}" }
If you are using Java 1.7+ then you can use Files.move instead of delete/renameTo:
Files.move(tempFile.toPath(), this.toPath(), StandardCopyOption.REPLACE_EXISTING)
See also Write to file after match in Kotlin.
You can't read and write to the same file unless you are using RandomAccessFile. Instead you should do the following:
Read line from your input file.
Do the modification you want (append to the end of the line, print line).
Write modified line to the output file.
After reading/writing all the data close both files.
Delete input file. Rename output file to the input file name.

Groovy: strange error with dynamic method invocation

The following is a program that dynamically calls all the getXXX methods on an object of CLASS, where the CLASS-name gets passed via command-line. And it works just fine.
// Program: callAllMethods.groovy
// Invoke this program as: groovy callAllMethods Date
args.each { arg ->
println "Methods of ${arg} ..."
def code = """
x = new ${arg}()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
print "new ${arg}()." + f.name + ": " + f.invoke(x)
println ''
}
}
"""
evaluate("$code")
println ''
}
However, when I try the simpler style of dynamic-method invocation (that does not use METHOD.invoke(OBJECT) but rather OBJECT."METHOD-NAME"()), like so,
// Program: callAllMethods.groovy
// Invoke this program as: groovy callAllMethods Date
args.each { arg ->
println "Methods of ${arg} ..."
def code = """
x = new ${arg}()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
result = x."${f.name}"()
println "new ${arg}().${f.name}: ${result}"
}
}
"""
evaluate("$code")
println ''
}
... I get the following error:
$ groovy callGetMethods.groovy Date
Methods of Date ...
Caught: groovy.lang.MissingPropertyException: No such property: f for class: callGetMethods
groovy.lang.MissingPropertyException: No such property: f for class: callGetMethods
at callGetMethods$_run_closure1.doCall(callGetMethods.groovy:13)
at callGetMethods.run(callGetMethods.groovy:10)
I cannot understand why! Groovy version that I'm using:
$ groovy -version
Groovy Version: 2.1.3 JVM: 1.6.0_43 Vendor: Sun Microsystems Inc. OS: Linux
It happens because when you use the reflection based one (the x.class.methods.each one), you concatenate and generate the code upon GString evaluation, which resolves only one variable against the current scope, which is arg, and that is ok. If you print the code, it outputs a perfectly runnable Groovy code:
x = new Date()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
print "new Date()." + f.name + ": " + f.invoke(x)
println ''
}
}
In your second version, the GString variables are resolved against the scope they were created, which is the script binding. So it tries to fetch the f variable from that scope, and not from the code variable. And that is why it crashes at the ${f} variable.
If you change the code variable into a plain string (single quotes), it won't resolve the variable arg, and thus you will need to tweak a bit around it to create a new class from it. Even so, it will fail, unless you pass as argument groovy callAllMethods java.util.Date, which is not groovy (pun intended).
So, to use your code in that way, the GString shouldn't be resolved in declaration time, but rather at evaluate() time. Still, the arg variable needs to be resolved in declaration time, thus, you need to concat it. Here is the result:
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.class.methods.each { m ->
if (m.name.startsWith("get")) {
result = x."${m.name}"()
println "new '''+arg+'''().${m.name}: ${result}"
}
}
'''
evaluate code
println ''
}
Which, in my box (jdk7, groovy 2.1.3), outputs:
new Date().getDay: 0
new Date().getTimezoneOffset: 180
new Date().getDate: 2
new Date().getHours: 10
new Date().getMinutes: 39
new Date().getMonth: 5
new Date().getSeconds: 56
new Date().getTime: 1370180396136
new Date().getYear: 113
new Date().getClass: class java.util.Date
If you just want to output the properties from an object, may i suggest the object.properties?
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.properties.each {
println "new '''+arg+'''().${it.key}: ${x[it.key]}"
}
'''
evaluate code
println ''
}
It outputs a bit more stuff for Date, though :-).