gradle: Execute task "type:Exec" with many arguments with spaces - batch-file

I have the gradle task that should create Websphere profile on Windows OS
task createProfile(type:Exec) {
def commandToExecute = new StringBuffer()
def profile = 'AppSrv02'
def wasHome = 'C:/IBM new/WebSphere/AppServer'
def str = new LinkedList <String> ();
str.add('cmd')
str.add('/c')
str.add(wasHome + '/bin/manageprofiles.bat')
str.add('-create')
str.add('-profileName')
str.add(profile)
//str.add('-templatePath')
//str.add(wasHome + '/profileTemplates/default')
println (str)
commandLine str.toArray()
}
And the problem appears if I uncomment commented lines, after it task fails and say me that: "C:/IBM" is not valid batch file. If I put profileTemplates not in the folder that contains spaces, everything works fine again. But templates should lies int wasHome( And sometimes wasHome has spaces(
I have, now ideas why adding templates key with value with spaces influence in such way that Gradle tries to start "C:/IBM" instead specified 'C:/IBM new/WebSphere/AppServer/bin/manageprofiles.bat'. It seems that, possibly, problem inside java.lang.ProcessBuilder.
I tries to quote paths, by adding "/"" but nothing works(((( what isn't surprise, because ProcessBuilder implies quoting by itself if it is needed.
So, I am asking if anybody had the similar problem and could recommend how to work around this issue? Thanks in advance.

If somebody needed it, we found a workaround for this problem. The task finally looks like:
task createProfile(type: Exec) {
executable = new File(wsadminLocation, manageProfilesFileName)
def templatePath = wasHome + File.separator + "profileTemplates" + File.separator + "default"
def argsList = ["-create", "-profileName", profile, "-templatePath", templatePath, "-nodeName", nodeName, "-cellName", wasCellName, "-enableAdminSecurity", isProfileSecured, "-adminUserName", rootProject.wasLogin, "-adminPassword", rootProject.wasPassword]
args = argsList
}
The basic idea is to pass the arguments to the Gradle not as long string, but as a list. So in this way there aren't any problems if an argument contains a space.

Change following lines
def wasHome = '"C:/IBM new/WebSphere/AppServer'
...
str.add(wasHome + '/bin/manageprofiles.bat"')
That way, the full path to the batch file is quoted.
EDITED - As stated by dbenhan, a little obfuscated. This "should" be something like
task createProfile(type:Exec) {
def commandToExecute = new StringBuffer()
def profile = 'AppSrv02'
def wasHome = 'C:/IBM new/WebSphere/AppServer'
def str = new LinkedList <String> ();
str.add('cmd')
str.add('/c')
str.add('"' + wasHome + '/bin/manageprofiles.bat"')
str.add('-create')
str.add('-profileName')
str.add(profile)
str.add('-templatePath')
str.add('"' + wasHome + '/profileTemplates/default"')
println (str)
commandLine str.toArray()
}
BUT, while gradle in particular and windows in general can handle paths with slash separators, i have no idea if manageprofiles.bat can, and you are passing a parameter with a path in it. Maybe, you will need to change your paths to 'c:\\IBM new\\....'

Try This
task xyz {
def result1 = exec {
workingDir "D:/abc/efg"
commandLine 'cmd', '/c', 'CDUTIL.bat', "qwe", "rty"
}
println result1.toString()
}

Related

Making a command that shows all your cooldowns and the time remaining

I need a command that shows the list of the commands with cooldowns and the time remaining to use the command again. Is it possible especially putting the command in a cog? If yes, can you help me how to do the command?
It's definitely possible, to get all commands in cooldown and their remaining time. However, discord.py does not give direct access to it, and thus we have to abuse private class variables to get them
Code:
import datetime
#client.command()
async def cooldowns(ctx: commands.Context):
string = ""
for command in client.walk_commands():
dt = ctx.message.edited_at or ctx.message.created_at
current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
bucket = command._buckets.get_bucket(ctx.message, current)
if not bucket:
continue
retry_after = bucket.update_rate_limit(current)
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
string = string or "No commands are on cooldown"
await ctx.send(string)
Here is what the above code will look like for commands not on cooldown:
It will follow:
command 1 - READY
command 2 - READY
...
command n - READY (and so on)
and, here is how it will look if commands are on cooldown:
Explaining how the code works:
string = ""
We initialize an empty string in a string variable, this is the string we will add our lines to and send it all at once.
for command in bot.walk_commands():
dt = ctx.message.edited_at or ctx.message.created_at
current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
bucket = command._buckets.get_bucket(ctx.message, current)
bot.walk_command() is a method that gives us a generator object, which is essentially a generator of all the command objects the bot has stored (i.e: everything under #bot.command(), #commands.command, and #commands.group)
dt is just storing the current time the message was created at, it's a datetime object
message.created_at is a time naive offset and so we bind a timezon to it with its replace method and then we get a timestamp of that with the timestamp() method of datetime.datetime objects
all of the things we did is a waste, the third line is the meat and potatoes of what we want. command._buckets.get_bucket is an internal, we provide the current message object and the timestamp we created earlier.
This gives us our Cooldown object (The one you create with #commands.cooldown(1, 5, commands.BucketType.user), it basically yields what is inside the ()) [This is None for commands with no cooldowns]
here is what it looks like, just for understanding.
if not bucket:
continue
retry_after = bucket.update_rate_limit(current)
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
await ctx.send(string)
if not bucket:
continue
If a bucket is not found, command does not have cooldown, meaning we can skip over it.
retry_after = bucket.update_rate_limit(current)
This basically gets us our remaining time (it's a float)
returns None if it's not on cooldown
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
the if statement checks if it returned a float, if yet then command is on cooldown and we add the command name along side the cooldown time
the else is for if it's not on cooldown, then it adds the command name and READY along side it.
And at the end we send the entire string.
In my case, I only have one command that had cooldown, which is spotify.
Creating a command that shows all cooldowns is possible. You can do this with a for loop and the is_on_cooldown() function.
Here is an example of a command to return a list of commands and if they are on cooldown:
#client.command(pass_content=True)
async def cooldowns(ctx):
cooldown_string = ""
for command in client.commands:
if command.is_on_cooldown(ctx):
cooldown_string += f"\n{command} - **Time Left:** {command.get_cooldown_retry_after(ctx)}MS"
await ctx.send(cooldown_string)
From here you can add condition statements to only show commands on cooldown.

Return Stringbuilder when using variable name to create string builder

trying to return string builder in a loop. is this workable.. I am collecting a list with each(), then appending 'it' to "scriptBldr_" to create a different object name each time to hold the string. then I collect the object names in a list. And trying to return using a for loop for each object name. But it's failing.
List.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
StringBuilder $builderstring = StringBuilder.newInstance()
if (ValidUDA == "Region") {
$builderstring <<"""
XYZCode
"""
StringBuilders.add(builderstring)
}
}
for(item in StringBuilders)
{
return item
}
I guess the following code does what you intended to code:
def myList = ['Hello "World"', 'asb"r"sd']
def ValidUDA = "Region"
def builders = [:]
myList.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
builders[builderstring] = StringBuilder.newInstance()
if (ValidUDA == "Region") {
builders[builderstring] <<"""
XYZCode
"""
}
}
return builders
A return statement will immediatly return from the method and hence will exit the loop and only called once. So, I guess, what you wanted to achieve is to return a list of StrinngBuilders.
some hints:
it is unusual in Groovy to start a variable with $ and you can run into problems with such a naming
when asking a question on SO, try to come up with a working example. As you can see, you example was missing some definitions
Update: as you've stated in you comment that you tryed to create dynamic variable names, I've updated the code to use maps. The returned map now contains the StringBuilders together with their names.

How to use Groovy jenkins directory path as an Array

I am checking out files from git to jenkins in this format:
local/joules/.../dev/n-1a/pf-as.manifest
local/joules/.../dev/n-2a/pf-as.manifest
local/joules/.../sit/n-3b/pf-as.manifest
local/joules/.../sit/n-4a/pf-as.manifest
local/joules/.../perf/n-3b/pf-as.manifest
local/joules/.../perf/n-4a/pf-as.manifest
i want to change this in groovy script something like:
pf-as-dev-n-1a.manifest
pf-as-dev-n-2a.manifest
pf-as-sit-n-3b.manifest
pf-as-sit-n-4a.manifest
can i do it using some looping mechanism in groovy. I am able to achieve this on by one...but i need to implement it using loop.
I stuggled a lot, but not get yet. Any1 have idea please help.
Here you go
list.map { it.split("/") }.flatMap {
val lastPart = it.last().split(".")
val extension = lastPart.last()
val begin = lastPart.first()
val middle = it[it.size - 3]
val end = it[it.size - 2]
listOf("$begin-$middle-$end.$extension")
}
You could do this easily as below:
//list of file paths
def files = ['local/joules/.../dev/n-1a/pf-as.manifest',
'local/joules/.../dev/n-2a/pf-as.manifest',
'local/joules/.../sit/n-3b/pf-as.manifest',
'local/joules/.../sit/n-4a/pf-as.manifest',
'local/joules/.../perf/n-3b/pf-as.manifest',
'local/joules/.../perf/n-4a/pf-as.manifest']
println files.collect{it.substring(it.lastIndexOf('/')+1, it.length())}
Quickly try this online demo

Having trouble getting multiple command line arguments to run in windows forms

This has been bugging me this whole weekend...I'm a bit new at this so please bear with me.
I am trying to get this windows form button to execute the command line arguments I am passing to it but it is not working. It just stays at the working directory...
private void convert_Click(object sender, EventArgs e)
{
string safeFile = #textBox2.Text;
string safePass = #textBox3.Text;
string safeDir = #textBox4.Text;
Process test = new Process();
test.StartInfo.FileName = "cmd.exe";
test.StartInfo.UseShellExecute = false;
test.StartInfo.WorkingDirectory = #safeDir;
test.StartInfo.Arguments = "sqltosafe.exe" + #safeFile + "-password" + #safePass;
test.StartInfo.RedirectStandardOutput = true;
test.Start();
textBox1.Text = test.StandardOutput.ReadToEnd();
}
The application is supposed to:
1) One the "convert" button is clicke, it will grab the location of where the .exe is located.
2)Execute upon that .exe with the command-line arguments such as:
C:\SafetoSQL\SafetoSQL.exe (location of .safe file) -password (password)
I've been searching all over the web to figure out how to get it work but to no avail. I think it could be a simple solution and that maybe I'm a N00B at this but I am working on getting better.
Thank you all for reading and I hope you all can provide some input on where I should look for figuring this out.
It looks like you failed to add spaces and quotation marks to the command-line arguments.
test.StartInfo.Arguments = "sqltosafe.exe" + #safeFile + "-password" + #safePass;
Should be:
test.StartInfo.Arguments = "sqltosafe.exe \"" + safeFile + "\" -password \"" + safePass + "\"";
Or using a format string instead of concatenation, which is clearer and doesn't create intermediate strings:
test.StartInfo.Arguments = String.Format("sqltosafe.exe \"{0}\" -password \"{1}\"", safeFile, safePass);
The reason you need the quotation marks is that the user-supplied values may contain spaces and spaces deliminate command-line parameters.
You should also validate the user-supplied strings to make sure at the very least they are not empty.

Groovy read most recent file in directory

I just have a question about writing a function that will search a directory for the most recent log in a directory. I currently came up with one, but I'm wondering if there is a better (perhaps more proper) way of doing this.
I'm currently using hdsentinel to create logs on computer and placing the log in a directory. The logs are saved like so:
/directory/hdsentinel-computername-date
ie. C:/hdsentinel-owner-2010-11-11.txt
So I wrote a quick script that loops through certain variables to check for the most recent (within the past week) but after looking at it, I'm question how efficient and proper it is to do things this way.
Here is the script:
String directoryPath = "D:"
def computerName = InetAddress.getLocalHost().hostName
def dateToday = new Date()
def dateToString = String.format('%tm-%<td-%<tY', dateToday)
def fileExtension = ".txt"
def theFile
for(int i = 0; i < 7; i++) {
dateToString = String.format('%tY-%<tm-%<td', dateToday.minus(i))
fileName = "$directoryPath\\hdsentinel-$computerName-$dateToString$fileExtension"
theFile = new File(fileName)
if(theFile.exists()) {
println fileName
break;
} else {
println "Couldn't find the file: " + fileName
}
}
theFile.eachLine { print it }
The script works fine, perhaps it has some flaws. I felt I should go ahead and ask what the typical route is for this type of thing before I continue with it.
All input is appreciated.
Though a bit messy, you could implement a multi-column sort via the 'groupBy' method (Expounding on Aaron's code)..
def today = new Date()
def recent = {file -> today - new Date(file.lastModified()) < 7}
new File('/yourDirectory/').listFiles().toList()
.findAll(recent)
.groupBy{it.name.split('-')[1]}
.collect{owner, logs -> logs.sort{a,b -> a.lastModified() <=> b.lastModified()} }
.flatten()
.each{ println "${new Date(it.lastModified())} ${it.name}" }
This finds all logs created within the last week, groups them by owner name, and then sorts according to date modified.
If you have files other than logs in the directory, you may first need to grep for files containing 'hdsentinel.'
I hope this helps.
EDIT:
From the example you provided, I cannot determine if the least significant digit in the format:
C:/hdsentinel-owner-2010-11-11.txt
represents the month or the day. If the latter, sorting by file name would automatically prioritize by owner, and then by date created (without all of the chicanery of the above code).
For Instance:
new File('/directory').listFiles().toList().findAll(recent).sort{it.name}
Hopefully this helps some..This sorts a given path by date modified in a groovier way. The lists them out.
you can limit the list, and add other conditions in the closure to get the desired results
new File('/').listFiles().sort() {
a,b -> a.lastModified().compareTo b.lastModified()
}.each {
println it.lastModified() + " " + it.name
}
As I was trying to solve a similar problem, learnt a much cleaner approach.
Define a closure for sorting
def fileSortCondition = { it.lastModified() }
And File.listFiles() has other variation which accepts FileFilter and FilenameFilter in Java, and these interfaces has a single method called accept, Implement the interface as a closure.
def fileNameFilter = { dir, filename ->
if(filename.matches(regrx))
return true
else
return false
} as FilenameFilter
And lastly
new File("C:\\Log_Dir").listFiles(fileNameFilter).sort(fileSortCondition).reverse()
Implement FileFilter interface if filtering is to be done by File attributes.
def fileFilter = { file ->
if(file.isDirectory())
return false
else
return true } as FileFilter

Resources