Appending 'variables' to a Construction Environment - scons

I need to add platform-specific build variables to a SCons script I'm writing, and to do this, as far as I know, I need to create a Construction Environment before defining the variables so that I can actually check the platform (env['PLATFORM'] etc.) If I do this, I have to append the variables afterwards, but for some reason it's not working.
env = Environment()
vars = Variables()
if env['PLATFORM'] == 'win32':
default_prefix = 'C:\Program Files\Example'
elif env['PLATFORM'] == 'posix':
default_prefix = '/usr/local/example'
vars.Add(PathVariable('prefix', 'installation path', default_prefix))
env.Append(variables = vars)
print env['prefix'] # error
I've found that a workaround is to just create the Environment again
env = Environment(variables = var)
but I was wondering if there's a better way, and why appending it doesn't work in the first place.

I am guessing what you are looking for here but is it this:
Update(env,variables)
Using this function you update the environment with the variables argument.
I think the reason for the Append(variables=x) doesn't work is that the variables isn't
a part of the "dictionary" environment, actually, if you pass variables into the constructor of the environment, inside the constructor the variables object will update the environment.

I usually fetch the platform from
platform = Environment()["PLATFORM"]
then I can create the environment based on this knowledge.

Related

How to execute a code from another script and pass arguments

I have a python code try.py which has to execute another one called prova.py.
I do it as folows and it works:
exec(open("prova.py").read())
Now, I have some variables I need to pass to prova.py, and I did it as follows according to what found here: https://www.geeksforgeeks.org/exec-in-python/
var = {key:val for key, val in enumerate(lista_gp_todict)}
exec(open("prova.py").read(), var)
try.py does not give error which means the way I write exec now is still correct in terms of syntax, but in the moment this exec runs it gives error in prova.py:
NameError: name 'var' is not defined
which mean that the code prova.py which has inside the variable var does not recognise it, like it was not declared. In fact var is not declared into prova.py because if I pass it I assume it already there.
What am I doing wrong?
PS: my OS is windows
Typically you would call another script with the subprocess module.
subprocess.run() accepts an iterable of strings as arguments to be run as a separate process. You can use the arguments exactly as you would call them from command line.
subprocess.run(['python', 'prova.py', my_argument])
Since you wish to pass a dict to your script, you can do so by first serializing to json, which is just a nice way of saying "convert it to a string".
Since var is your dict you can do so like.
subprocess.run(['python', 'prova.py', json.dumps(var)])
And then deserialize or "convert back to a dict" in prova.py.
var = json.loads(sys.argv[1])
Alternatively, you could import prova.py if all you intend to use from it are functions, classes, or variables.
For example, if prova.py contains:
# prova.py
def my_func(var):
# do some stuff to var
You can then do this in your main script:
import prova
var = {key:val for key, val in enumerate(lista_gp_todict)}
prova.my_func(var)

How to list all variables listed in a dot env file (e.g: .env.local.example)

I'd like to iterate over a list (in Node.js) of env variables defined in a .env.local.example, without loading those variables. (they must not replace the existing variables)
So, I basically want to read those, should I use a dot-env specific tool, or can I simply grab any YAML parser?
I don't care about the values, I only care about the keys in the .env.local.example file.
So, given the following .env.local.example:
FAUNADB_SERVER_SECRET_KEY=
MAGIC_AUTH_SECRET_KEY=
I want to get an array of strings ['FAUNADB_SERVER_SECRET_KEY', 'MAGIC_AUTH_SECRET_KEY'].
If you don't want to load your .env.local.example to avoid replacing of existing variables.
Try to use fs, with the help of regex.
Here's an example:
const fs = require('fs');
const path = require('path');
let arr_env = fs.readFileSync(path.join(__dirname, '.env.local.example'), 'utf-8').match(/^[A-Za-z0-9_]+/gm);
console.log(arr_env);
// Expected Result: ['FAUNADB_SERVER_SECRET_KEY', 'MAGIC_AUTH_SECRET_KEY']
You can try
Console.log(Object.keys(process.env))
But just be cautious, local system adds extra variables too (like vsCode add some different things too, that got added in process.env also), so you might get extra variables from you system too.

Details about ApplicationUnderTest.Launch() method's fileName and alternateFileName arguments

