echo of var to file in SConscript - scons

In an SConscript file I have a env variable BUILDID_STR
that contains a C string that I wish to output to a file.
bstr = env['BUILDID_STR']
print(bstr)
which when printed, print(bstr) correctly shows this:
//this file is automatically generated
static char* build_str="0|0.1.0|2014-05-29_16:16:51";
However, I can't get the var expanded/exported correctly, just the literal string is output instead of the above text:
cat src/log/src/version.c
env[BUILDID_STR]
Here's the pertinent part of my SConscript file
env.Command(target='#/src/log/src/version.c',
source=libSrcfiles,
action="echo env['BUILDID_STR'] > $TARGET")
env.SharedLibrary('log', [libSrcfiles, '#/src/log/src/version.c'])
I've also tried the code in a function and also passing to a shell script, all with the same result.
The reason I have .../version.c in the SharedLibrary is that my goal is to have the .c file generated only when on of the libSrcfiles is built, thereby version.c is compiled-in.

The "textfile" Tool offers two Builders Textfile() and Substfile() for cases like this. You probably want to use the first:
env = Environment(tools=['textfile'])
env['BUILDID_STR'] = 'A test'
env.Textfile('test.txt', ['$BUILDID_STR'])

As you have seen, the action is not expanding the env variable. In the action, you can refer to env variables with the $VAR syntax (just like referring to the $SOURCE and $TARGET variables provided by SCons):
env.Command(target='#/src/log/src/version.c',
source=libSrcfiles,
action="echo $BUILDID_STR > $TARGET")
This solution may not handle a BUILDID_STR containing multiple lines.
You may want to investigate a system that builds your source file from a template (instead of constructing the file contents entirely within a string). The Substfile Builder referenced in this previous question might be a good starting point -- you can provide a list of (key, value) pairs to be substituted in an input file. The Substfile Builder is built into recent versions of SCons.

Related

One .po file for each .py script

In my package, I would like to use one .po file for each .py script it contains.
Here is my file tree :
foo
mainscript.py
commands/
commandOne.py
locales/fr/LC_MESSAGES/
mainscript_fr.po
commandOne_fr.po
In the mainscript.py, I got the following line to apply gettext to the strings :
if "fr" in os.environ['LANG']:
traduction = gettext.translation('mainscript_fr', localedir='./locales', languages=['fr'])
traduction.install()
else:
gettext.install('')
Until now, it is working as expected. But now I would like to add another .po file to translates the strings in commandOne.py.
I tried the following code :
if "fr" in os.environ['LANG']:
traduction = gettext.translation('commandOne_fr', localedir='../locales', languages=['fr'])
traduction.install()
else:
gettext.install('')
But I get a "FileNotFoundError: [Errno 2] No translation file found for domain: 'commandOne_fr' "
How can I use multiple file like that ? The package being a cli, there is many strings in a single file because of the help man and verbose mode...etc and this is not acceptable to have a single .po file with hundreds of strings.
Note : The mainscript.py calls a function from commandOne.py, which is itself inherited from an abstract class that contains other strings to translate... so I hope if any solution exists that it will also be applicable to the abstract class file.
Thank you
Translations are retrieved from .mo files, not .po files, see https://docs.python.org/3/library/gettext.html#gettext.translation. Most probably you have to compile CommandOne_fr.po with the program msgfmt into CommandOne_fr.mo.
Two more hints:
What you are doing looks like a premature optimization. You won't have any performance problem until the number of translations gets really big. Rather wait for that to happen.
Why the _fr in the name of the translation files? The language code fr is already a path component.

Check if same file exists in another directory using Bash

