Kotlin enviromental values - kotlin

I'm learning kotlin, I stumbled across an open-source repo, cloned it and ran on my computer, it is a update tool to update an existing jar, although looking at their code how do they approached to that, they did something like this.
private fun updateJar(frame: LaunchFrame, project: Project) {
val sourcePath = project.jarSourcePath
val jarPath = project.jarPath
val repoName = project.repoName
frame.log("Reading source URL from '$sourcePath'")
val sourceUrl = readTextFile(sourcePath)?.let { URI(it) }
frame.log("Source URL: $sourceUrl")
frame.log("Connecting to GitHub")
val github = GitHub.connectAnonymously()
frame.log("Using repository '$repoName'")
val repo = github.getRepository(repoName)
frame.log("Finding latest release")
val latestRelease = repo.listReleases().first()
val assets = latestRelease.assets
check(assets.size == 1) { "Release must only have one asset" }
val asset = assets.first()
val downloadUrl = URI(asset.browserDownloadUrl)
frame.log("Latest URL: $downloadUrl")
if (sourceUrl == null || sourceUrl != downloadUrl || !verifyJar(jarPath)) {
frame.log("Downloading '$downloadUrl' to '$jarPath'")
downloadFile(downloadUrl, jarPath)
frame.log("Writing '$downloadUrl' to '$sourcePath'")
writeTextFile(sourcePath, downloadUrl.toString())
} else {
frame.log("'$jarPath' is up to date")
}
}
Which looks pretty much straight-forward, but here's the catch, there are no actual URL's for the $sourceUrl and others, can someone shed some light to this question? It starts downloading the repo which is runestar/client but there are no actual links for the exact repo what it's trying to download, so how did they do that?

The values are being extracted using some logic, scattered around various places in the code.
For example, see https://github.com/RuneStar/launcher/blob/3e8dcb59c32d2818c917705c6c4432f9fc12c449/src/main/java/org/runestar/launcher/RuneStar.kt#L15
override val repoName: String get() = "RuneStar/client"

It's not environment variables, and it's not downloading from a URL, it's writing to one on the local filesystem.
The Project interface sets up the file locations and the RuneStar class sets up a specfic Github repository.

Related

File picker doesnt get the path right

im using the modern way to get user to pick file and then get it using the "registerForActivityResult(ActivityResultContracts.StartActivityForResult())" method, but the path that I get is not correct (after creating File with the given path it says it doesnt exists). Could anyone please help me with this problem? cant find any solution online with the modern way.
private fun initializeImportResultLauncher() {
importResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val path = result.data!!.data!!.path ?: return#registerForActivityResult
val file = File(path)
val fileExists = file.exists()
binding.importedFileText.text =
String.format("selected file: %s", importFile!!.name)
}
}
}
private fun initializeImportButton() {
binding.importButton.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
importResultLauncher.launch(intent)
}
}
in the debugger after selecting existing file it says that fileExists is false.
Path in the debugger is: /document/raw:/storage/emulated/0/Download/importFile.csv.
Or maybe im just not correctly saving files in the phone directory, if the code is correct could I get some help with that.
Tried every other method but just cant get it working

Configure array/object indentation for YAML in Jackson

