[PATCH v10 3/9] env: Allow U-Boot scripts to be placed in a .env file

Patrick DELAUNAY patrick.delaunay at foss.st.com
Thu Feb 10 12:20:35 CET 2022


Hi Simon,

On 10/22/21 05:08, Simon Glass wrote:
> At present U-Boot environment variables, and thus scripts, are defined
> by CONFIG_EXTRA_ENV_SETTINGS. It is painful to add large amounts of text
> to this file and dealing with quoting and newlines is harder than it
> should be. It would be better if we could just type the script into a
> text file and have it included by U-Boot.
>
> Add a feature that brings in a .env file associated with the board
> config, if present. To use it, create a file in a board/<vendor>
> directory, typically called <board>.env and controlled by the
> CONFIG_ENV_SOURCE_FILE option.
>
> The environment variables should be of the form "var=value". Values can
> extend to multiple lines. See the README under 'Environment Variables:'
> for more information and an example.
>
> In many cases environment variables need access to the U-Boot CONFIG
> variables to select different options. Enable this so that the environment
> scripts can be as useful as the ones currently in the board config files.
> This uses the C preprocessor, means that comments can be included in the
> environment using /* ... */
>
> Also support += to allow variables to be appended to. This is needed when
> using the preprocessor.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> Reviewed-by: Marek Behún <marek.behun at nic.cz>
> Tested-by: Marek Behún <marek.behun at nic.cz>
> ---
...
>
>
>   MAINTAINERS               |   7 +++
>   Makefile                  |  66 ++++++++++++++++++++++-
>   config.mk                 |   2 +
>   doc/usage/environment.rst |  81 ++++++++++++++++++++++++++++-
>   doc/usage/index.rst       |   1 +
>   env/Kconfig               |  18 +++++++
>   env/embedded.c            |   1 +
>   include/env_default.h     |  11 ++++
>   scripts/env2string.awk    |  80 ++++++++++++++++++++++++++++
>   test/py/tests/test_env.py | 107 ++++++++++++++++++++++++++++++++++++++
>   10 files changed, 372 insertions(+), 2 deletions(-)
>   create mode 100644 scripts/env2string.awk
>

...


For information, it seems the new test "test_env_text" failed when the 
gawk is not installed on Ubuntu distribution,

or when /usr/bin/mawk is used as alternative (sudo update-alternatives 
--config awk)

The test result is

