if condition always returning False - powershell-2.0

I am writing a powershell-v2.0 script. The script contains a function to set environment variable. The function is as follows:
function SetSvnEnvironmentVariable($path)
{
# Get the Path environment variable
$pathVar = [Environment]::GetEnvironmentVariable("Path","User")
# Check if path environment variable already contains the path to be added
if(-Not ($pathVar -like $path))
{
$pathVar += $path
[Environment]::SetEnvironmentVariable("Path",$pathVar, [System.EnvironmentVariableTarget]::User)
}
}
The $path variable contains the path to be added to the PATH environment variable.
The problem I am facing is, even though $path is a substring of $pathVar, the if condition always returns False.
Following are the values of $pathVar and $path.
$pathVar:
C:\Program Files (x86)\MATLAB\R2009b\bin\win32;C:\Program Files\TortoiseSVN\bin
$path:
;C:\Program Files\TortoiseSVN\bin

Using wildcard or regular expression matches for this kind of check bears the risk of getting false positives if the path already contains a subfolder of the folder you want to add. It's better to split the value of the environment variable at semicolons and use the -contains/-notcontains operator to check if the resulting array does or doesn't contain the item you want to add:
function SetSvnEnvironmentVariable($path)
{
$pathVar = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($pathVar.Split(';') -notcontains $path))
{
$pathVar += ";$path"
[Environment]::SetEnvironmentVariable('Path', $pathVar, [EnvironmentVariableTarget]::User)
}
}
Note that $path should not be specified with a leading (or trailing) semicolon.

Using a wildcard fixed my problem. -like operator without a wildcard compared the strings if they were equal and hence always returned False.
By changing the if condition as follows, the if condition returns True:
if(-Not ($pathVar -like "*$path*"))
{
....
}

Related

Jenkins Pipeline define and set variables