I'm trying to generate a YAML file from an input Map I'm using Jackson and the YamlFactory utility provided by Jackson to do so. I'm attempting to configure the indentation property for the YAML output, but it doesn't seem like that's being respected at all.
Here's how my code looks like:
fun getSdkResultAsGenericObject(sdkResult: Any?): Any? {
if (sdkResult == null) {
return null
}
var genericObj: Any?
val stringified = genericSdkObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(sdkResult)
.replace("\n", "")
val isArray = stringified.startsWith("[")
genericObj = if (isArray) {
genericSdkObjectMapper.readValue(stringified, List::class.java)
} else {
genericSdkObjectMapper.readValue(stringified, LinkedHashMap::class.java)
}
val defaultYaml = resultYamlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(genericObj )
}
The declaration of the resultYamlMapper is like this:
val yamlFactory = YAMLFactory()
.configure(YAMLGenerator.Feature.SPLIT_LINES, false)
.configure(YAMLGenerator.Feature.INDENT_ARRAYS, true)
val resultYamlMapper = ObjectMapper(YamlFactory())
The documentation says that the INDENT_ARRAYS feature uses 2 spaces by default. I'm trying to understand how I can configure that? I need 4 spaces in the resultant YAML. I tried setting a pretty print writer:
val yamlFactory = YAMLFactory()
.configure(YAMLGenerator.Feature.SPLIT_LINES, false)
.configure(YAMLGenerator.Feature.INDENT_ARRAYS, true)
val resultYamlMapper = ObjectMapper(YamlFactory())
val arrayIndenter = DefaultIndenter(" ", DefaultIndenter.SYS_LF)
val objectIndenter = DefaultIndenter(" ", DefaultIndenter.SYS_LF)
resultYamlMapper.setDefaultPrettyPrinter(DefaultPrettyPrinter().withObjectIndenter(objectIndenter).withArrayIndenter(arrayIndenter))
But this doesn't seem to be respected at all. Any thoughts? Or does Jackson not let you configure the indentation at all?
The docs show that the PrettyPrinter interface is only for the JsonGenerator.
If you want to customize your YAML output, you have to use the SnakeYAML API directly (which is used by Jackson for YAML processing). SnakeYAML has similar features to Jackson and there is little reason to use Jackson if you only want to process YAML. Most importantly, it lets you configure YAML formatting.

How to exclude mutations from Query root node with spqr?

