Groovy how to compare two floats - groovy

I need to check an array and get all the values if the os value is above 13.0 . So my script is like :
for(String item: jsonObj.devices) {
if (item.os >= 13.0) {
name = item.name
os = item.os
println name
println os
}
}
But it's not listing any values. The item.os have values like : 9, 14.5.6, 13.0.1, 12.1
Could you please let me know where I am wrong here.

Related

Sort list of version numbers groovy

I have a list of version numbers like,
Versions = [0.0.10, 0.0.11, 0.0.13, 0.0.14, 0.0.15, 0.0.16, 0.0.17, 0.0.18, 0.0.19, 0.0.20, 0.0.21, 0.0.22, 0.0.23, 0.0.24, 0.0.25, 0.0.26, 0.0.27, 0.0.28, 0.0.29, 0.0.3, 0.0.30, 0.0.33, 0.0.34, 0.0.35, 0.0.36, 0.0.37, 0.0.38, 0.0.39, 0.0.4, 0.0.41, 0.0.42, 0.0.43, 0.0.44, 0.0.45, 0.0.46, 0.0.47, 0.0.48, 0.0.49, 0.0.5, 0.0.5-delivery.5, 0.0.50, 0.0.51, 0.0.52, 0.0.53, 0.0.54, 0.0.55, 0.0.56, 0.0.57, 0.0.58, 0.0.59, 0.0.6, 0.0.60, 0.0.61, 0.0.62, 0.0.63, 0.0.64, 0.0.7, 0.0.8, 0.0.9]'
And i need to get the last version (0.0.64), Versions.sort() && Collections.max(Versions) doesn't work for me.
So I developed this function blow
def mostRecentVersion(def versions) {
def lastversion = "0.0.0"
for (def items : versions) {
def version = items.tokenize('-')[0]
def ver = version.tokenize('.')
def lastver = lastversion.tokenize('.')
if (lastver[0].toInteger() < ver[0].toInteger() ){
lastversion = version
}else if(lastver[0].toInteger() == ver[0].toInteger()) {
if (lastver[1].toInteger() < ver[1].toInteger() ){
lastversion = version
}else if(lastver[1].toInteger() == ver[1].toInteger()){
if (lastver[2].toInteger() < ver[2].toInteger() ){
lastversion = version
}
}
}
}
return lastversion }
i'm asking if there is something better,
Thank you for help :)
the idea:
build map with sortable key and original version value, then sort map by keys, then get only values
to create sortable key for each value
split version to digits & not-digit strings array
prepend to each part 0 to have minimum length 3 (assume each number not longer then 3 digits)
join array to string
so, for 0.11.222-dev ->
1. [ '0', '.', '11', '222', '-dev' ]
2. [ '000', '00.', '011', '222', '-dev' ]
3. '00000.011222-dev'
the code
def mostRecentVersion(versions){
return versions.collectEntries{
[(it=~/\d+|\D+/).findAll().collect{it.padLeft(3,'0')}.join(),it]
}.sort().values()[-1]
}
//test cases:
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16',
'0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24',
'0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33',
'0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41',
'0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49',
'0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54',
'0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61',
'0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'
I believe this will work... it also keeps the original version strings around, incase 0.5.5-devel.5 is the latest... It relies on the fact that Groovy will use a LinkedHashMap for the sorted map, so the order will be preserved :-)
def mostRecentVersion(def versions) {
versions.collectEntries {
[it, it.split(/\./).collect { (it =~ /([0-9]+).*/)[0][1] }*.toInteger()]
}.sort { a, b ->
[a.value, b.value].transpose().findResult { x, y -> x <=> y ?: null } ?:
a.value.size() <=> b.value.size() ?:
a.key <=> b.key
}.keySet()[-1]
}
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16', '0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24', '0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33', '0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41', '0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49', '0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54', '0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61', '0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'
Edit:
Made a change so that 0.5.5.5 > 0.5.5-devel.5