I am using branch name to pass it into build script. $(env.BRANCH_NAME).
I would like to manipulate the value before using it. For example in case we build from trunk I want suffix for the build output be empty but in case of branch I want it to be -branch name.
currently I am doing it by defining environment section.
environment {
OUTPUT_NAME_SUFFIX = ($(env.BRANCH_NAME) == 'trunk') ? '': $(env.BRANCH_NAME)
}
I am getting this error:
WorkflowScript: 4: Environment variable values must either be single quoted, double quoted, or function calls. # line 4, column 62.
(env.BRANCH_NAME) == 'trunk') ? '': $(en
^
What the best way to define variables and eval their values in scope of pipeline.
TIA
You can use string interpolation to evaluate the expression:
environment {
OUTPUT_NAME_SUFFIX = "${env.BRANCH_NAME == 'trunk' ? '': env.BRANCH_NAME}"
}
This will fix the error you're getting, however pipeline does not allow you to have environment variables that are of 0 length, aka empty string (JENKINS-43632).
That means that setting OUTPUT_NAME_SUFFIX to '' is like unseting it. You might want to precalculate the whole name of your output, so that your env variable is never an empty string.
I have solved it by adding following code. So far had no issues with empty strings.
stage('Set Environmnet'){
steps {
script {
if(BRANCH_NAME == 'trunk'){
env.OUTPUT_NAME_SUFFIX = ''
}else if (BRANCH_NAME.startsWith("branches")){
env.OUTPUT_NAME_SUFFIX = "-" + BRANCH_NAME.substring(BRANCH_NAME.lastIndexOf("/")+1)
}else{
env.OUTPUT_NAME_SUFFIX = ''
}
}
}
}

Comparing 2 parameters in Jenkins pipeline in a single command

what is wrong with below code, comparing 2 strings in groovy
I am trying do the comparison between the 2 parameters in a single line to make it look tidier
if (params.dirname == ((params.path =~ ~/${params.dirname}/).with { matches() ? it[0] : null })) {
print success
}
Throwing Exception -
java.lang.NoSuchMethodError: No such DSL method 'matches' found among steps
There is no need to over-complicate your use case. According to:
params.dirname = hde, params.path = /usr/tmp/jenkins/hde/filename.txt or /usr/hde/jenkins/ing/filename.txt or any random path which has hde in it
you are trying to find if given string a contains substring b. It can be done using Java's method String.contains(String substring). Alternatively you can use regular expression for that, but String.contains() just looks a few times simpler to understand what is your intention. Consider following Groovy script:
def params = [
dirname: 'hde',
path: '/usr/tmp/jenkins/hde/filename.txt'
]
// Using String.contains()
if (params.path.contains(params.dirname)) {
println "Path '${params.path}' contains '${params.dirname}'"
}
// Using regular expression
if (params.path ==~ /(.*)${params.dirname}(.*)/) {
println "Path '${params.path}' contains '${params.dirname}'"
}
When you run it both if statements evaluates to true:
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'

How can I include the current workspace name in the default argument value of a rule?

Let's say I have a rule:
blah = rule(
attrs = {
"foo": attr.string(default = "#HELP#"),
},
)
I want the default value of foo to contain the name of the workspace that invokes the rule. How can I accomplish this?
(Note: An acceptable approach is to leave a placeholder in the value and replace it when the rule uses the attribute, but I can't figure out how to get the current workspace there either. The closest I can find is ctx.label.workspace_root, but that is empty for the "main" workspace, and e.g. external/foo for other things.)
ctx.workspace_name does not give the correct answers. For example, if I print("'%s' -> '%s'", (ctx.label.workspace_root, ctx.workspace_name)), I get results like:
'externals/foo' -> 'main'
'externals/bar' -> 'main'
...which is wrong; those should be 'foo' and 'bar', not 'main' ('main' being my main/root workspace). Note that labels from those contexts are e.g. '#foo//:foo', so Bazel does apparently know the correct workspace name.
You can use a placeholder attribute and then use ctx.workspace_name in the implementation.
def _impl(ctx):
print("ws: %s" % ctx.workspace_name)
blah = rule(
implementation = _impl,
)
As far as getting the workspace name, this seems sub-optimal, but also seems to work:
def _workspace(ctx):
"""Compute name of current workspace."""
# Check for meaningful workspace_root
workspace = ctx.label.workspace_root.split("/")[-1]
if len(workspace):
return workspace
# If workspace_root is empty, assume we are the root workspace
return ctx.workspace_name
Per Kristina's answer and comment in the original question, this can then be used to replace a placeholder in the parameter value.

How to handle unexisting variables passed to a proc

I would like to create a procedure like this simple example:
proc name {args} {
foreach val $args {
puts $val
}
}
But I would like the procedure to handle variables that don't exist, something like the code shown below:
proc name {args} {
foreach val $args {
if [info exists $val] {
puts $val
}
}
}
The problem is that the code is not executed because as soon as I call the procedure with an unexisting variable it immediately stalls, prior to go into the code, saying that there is a variable that doesn't exist. Is it probable because the procedure checks argument existance before entering the body?.
I can make it work by changing args by several optional variables with predefined values, but that limits the procedure and makes it look bad.
Can I make a proc able to handle unexisting variables?
You can't pass a variable as an argument: arguments have to be values. You can pass a variable name as an argument and use that as a reference to the variable inside the procedure. Example:
proc name args {
foreach varname $args {
upvar 1 $varname var
if {[info exists var]} {
puts $var
}
}
}
(The call to upvar creates a link between the variable whose name is the value of the variable varname outside the procedure and the variable called var inside the procedure. This is one way to "pass a variable to a procedure".)
Then you can do this:
% set foo 1 ; set baz 3
% name foo bar baz
1
3
Note that if you try to invoke the procedure as
% name $bar
where bar is undefined, the interpreter tries (and fails) to evaluate it before calling the procedure. That might be what you are seeing.
Documentation:
upvar
If we look at the point where you are calling the command (procedures are commands; they're a subclass really) you'll see something like this in your code:
name $a $b $c
That's fine if all those variables exist, but if one doesn't, it will blow up even before name is called. In Tcl, $a means exactly “read the variable a and use its contents here”, unlike in some other languages where $ means “look out language, here comes a variable name!”
Because of this, we need to change the calling convention to be one that works with this:
name a b c
That's going to require the use of upvar. Like this:
proc name {args} {
foreach varName $args {
# Map the caller's named variable to the local name “v”
upvar 1 $varName v
# Now we can work with v in a simple way
if {[info exists v]} {
puts $v
}
}
}
You made a mistake here
if [info exists $val]
When info exists is used it should be checked against variable name, not the variable value.
Lets come to your actual question.
You can pass the arguments to the procedure as a key-value pair, then it is pretty simple.
proc user_info {args} {
#Converting the arguments into array
if {[catch {array set aArgs $args}]} {
puts "Please pass the arguments as key-value pair"
return 1
}
#Assume, we need to ensure these 3 arguments passed for sure.
set mandatoryArgs "-name -age -country"
foreach mArg $mandatoryArgs {
if {![info exists aArgs($mArg)]} {
puts "Missing mandatory argument '$mArg'"
return 1
}
}
}
user_info -name Dinesh

lua how require works

I'm using a graphics library that lets you program in Lua. I have a need for the A* pathfinding library so I found one online. It's just 1 lua file that does the pathfinding and 1 example file. In the example file it uses the object like:
-- Loading the library
local Astar = require 'Astar'
Astar(map,1) -- Inits the library, sets the OBST_VALUE to 1
I run the script and everything works. So now I add the Astar.lua file to the path location where my graphics engine is running and do the same thing and I get the error on the Astar(map, 1) line:
"attempt to call local 'AStar' (a number value)
Any ideas why I would be getting that error when I'm doing the same thing as the example that comes with this AStar lib?
Here is a little of the AStar file
-- The Astar class
local Astar = {}
setmetatable(Astar, {__call = function(self,...) return self:init(...) end})
Astar.__index = Astar
-- Loads the map, sets the unwalkable value, inits pathfinding
function Astar:init(map,obstvalue)
self.map = map
self.OBST_VALUE = obstvalue or 1
self.cList = {}
self.oList = {}
self.initialNode = false
self.finalNode = false
self.currentNode = false
self.path = {}
self.mapSizeX = #self.map[1]
self.mapSizeY = #self.map
end
So note that when I run this from my graphics engine it's returning 1, but when run from the example that it came with it's returning a table, which is what it should be returning. So not sure why it would only be returning 1.
How is Astar getting added to the package.loaded table for the example script, as opposed to your code?
QUICK LUA SYNTACTIC SUGAR REVIEW:
func 'string' is equivalent to func('string')
tabl.ident is equivalent to tabl['ident']
When you run a script using require('Astar'), this is what it does:
checks if package.loaded['Astar'] is a non-nil value.
If it is, it returns this value. Otherwise it continues down this list.
Runs through filenames of the patterns listed in package.path (and package.cpath), with '?' replaced with 'Astar', until it finds the first file matching the pattern.
Sets package.loaded['Astar'] to true.
Runs the module script (found via path search above- for the sake of this example we'll assume it's not a C module) with 'Astar' as an argument (accessible as ... in the module script).
If the script returns a value, this value is placed into package.loaded['Astar'].
The contents of package.loaded['Astar'] are returned.
Note that the script can load the package into package.loaded['Astar'] as part of its execution and return nothing.
As somebody noted in the comments above, your problem may come from loading the module using 'AStar' instead of 'Astar'. It's possible that Lua is loading this script using this string (since, on the case-insensitive Windows, a search for a file named "AStar.lua" will open a file called "Astar.lua"), but the script isn't operating with that (by using a hard-coded "Astar" instead of the "AStar" Lua is loading the script under).
You need to add return Astar at the end of Astar.lua.

Resources