I use io.leangen.graphql.spqr library version 0.9.6 and I need to exclude mutations from Query root node into the Doc.
My GraphQLController.kt looks this way:
#RestController
class GraphQLController {
private var graphQL: GraphQL? = null
#Autowired
fun GraphQLController(bookGraph: BookGraph) {
val schema = GraphQLSchemaGenerator()
.withResolverBuilders(
AnnotatedResolverBuilder(),
PublicResolverBuilder("com.example.graphql.spqr"))
.withOperationsFromSingleton(bookGraph)
.withValueMapperFactory(JacksonValueMapperFactory())
.generate()
graphQL = GraphQL.newGraphQL(schema)
.build()
}
#PostMapping(value = ["/graphql"], consumes = [MediaType.APPLICATION_JSON_UTF8_VALUE], produces = [MediaType.APPLICATION_JSON_UTF8_VALUE])
#ResponseBody
fun execute(#RequestBody request: Map<String?, Any?>): ExecutionResult? {
return graphQL!!.execute(ExecutionInput.newExecutionInput()
.query(request["query"] as String?)
.variables(request["variables"] as Map<String, Object>?)
.operationName(request["operationName"] as String?)
.build())
and my BookGraph.kt looks this way:
#Component
class BookGraph {
#Autowired
private lateinit var bookService: BookService
#GraphQLQuery(name = "books")
fun books() : List<Book> {
return bookService.findAll()
}
#GraphQLMutation(name = "createBook")
fun createBook(#GraphQLInputField(name = "name") name: String) : Book {
return bookService.findAll()
}
}
How can I do it?
I searched for possible solutions both in StackOverflow and SPQR issues but cannot find a solution.
Example of Query root node below, I want to exclude createBook:
While I want Mutation root node to remain untouched:
It's bug. You're using a very old version of SPQR (Feb. 2018). This has been fixed a long long time ago. Please try to follow the releases as much as possible, as lots of things are getting fixed and improved.
It is possible to work around the bug by customizing the ResolverBuilders, but I wouldn't recommend going that route.
The Spring Starter (if even relevant to you) is currently lagging behind (not yet on the latest SPQR version) but I'm actively working on the new release. Should be out very soon.
Btw, your setup has a lot of redundancy. Can be simplified to:
val schema = GraphQLSchemaGenerator()
.withOperationsFromSingleton(bookGraph)
//replace with your own root package(s)
.withBasePackages("com.example.graphql.spqr")
.generate()

Since ripple-lib-java is unmaintained, how do you manually sign a transaction?

Looking for a lightweight way to manually sign an OfferCreate ... it would be clumsy to start some JavaScript engine in order to get it done.
Hmm ... even though it hasn't been maintained for 4 years it looks like it still works.
Clone ripple-lib-java and do mvn install in ripple-bouncycastle & ripple-core
Then copy the built JARs into <YourProject>/libs
Add local dependencies in Gradle Kotlin DSL:
repositories {
flatDir {
dirs("libs")
}
}
dependencies {
implementation(":ripple-bouncycastle-0.0.1-SNAPSHOT")
implementation(":ripple-core-0.0.1-SNAPSHOT")
runtime("org.json:json:20190722") // No newskool kotlinx-serialization here :(
}
Create & sign OfferCreate:
val offerCreate = OfferCreate()
offerCreate.account(AccountID.fromString("r3jpWpUysF4SAkUNbG4WhDZ5mAJ7rGUDx6"))
offerCreate.expiration(UInt32(get2MinExpiration()))
offerCreate.fee(Amount(BigDecimal("0.00001")))
offerCreate.flags(UInt32(0))
offerCreate.sequence(UInt32(1))
val amountXRP = BigDecimal(200)
val amountBTC = convert(amountXRP, RIPPLE_XRP, BITCOIN)
offerCreate.takerGets(Amount(amountXRP))
offerCreate.takerPays(Amount(amountBTC, Currency.fromString(BITCOIN), AccountID.fromString(BITCOIN_TRUSTED_ISSUER)))
val signedTransaction = offerCreate.sign("[***Secret***]")
println(offerCreate.toJSON())
println(signedTransaction.tx_blob)
A bit annoying that you can't do a toJSON() on a SignedTransaction. It can
t be a security thing, since sign() only adds public key fields: https://xrpl.org/transaction-common-fields.html#signers-field

How to pass parameters or arguments into a Gradle task?

I have a Gradle build script into which I am trying to include Eric Wendelin's CSS plugin.
It's easy enough to implement, and because I only want minification (rather than combining and gzipping), I've got the pertinent parts of the build script looking like this:
minifyCss {
source = "src/main/webapp/css/brandA/styles.css"
dest = "${buildDir}/brandA/styles.css"
yuicompressor {
lineBreakPos = -1
}
}
war {
baseName = 'ex-ren'
}
war.doFirst {
tasks.myTask.minifyCss.execute()
}
This is perfect - when I run the gradle war task, it calls the minifyCss task, takes the source css file, and creates a minified version in the buildDir
However, I have a handful of css files which need minify-ing, but not combining into one file (hence I'm not using the combineCss task)
What I'd like to be able to do is make the source and dest properties (assuming that's the correct terminology?) of the minifyCss task reference variables of some sort - either variables passed into the task in the signature, or global variables, or something ...
Something like this I guess (which doesn't work):
minifyCss(sourceFile, destFile) {
source = sourceFile
dest = destFile
yuicompressor {
lineBreakPos = -1
}
}
war {
baseName = 'ex-ren'
}
war.doFirst {
tasks.myTask.minifyCss.execute("src/main/webapp/css/brandA/styles.css", "${buildDir}/brandA/styles.css")
tasks.myTask.minifyCss.execute("src/main/webapp/css/brandB/styles.css", "${buildDir}/brandB/styles.css")
tasks.myTask.minifyCss.execute("src/main/webapp/css/brandC/styles.css", "${buildDir}/brandC/styles.css")
}
This doesn't work either:
def sourceFile = null
def destFile = null
minifyCss {
source = sourceFile
dest = destFile
yuicompressor {
lineBreakPos = -1
}
}
war {
baseName = 'ex-ren'
}
war.doFirst {
sourceFile = "src/main/webapp/css/brandA/styles.css"
destFile = "${buildDir}/brandA/styles.css"
tasks.myTask.minifyCss.execute()
}
For the life of me I cannot work out how to call a task and pass variables in :(
Any help very much appreciated;
You should consider passing the -P argument in invoking Gradle.
From Gradle Documentation :
--project-prop
Sets a project property of the root project, for example -Pmyprop=myvalue. See Section 14.2, “Gradle properties and system properties”.
Considering this build.gradle
task printProp << {
println customProp
}
Invoking Gradle -PcustomProp=myProp will give this output :
$ gradle -PcustomProp=myProp printProp
:printProp
myProp
BUILD SUCCESSFUL
Total time: 3.722 secs
This is the way I found to pass parameters.
If the task you want to pass parameters to is of type JavaExec and you are using Gradle 5, for example the application plugin's run task, then you can pass your parameters through the --args=... command line option. For example gradle run --args="foo --bar=true".
Otherwise there is no convenient builtin way to do this, but there are 3 workarounds.
1. If few values, task creation function
If the possible values are few and are known in advance, you can programmatically create a task for each of them:
void createTask(String platform) {
String taskName = "myTask_" + platform;
task (taskName) {
... do what you want
}
}
String[] platforms = ["macosx", "linux32", "linux64"];
for(String platform : platforms) {
createTask(platform);
}
You would then call your tasks the following way:
./gradlew myTask_macosx
2. Standard input hack
A convenient hack is to pass the arguments through standard input, and have your task read from it:
./gradlew myTask <<<"arg1 arg2 arg\ in\ several\ parts"
with code below:
String[] splitIntoTokens(String commandLine) {
String regex = "(([\"']).*?\\2|(?:[^\\\\ ]+\\\\\\s+)+[^\\\\ ]+|\\S+)";
Matcher matcher = Pattern.compile(regex).matcher(commandLine);
ArrayList<String> result = new ArrayList<>();
while (matcher.find()) {
result.add(matcher.group());
}
return result.toArray();
}
task taskName, {
doFirst {
String typed = new Scanner(System.in).nextLine();
String[] parsed = splitIntoTokens(typed);
println ("Arguments received: " + parsed.join(" "))
... do what you want
}
}
You will also need to add the following lines at the top of your build script:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;
3. -P parameters
The last option is to pass a -P parameter to Gradle:
./gradlew myTask -PmyArg=hello
You can then access it as myArg in your build script:
task myTask {
doFirst {
println myArg
... do what you want
}
}
Credit to #789 for his answer on splitting arguments into tokens
I would suggest the method presented on the Gradle forum:
def createMinifyCssTask(def brand, def sourceFile, def destFile) {
return tasks.create("minify${brand}Css", com.eriwen.gradle.css.tasks.MinifyCssTask) {
source = sourceFile
dest = destFile
}
}
I have used this method myself to create custom tasks, and it works very well.
task mathOnProperties << {
println Integer.parseInt(a)+Integer.parseInt(b)
println new Integer(a) * new Integer(b)
}
$ gradle -Pa=3 -Pb=4 mathOnProperties
:mathOnProperties
7
12
BUILD SUCCESSFUL
Its nothing more easy.
run command: ./gradlew clean -PjobId=9999
and
in gradle use: println(project.gradle.startParameter.projectProperties)
You will get clue.
I think you probably want to view the minification of each set of css as a separate task
task minifyBrandACss(type: com.eriwen.gradle.css.tasks.MinifyCssTask) {
source = "src/main/webapp/css/brandA/styles.css"
dest = "${buildDir}/brandA/styles.css"
}
etc etc
BTW executing your minify tasks in an action of the war task seems odd to me - wouldn't it make more sense to make them a dependency of the war task?
Here is a solution for Kotlin DSL (build.gradle.kts).
I first try to get the variable as a property and if it was null try to get it from OS environment variables (can be useful in CIs like GitHub Actions).
tasks.create("MyCustomTask") {
val songName = properties["songName"]
?: System.getenv("SONG_NAME")
?: error("""Property "songName" or environment variable "SONG_NAME" not found""")
// OR getting the property with 'by'. Did not work for me!
// For this approach, name of the variable should be the same as the property name
// val songName: String? by properties
println("The song name: $songName")
}
We can then pass a value for the property from command line:
./gradlew MyCustomTask -PsongName="Black Forest"
Or create a file named local.properties at the root of the project and set the property:
songName=Black Forest
We can also add an env variable named SONG_NAME with our desired value and then run the task:
./gradlew MyCustomTask