I'm having a hard time trying to figure out some details about the arguments of the ApplicationUnderTest.Launch(String, String) method. From the MSDN page, they are described like this:
fileName
Type: System.String
The file name of the application to start.
alternateFileName
Type: System.String
The alternate file name that has environment variables.
My questions are:
What is the purpose of alternateFileName? Is it only used when fileName is not found or not valid? Does the Launch() method always try the fileName first?
Does fileName support environment variables in it? Does alternateFileName always require at least one environment variable in it?
Based on my own experience (and a little help from a decompiler), here's what I've discovered.
What is the purpose of alternateFileName?
alternateFileName allows you to use a path with environment variables that are expanded at run time. There is also some special handling to convert environment variables only found on a 64-bit environment to those found on a 32-bit environment, if necessary (for example, converting %programfiles(x86)% to %programfiles%).
Is it only used when fileName is not found or not valid? Does the Launch() method always try the fileName first?
If you use one of the Launch() overloads that include the alternateFileName parameter, it is always checked first. If there is a matching file at the expanded path, then that path is used and fileName is never checked. If there is no matching file at the expanded alternateFileName path, only then will it use fileName.
Note: I just discovered a bug present in Visual Studio 2013 Update 4 where alternateFileName is in fact incorrectly handled on a 32-bit system. In that case, alternateFileName was always getting prepended with the value C:\Windows\System32 so it would end up with a value like C:\Windows\System32C:\Program Files\foo\bar.exe. Since this is an invalid value, the system was only relying on fileName.
Does fileName support environment variables in it?
No, any environment variables in fileName are not expanded.
Does alternateFileName always require at least one environment variable in it?
No, environment variables are not required -- although I can't think of how it would be useful to supply a value for alternateFileName without them.
Here's what I do:
private static ApplicationUnderTest _application;
public static ApplicationUnderTest LaunchApplicationUnderTest(string applicationPath,
bool closeOnPlaybackCleanup)
{
Process[] processes = Process.GetProcessesByName("MyApp");
if (processes.Length > 0)
{
_application = ApplicationUnderTest.FromProcess(processes[0]);
}
else
{
_application = ApplicationUnderTest.Launch(applicationPath);
_application.CloseOnPlaybackCleanup = closeOnPlaybackCleanup;
}
return _application;
}

Adding Barewords to Lua

To implement a domain specific language, within lua,
I want to add barewords to the language.
So that
print("foo") could be written as print(foo)
The way I have done this is by changing the metatable of the enviroment table _G.
mt = {__index = function(tbl,key) return key end}
setmetatable(_G, mt)
And that works, because retrieving the value of variable foo is done by _G.foo which is equivalent to _G["foo"]
Is this a good approach?
Are there hidden downsides?
Is there a better way?
Can I do it so that barewords only work inside a certain file?
(Perhaps by executing that file, from another luascript, using loadstring)
As soon as someone declares a local with the same name of your "keywords" it will shadow your "keyword/global var" and your mechanism will fail:
print(foo) -- does what you think
local foo = 2
print(foo) -- argh!
and note that you cannot prevent the definition of local variables in a script.
Edit: (answering to a comment).
Are you using a customized Lua engine? You cannot prevent entering local scope, because you are always in local scope. It is exactly the other way around: technically there is no global scope in Lua (with the same meaning as in C, for example). There is a global namespace (implemented as a table), instead. The mechanisms for accessing globals differs between Lua 5.1 (function environments) and Lua 5.2 (implicit _ENV prefixing), but the concept is almost the same.
In particular, when a Lua script is loaded, whether by the interpreter, or by load, loadstring, dofile, etc., it is interpreted as the body of an anonymous function (a closure), usually referred to as the "main chunk". Thus there is always a local scope. In standard Lua you cannot prevent the definition of a local variable when the parser encounters a local statement in the script being loaded.

append value to environment variable on builder call

The problem is as follows:
I have an environment with some variables defined like this:
env = Environment(CPPPATH=['#/include'])
In some cases I need to invoke a builder with some extra values which should not be added permanently to the environment to not unnecessarily pollute it.
One way is to append the extra value to the builder call by merging it with the environment's value.
env.Object('test.c', CPPPATH=['#/some_other_include_path']+env['CPPPATH'])
Is there a more elegant way to do it?
I do this by cloning the env and appending on to it, like this:
clonedEnv = env.Clone()
clonedEnv.Append(CPPPATH=['#anotherPath'])
clonedEnv.Object('test.c')
A more pythonic (and efficient) way to do what you are doing would be to use the python list.extend() function:
cpppath = ['path1', 'path2']
cpppath.extend(env['CPPPATH'])
env.Object('test.c', CPPPATH = cpppath)

Resources