How do you do simple string concatenation in Terraform?

I must be being incredibly stupid but I can't figure out how to do simple string concatenation in Terraform.
I have the following data null_data_source:
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api.${var.env_name == "prod" ? "" : var.env_name}mydomain.com"
}
}
So when env_name="prod" I want the output app.api.mydomain.com and for anything else - let's say env_name="staging" I want app.api.staging.mydomain.com.
But the above will output app.api.stagingmydomain.com <-- notice the missing dot after staging.
I tried concating the "." if the env_name was anything but "prod" but Terraform errors:
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api.${var.env_name == "prod" ? "" : var.env_name + "."}mydomain.com"
}
}
The error is __builtin_StringToInt: strconv.ParseInt: parsing ""
The concat() function in TF appears to be for lists not strings.
So as the title says: How do you do simple string concatenation in Terraform?
I can't believe I'm asking how to concat 2 strings together XD
Update:
For anyone that has a similar issue I did this horrific workaround for the time being:
main_api_gw = "app.api.${var.env_name == "prod" ? "" : var.env_name}${var.env_name == "prod" ? "" : "."}mydomain.com"
I know this was already answered, but I wanted to share my favorite:
format("%s/%s",var.string,"string2")
Real world example:
locals {
documents_path = "${var.documents_path == "" ? format("%s/%s",path.module,"documents") : var.documents_path}"
}
More info:
https://www.terraform.io/docs/configuration/functions/format.html
so to add a simple answer to a simple question:
enclose all strings you want to concatenate into one pair of ""
reference variables inside the quotes with ${var.name}
Example: var.foo should be concatenated with bar string and separated by a dash
Solution: "${var.foo}-bar"
Try Below data resource :
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api${var.env_name == "prod" ? "." : ".${var.env_name}."}mydomain.com"
}
}
For Terraform 0.12 and later, you can use join() function:
join(separator, list)
Example:
> join(", ", ["foo", "bar", "baz"])
foo, bar, baz
> join(", ", ["foo"])
foo
If you just want to concatenate without a separator like "foo"+"bar" = "foobar", then:
> join("", ["foo", "bar"])
foobar
Reference: https://www.terraform.io/docs/configuration/functions/join.html
Use the Interpolation Syntax for versions < 0.12
Here is a simple example:
output "s3_static_website_endpoint" {
value = "http://${aws_s3_bucket.bucket_tf.website_endpoint}"
}
Reference the Terraform Interpolation docs:
https://developer.hashicorp.com/terraform/language/expressions/strings#string-templates
after lot of research, It finally worked for me. I was trying to follow https://www.hashicorp.com/blog/terraform-0-12-preview-first-class-expressions/, but it did not work. Seems string can't be handled inside the expressions.
data "aws_vpc" "vpc" {
filter {
name = "tag:Name"
values = ["${var.old_cluster_fqdn == "" ? "${var.cluster_fqdn}" : "${var.old_cluster_fqdn}"}-vpc"]
}
}

looping a template using groovy GStringTemplateEngine()

My requirement is to create a template engine to support a looping in it.
The final template should look something like this:
#cat output.template
env:
- name : param1
value : 1
- name : param2
value : 2
I have pseudo code to explain my requirement
def f = new File('output.template')
def engine = new groovy.text.GStringTemplateEngine()
def mapping = [
[ name : "param1",
value : "1"],
[ name : "param2",
value : "2" ]
] // This mapping can consists of a multiple key value pairs.
def Template = engine.createTemplate(f).make(mapping)
println "${Template}"
Can someone help me how to achieve this requirement of looping inside the templates and how should I modify my template?
*UPDATE : All the solutions provided by tim_yates or by Eduardo Melzer has resulted in following output with extra blank lines at the end of template. What could be the reason for that?* Are the solution providers not able to see this behavior or the issue is my system only?.
# groovy loop_template.groovy
env:
- name: param1
value : 1
- name: param2
value : 2
root#instance-1:
Change your template file to look like this:
#cat output.template
env:<% mapping.eachWithIndex { v, i -> %>
- name : ${v.name}
value : ${v.value}<% } %>
As you can see, your template file expects an input parameter called mapping, so you need change your main code to something like this:
def f = new File('output.template')
def engine = new groovy.text.GStringTemplateEngine()
def mapping = [
[ name : "param1", value : "1"],
[ name : "param2", value : "2"]
] // This mapping can consists of a multiple key value pairs.
def Template = engine.createTemplate(f).make([mapping: mapping])
println "${Template}"
Output:
#cat output.template
env:
- name : param1
value : 1
- name : param2
value : 2