test/py/tests/test_env.py:556: in test_env_text
     check_script('''fred=123
test/py/tests/test_env.py:542: in check_script
     assert result == expect
E   assert '#define CONF...red=123\\0"\n' == '#define CONF...nie=456\\0"\n'
E     - #define CONFIG_EXTRA_ENV_TEXT "ernie=456\0fred=123\0"
E     ?                                           ----------
E     + #define CONFIG_EXTRA_ENV_TEXT "fred=123\0ernie=456\0"
E     ?                                ++++++++++
------------------------------------------------------------ Captured 
stdout call -------------------------------------------------------------
+awk -f <PATH>/u-boot/scripts/env2string.awk /tmp/tmp0zgiwrd9/infile
#define CONFIG_EXTRA_ENV_TEXT "fred=123\0"
+awk -f <PATH>/u-boot/scripts/env2string.awk /tmp/tmpq6xej0ct/infile
+awk -f <PATH>/u-boot/scripts/env2string.awk /tmp/tmpyrn10apn/infile
#define CONFIG_EXTRA_ENV_TEXT "ernie=456\0fred=123\0"


=> the env variables are sorted in alphabetic order in mawk output / in 
creation order in gawk ouput

I don't found solution to be POSIX compliant and to guarantee the output 
order


 >> By default, when a for loop traverses an array, the order is undefined,

 >> meaning that the awk implementation determines the order in which

 >> the array is traversed. This order is usually based on the internal

 >> implementation of arrays and will vary from one version of awk to 
the next.


References:

https://www.gnu.org/software/gawk/manual/html_node/Controlling-Scanning.html

https://www.gnu.org/software/gawk/manual/html_node/Controlling-Array-Traversal.html


> diff --git a/scripts/env2string.awk b/scripts/env2string.awk
> new file mode 100644
> index 00000000000..57d0fc8f3ba
> --- /dev/null
> +++ b/scripts/env2string.awk
> @@ -0,0 +1,80 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright 2021 Google, Inc
> +#
> +# SPDX-License-Identifier:	GPL-2.0+
> +#
> +# Awk script to parse a text file containing an environment and convert it
> +# to a C string which can be compiled into U-Boot.
> +
> +# The resulting output is:
> +#
> +#   #define CONFIG_EXTRA_ENV_TEXT "<environment here>"
> +#
> +# If the input is empty, this script outputs a comment instead.
> +
> +BEGIN {
> +	# env holds the env variable we are currently processing
> +	env = "";
> +	ORS = ""
> +}
> +


...


> +
> +END {
> +	# Record the value of the variable now completed. If the variable is
> +	# empty it is not set.
> +	if (length(env) != 0) {
> +		vars[var] = env
> +	}
> +
> +	if (length(vars) != 0) {
> +		printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
> +
> +		# Print out all the variables


ORDER is not guarantee here by awk for the loop on the "vars" array


> +		for (var in vars) {
> +			env = vars[var]
> +			print var "=" vars[var] "\\0"
> +		}
> +		print "\"\n"
> +	}
> +}
> diff --git a/test/py/tests/test_env.py b/test/py/tests/test_env.py
> index 9bed2f48d77..f85cb031382 100644
> --- a/test/py/tests/test_env.py
> +++ b/test/py/tests/test_env.py
> @@ -7,6 +7,7 @@
>   import os
>   import os.path
>   from subprocess import call, check_call, CalledProcessError
> +import tempfile
>   
>   import pytest
>   import u_boot_utils
> @@ -515,3 +516,109 @@ def test_env_ext4(state_test_env):
>       finally:
>           if fs_img:
>               call('rm -f %s' % fs_img, shell=True)
> +
> +def test_env_text(u_boot_console):
> +    """Test the script that converts the environment to a text file"""
> +
> +    def check_script(intext, expect_val):
> +        """Check a test case
> +
> +        Args:
> +            intext: Text to pass to the script
> +            expect_val: Expected value of the CONFIG_EXTRA_ENV_TEXT string, or
> +                None if we expect it not to be defined
> +        """
> +        with tempfile.TemporaryDirectory() as path:
> +            fname = os.path.join(path, 'infile')
> +            with open(fname, 'w') as inf:
> +                print(intext, file=inf)
> +            result = u_boot_utils.run_and_log(cons, ['awk', '-f', script, fname])
> +            if expect_val is not None:
> +                expect = '#define CONFIG_EXTRA_ENV_TEXT "%s"\n' % expect_val
> +                assert result == expect
> +            else:
> +                assert result == ''
> +
> +    cons = u_boot_console
> +    script = os.path.join(cons.config.source_dir, 'scripts', 'env2string.awk')
> +
> +    # simple script with a single var
> +    check_script('fred=123', 'fred=123\\0')
> +
> +    # no vars
> +    check_script('', None)
> +
> +    # two vars
> +    check_script('''fred=123
> +ernie=456''', 'fred=123\\0ernie=456\\0')

Here according the awk implementation  the test result can be

'fred=123\\0ernie=456\\0' => creation order

'ernie=456\\0fred=123\\0' => alphabetic order

and perhaps other order for other awk ?


do you think you can have a solution with POSIX awk ?
today I found only solution for gawk:


---------------------------- scripts/env2string.awk ----------------------------
index 1bfe9ed07a..f3215c369a 100644
@@ -81,7 +81,8 @@ END {
  	if (do_output) {
  		printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
  
-		# Print out all the variables
+		# Print out all the variables by alphabetic order
+		PROCINFO["sorted_in"] = "@ind_str_asc"
  		for (var in vars) {
  			env = vars[var]
  			print var "=" vars[var] "\\0"


But this GNU feature must be avoid,
see commit 7acb32256831 ("env: Avoid using GNU features in awk")

Regard

Patrick Delaunay





More information about the U-Boot mailing list