I'm new to bash and would like your help; couldn't find an answer for this case.
I'm trying to check if the files in one directory exist in another directory
Let's say I have the path /home/public/folder/ (here I have several files)
and I want to check if the files exist in /home/private/folder2
I tried that
for file in $firstPath/*
do
if [ -f $file ]; then
(ask if to over write etc.. rest of the code)
And also
for file in $firstPath/*
do
if [ -f $file/$secondPath ]; then
(ask if to over write etc.. rest of the code)
Both don't work; it seems that in the first case, it compares the files in the first path (so it always ask me if I want to overwrite although it doesn't exist in the second path)
And in the second case, it doesn't go inside the if statement.
How could I fix that?
When you have a construct like for file in $firstPath/*, the value of $file is going to include the value of $firstPath, which does not exist within $secondPath. You need to strip the path in order to get the bare filename.
In traditional POSIX shell, the canonical way to do this was with an external tool called basename. You can, however, achieve what is generally thought to be equivalent functionality using Parameter Expansion, thus:
for file in "$firstPath"/*; do
if [[ -f "$secondPath/${file##*/}" ]]; then
# file exists, do something
fi
done
The ${file##*/} bit is the important part here. Per the documentation linked above, this means "the $file variable, with everything up to the last / stripped out." The result should be the same as what basename produces.
As a general rule, you should quote your variables in bash. In addition, consider using [[ instead of [ unless you're actually writing POSIX shell scripts which need to be portable. You'll have a more extensive set of tests available to you, and more predictable handling of variables. There are other differences too.

How to run a string from an input file as python code?

I am creating something along the likes of a text adventure game. I have a .yaml file that is my input. This file looks something like this
node_type:
action
title:
Do some stuff
info:
This does some stuff and things
script:
'print("hello world")
print(ret_val)
foo.bar(True)
ret_val = (foo.bar() == True)
if (thing):
print(thing)
print(ret_val)
'
My end goal is to have my python program run the script portion of the yaml file exactly as if it had been copy pasted into the main code. (I know there are about ten bazillion security reasons I should not be running user input like this, but I am the only one writing these nodes, and the only one using this program so I'm mostly just ignoring this fact...)
Currently my attempt goes like this: I load my yaml file as a dict using pyyaml
node = yaml.safe_load(file.yaml)
Then I'm trying to use exec to run my code and hitting a lot of problems, I can't run if statements, I simply get a syntax error, and I can't get any sort of return value from my code. I've tried this as a work around:
def main()
ret_val = "test";
thing = exec(node['script'], globals(),locals())
print(ret_val)
which when run with the above .yaml file prints
>> hello world
>> test
>> True
>> test
for some reason not actually modifying any of my main variables even though I fed them to exec.
Is there any way for me to work around these issues or is there an all together better way to be doing this?
One way of doing this would be to parse the code out and save it to a .py file, from which it can be imported dynamically, for example by importlib.
You might want to encapsulate parsed code into a function, which you can then easily call to invoke your action. Also, it would make sense to specify some default imports there.

String Expansion with Variables

I have a config file, that contains strings used within my scripts. The config file is read via a C# class using this Syntax:
$final = $PropMgr.GetValue($section, $property)
$final = $ExecutionContext.InvokeCommand.ExpandString($final)
This returns the string from the config file. Afterwards the returned string gets expanded because it may contain objects that need expansion
Everything works fine but for one thing. One of my strings in the config file looks like this:
Found $($scripts.Length) scripts to execute in the config file
$scripts is array, so the expanded string should look like this:
Found 6 scripts to execute in the config file
But using my code avove I receive an exception:
Exception calling "ExpandString" with "1" argument(s): "Object reference not set to an instance of an object."
If I debug the script and execute this code in a commandline:
$ExecutionContext.InvokeCommand.ExpandString("Found $($scripts.Length) scripts to execute in the config file")
Everything is fine, but using the $final variable instead of the string itself, I receive the exception again.
What do I have to do to achieve what I was looking for?

Organize code in unix bash scripting

I am used to object oriented programming. Now, I have just started learning unix bash scripting via linux.
I have a unix script with me. I wanted to break it down into "modules" or preferably programs similar to "more", "ls", etc., and then use pipes to link all my programs together. E.g., "some input" myProg1 | myProg2 | myProg3.
I want to organize my code and make it look neater, instead of all in one script. Also, it will be easy to do testing and development.
Is it possible to do this, especially as a newbie ?
There are a few things you could take a look at, for example the usage of aliases in bash and storing them in either bashrc or a seperate file called by bashrc
that will make running commands easier..
take a look here for expanding commands into aliases (simple aliases are easy)
You can also look into using functions in your code (lots of bash scripts in above link's home folder to make sense of functions browse this site :) which has much better examples...
Take a look here for some piping tails into script
pipe tail output into another script
The thing with bash is its flexibility, so for example if something starts to get too messy for bash you could always write a perl/Java any lang and then call this from within your bash script, capture its output and do something else..
Unsure why all the pipes anyways here is something that may be of help:
./example.sh 20
function one starts with 20
In function 2 20 + 10 = 30
Function three returns 10 + 10 = 40
------------------------------------------------
------------------------------------------------
Local function variables global:
Result2: 30 - Result3: 40 - value2: 10 - value1: 20
The script:
example.sh
#!/bin/bash
input=$1;
source ./shared.sh
one
echo "------------------------------------------------"
echo "------------------------------------------------"
echo "Local function variables global:"
echo "Result2: $result2 - Result3: $result3 - value2: $value2 - value1: $value1"
shared.sh
function one() {
value1=$input
echo "function one starts with $value1"
two;
}
function two() {
value2=10;
result2=$(expr $value1 + $value2)
echo "In function 2 $value1 + $value2 = $result2"
three;
}
function three() {
local value3=10;
result3=$(expr $value2 + $result2;)
echo "Function three returns $value2 + $value3 = $result3"
}
I think the pipes you mean can actually be functions and each function can call one another.. and then you give the script the value which it passes through the functions..
bash is pretty flexible about passing values around, so long as the function being called before has the variable the next function being called by it can reuse it or it can be called from main program
I also split out the functions which can be sourced by another script to carry out the same functions
E2A Thanks for the upvote, I have also decided to include this link
http://tldp.org/LDP/abs/html/sample-bashrc.html
There is an awesome .bashrc to be reused, it has a lot of functions which will also give some insight into how to simplify a lot of daily repetitive commands such as that require piping, an alias can be written to do all of them for you..
You can do one thing.
Just as a C program can be divided into a header file and a source file for reducing complexity, you can divide your bash script into two scripts - a header and a main script but with some differences.
Header file - This will contain all the common variables defined and functions defined which will be used by your main script.
Your script - This will only contain function calls and other logic.You need to use "source <"header-file path">" in your script at starting to get all the functions and variables declared in the header available to your script.
Shell scripts have standard input and output like any other program on Unix, so you can use them in pipes. Splitting your scripts is a good solution because you can later use them in pipes with other commands.
I organize my Bash projects in the following way :
Each command is put in its own file
Reusable functions are kept in a library file which is just a classic script with only functions
All files are in the same directory, so commands can find the library with $(dirname $0)/library
Configuration is stored in another file as environment variables
To keep things clear, you should not use global variables to communicate between functions and main program.
I prepare a template for scripts with the following parts prepared :
Header with name and copyright
Read configuration with source
Load library with source
Check parameters
Function to display help, which is called if asked for or if parameters are wrong
My best advice is : always write the help function, as the next person who will need it is ... yourself !
To install your project you simply copy all files, and explain what to configure in the configuration file.

Resources