Groovy TimeCategory bad millseconds addition

When try this sample code:
use(groovy.time.TimeCategory) {
800.millisecond + 300.millisecond
}
in groovy web console, I get a funny result:
0.1100 seconds
Does any one know why this happens or how to fix it?
That looks like a bug, the TimeDuration contains 1100 milliseconds, but when it prints it out, it converts it wrongly to seconds.
I've added it to the Groovy JIRA as a bug EDIT It's now marked as FIXED for versions 2.0.6, 1.8.9 and 2.1.0
In the mean time, I guess you'll need to do your own converter from TimeDuration to String :-/
Edit
You could do something like this (and there is probably a neater way of doing it)
groovy.time.TimeDuration.metaClass.normalize = { ->
def newdmap = ['days','hours','minutes','seconds','millis'].collectEntries {
[ (it):delegate."$it" ]
}.with { dmap ->
[millis:1000,seconds:60,minutes:60,hours:24,days:-1].inject( [ dur:[ days:0, hours:0, minutes:0, seconds:0, millis:0 ], roll:0 ] ) { val, field ->
val.dur."$field.key" = dmap."$field.key" + val.roll
val.roll = val.dur."$field.key".intdiv( field.value )
val.dur."$field.key" = field.value < 0 ?
val.dur."$field.key" :
val.dur."$field.key" % field.value
val
}.dur
}
new TimeDuration( newdmap.days, newdmap.hours, newdmap.minutes, newdmap.seconds, newdmap.millis )
}
That adds a normalize method to TimeDuration, so then doing:
use(groovy.time.TimeCategory) {
800.millisecond + 300.millisecond
}.normalize()
Shows 1.100 seconds
I haven't done a huge amount of testing on that method, so be warned it could do with some unit tests to make sure it doesn't fall over with other situations.

Groovy 1.7 changes "final"?

Just started learning Groovy, got the PragProg book "Programming Groovy" and had a problem compiling one of the sample scripts:
class GCar2 {
final miles = 0
def getMiles() {
println "getMiles called"
miles
}
def drive(dist) {
if (dist > 0) {
miles += dist
}
}
}
def car = new GCar2()
println "Miles: $car.miles"
println 'Driving'
car.drive(10)
println "Miles: $car.miles"
try {
print 'Can I see the miles? '
car.miles = 12
} catch (groovy.lang.ReadOnlyPropertyException ex) {
println ex.message
GroovyCar2.groovy: 20: cannnot access final field or property outside of constructor.
# line 20, column 35.
def drive(dist) { if (dist > 0) miles += dist }
^
Groovy versions prior to 1.7 do not give an error. I looked through whatever documentation I could find and did not see the issue discussed. What is going on here?
Aaron
I don't know much about Groovy 1.7, but it looks like a bug in earlier versions which has now been fixed - if a variable is final, you shouldn't be able to assign to it outside the constructor (or its declaration). If you can, what's the point of making it final?
I doubt that it'll stop you from reading it outside the constructor though...
You shouldn't be able to assign to a final variable in a normal method. It was a bug in groovy, fixed in 1.7.

Resources