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)
Related
In anchor the "top" of any program features a declare_id!() statement. The input to that statement is a Pubkey, typically in the form of a hard coded string. 12Factor Methodology typically dictates that hard coded configuration values like this should be avoided. However trying to not hard code the value has me pulling out my hair.
declare_id!(std::env::var("VARIABLE_NAME"));
Does not work because the env::var call executes at runtime while the macro executes at compile time.
declare_id!(env!("VARIABLE_NAME"));
Does not work because env! returns a &str.
declare_id!(Pubkey::from_str(env!("VARIABLE_NAME")));
Does not work because Pubkey::from_str can fail and as such returns a Result
declare_id!(Pubkey::from_str(env!("VARIABLE_NAME")).unwrap());
Does not work because declare_id! requires a constant and constants cannot be made from unwrap (Its probably more nuanced than that, but I'm new to rust) and ? fails for the same reason.
How would I go about defining an environment variable within a macro?
Given the lack of resources on the topic, I'm presuming an environment variable in this case is not a best practice. Why should one not use an environment variable in this case?
How can one accomplish the injection of program id into an anchor application if environment variables are not the way to do so?
Bonus points:
env::var() returns a Result<&str>
env::var_os() returns a Result<&OsStr>
env!() returns a &str
env_os!() does not exist in core
How do you handle an OsStr environment variable at build time? Why would you not need to be able to?
Working with env vars seems troublesome, since most of the ways of creating a Pubkey aren't const fn. To me, this seems like an issue with the anchor-lang crate, usually env vars aren't this troublesome.
That said, you could write the key to a config file somewhere, and read that in using include_bytes, and pass that to Pubkey::new_from_array, which is const:
// this works because concat! expands to a string literal
const BYTES: &[u8; 32] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/key"));
anchor_lang::declare_id!(Pubkey::new_from_array(*BYTES));
If you don't want to store the file in the repo, you can point include_bytes!() at any location, even one read from an env var. For example, you could have:
const BYTES: &[u8; 32] = include_bytes!(env!("ANCHOR_KEY_LOCATION"));
anchor_lang::declare_id!(Pubkey::new_from_array(*BYTES));
which will read the key bytes from a file at $ANCHOR_KEY_LOCATION
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.
I have an RPGLE program that I'm trying to convert from fixed-format to free-format. In general, I know that defining entry variables is done using prototypes like so:
dcl-pr myprogram;
I#Entry1 char(5);
end-pr;
dcl-pi myprogram;
InEntry1 char(5);
end-pi;
But what I don't know is how to do this when the field is already defined. We have a standard definitions file that we copy into programs such as the one I am writing, which has the field I'm using as the enter variable already defined and copied in. In fixed-format, this is just
C *Entry PList
C Parm InEntry1
I have already tried just doing the copy before the prototype entry and leaving the specification blank, but that caused errors. I know I could just use the 'LIKE' keyword and change the variable names, but for readability's sake I would prefer to avoid doing that, and I don't know what problems that may cause down the road.
Just in case it's necessary, there are two variables I'm trying to get in: a data structure and a zoned decimal.
How can I use a variable that is already defined as an entry variable in free-format RPGLE, whether using prototypes or some other way that I do not know of?
The "right" way to handle this would be to create a new version of your standard definitions file (StdDefs==>StdDefs2) to declare the variables under a new name (perhaps with a _t suffix) and the TEMPLATE keyword.
Then in your refactored PR/PI, you use LIKE or LIKEDS.
so your original program looks somthing like
/copy StdDefs
C *Entry PList
C Parm InEntry1
Your refactored one with PR/PI looks like
/copy StdDefs2
/copy Mypr
dcl-pi myprogram;
InEntry1 like(inEntry_t);
end-pi;
Note that best practice is to have the PR in a separate member that's /COPY'd into both caller and callee.
Could not find a solution without declaring another variable with like. And assign the new variable to the old at the begenning of the program, and vice versa at the end.
I often find myself in a situation where i need to check if i assigned something to a variable and then if so, compare it's value to something else.
Sure, I know how to do it, but I wonder if there is a more elegant way of handling this.
EXAMPLE:
def function():
with suppress(SomeException):
variable = 10
if variable and variable > 5:
# do things
That will give me an UnboundLocalError exception (in case of SomeException happening during variable assignment). Again, I know how to code it, so it will work, it's the style of coding that troubles me. I want to avoid creating unnecessary local variable.
You say you know how to do it, but the code you posted will throw an exception if the assignment doesn't happen.
There really is a simple way to do this: just don't write code that can leave a variable uninitialised.
def function():
variable = None
if SomeCondition():
variable = 10
if variable is not None:
# do things
Note that this doesn't create any unneeded local variables, the variable variable would be created whether or not you assign to it, but if you don't assign then it is uninitialised and testing whether it is initialised means having to throw and catch an exception, and that is slow. Simply initialising it means you have a simple easy test. Stop trying to optimise things that don't need optimising.
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.