From ee77b4f7bea938c4ebad1174204fc32ace18a573 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Fri, 24 Jun 2022 14:13:51 +0200 Subject: [PATCH] Allow more than one conditional action (#1070) * Allow conditional tables within multivalue arrays * New test for loading of conditional actions Co-authored-by: GHA --- .../alire-conditional_trees-toml_load.adb | 16 +++++- src/alire/alire-properties-from_toml.adb | 55 +++++++++++++++---- src/alire/alire-toml_adapters.adb | 15 ++++- src/alire/alire-toml_load.adb | 2 - testsuite/tests/action/conditional/test.py | 53 ++++++++++++++++++ testsuite/tests/action/conditional/test.yaml | 1 + testsuite/tests/index/environment/test.py | 10 +++- 7 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 testsuite/tests/action/conditional/test.py create mode 100644 testsuite/tests/action/conditional/test.yaml diff --git a/src/alire/alire-conditional_trees-toml_load.adb b/src/alire/alire-conditional_trees-toml_load.adb index 9726c4b1..79a4a1be 100644 --- a/src/alire/alire-conditional_trees-toml_load.adb +++ b/src/alire/alire-conditional_trees-toml_load.adb @@ -119,6 +119,16 @@ package body Alire.Conditional_Trees.TOML_Load is is Table : constant TOML_Adapters.Key_Queue := From.Descend (Val, "values"); + + Case_Result : Tree; + -- We store properties coming from cases separately so for the action + -- syntax of: + -- [[actions]] + -- key = val + -- [actions.case] + -- key = val + -- respects the ordering of first the common case and then subcases. + begin return Result : Tree do @@ -133,7 +143,7 @@ package body Alire.Conditional_Trees.TOML_Load is begin exit when Case_Key = ""; -- Table contains no more cases - Result.Append + Case_Result.Append (Process_Case (From, Key, Case_Key, Case_Val)); end; end loop; @@ -148,6 +158,10 @@ package body Alire.Conditional_Trees.TOML_Load is Value => Val, Context => Key))); end if; + + if not Case_Result.Is_Empty then + Result.Append (Case_Result); + end if; end return; end Process_Nested_Table; diff --git a/src/alire/alire-properties-from_toml.adb b/src/alire/alire-properties-from_toml.adb index 98c8d9dc..ea42e172 100644 --- a/src/alire/alire-properties-from_toml.adb +++ b/src/alire/alire-properties-from_toml.adb @@ -43,18 +43,49 @@ package body Alire.Properties.From_TOML is exit Process_Property; end if; - -- Load property once we know its exact name, allowing - -- expressions were appropriate. - - Props.Append - (Prop_Loader.Load - (From => From.Descend - (Key => Key, - Value => Val, - Context => Key), - Loader => Loaders (Prop), - Resolve => Is_Dynamic (Prop), - Strict => Strict)); + -- If the property is an array of tables (e.g. actions), + -- reconstruct items as a single table to redispatch. + -- This ensures that properties that can have dynamic + -- expressions within each array entry are transparently + -- managed before they reach the actual property loader. + + if Val.Kind = TOML_Array + and then + (for all I in 1 .. Val.Length => + Val.Item (I).Kind = TOML_Table) + then + + -- Load each array entry individually + + for I in 1 .. Val.Length loop + Props.Append + (Prop_Loader.Load + (From => From.Descend + (Key => Key, + Value => Val.Item (I), + Context => Key & " (array item" + & I'Image & ")"), + Loader => Loaders (Prop), + Resolve => Is_Dynamic (Prop), + Strict => Strict)); + end loop; + + else + + -- Load a single property once we know its exact name, + -- allowing expressions were appropriate. + + Props.Append + (Prop_Loader.Load + (From => From.Descend + (Key => Key, + Value => Val, + Context => Key), + Loader => Loaders (Prop), + Resolve => Is_Dynamic (Prop), + Strict => Strict)); + + end if; else From.Recoverable_Error ("invalid property: " & Key); diff --git a/src/alire/alire-toml_adapters.adb b/src/alire/alire-toml_adapters.adb index 07666162..d0660cdf 100644 --- a/src/alire/alire-toml_adapters.adb +++ b/src/alire/alire-toml_adapters.adb @@ -338,7 +338,7 @@ package body Alire.TOML_Adapters is function Image (Val : TOML_Value) return String is (case Val.Kind is - when TOML_String => Val.As_String, + when TOML_String => Val.As_String, when TOML_Boolean => Val.As_Boolean'Img, when TOML_Integer => Val.As_Integer'Img, when others => raise Unimplemented); @@ -363,12 +363,23 @@ package body Alire.TOML_Adapters is & (if Val.Length > 0 then " of " & Val.Item (1).Kind'Img else "")); + for I in 1 .. Val.Length loop + Trace.Always (Prefix & "array entry" & I'Img & ":"); + Print (Val.Item (I), Prefix & " "); + end loop; when others => - Trace.Always (Prefix & "value: " & Val.Kind'Img); + Trace.Always (Prefix & "value: " & Val.Kind'Img + & "; img: " + & (case Val.Kind is + when TOML_String => Val.As_String, + when TOML_Integer => Val.As_Integer'Image, + when TOML_Boolean => Val.As_Boolean'Image, + when others => "(unimplemented)")); end case; end Print; begin + Trace.Always ("Printing context: " & Errors.Stack ("")); Print (Queue.Value, ""); end Print; diff --git a/src/alire/alire-toml_load.adb b/src/alire/alire-toml_load.adb index 5ab61cc5..042c0740 100644 --- a/src/alire/alire-toml_load.adb +++ b/src/alire/alire-toml_load.adb @@ -180,8 +180,6 @@ package body Alire.TOML_Load is Context => TOML_Keys.Pins)); end if; - -- TODO: Process Forbidden - -- Process Available if Allowed_Tables (Section, Available) then diff --git a/testsuite/tests/action/conditional/test.py b/testsuite/tests/action/conditional/test.py new file mode 100644 index 00000000..b8e74670 --- /dev/null +++ b/testsuite/tests/action/conditional/test.py @@ -0,0 +1,53 @@ +""" +Test conditional actions, mixed with unconditional ones +""" + +import re + +from drivers.alr import run_alr, init_local_crate, alr_manifest +from drivers.asserts import assert_eq, assert_match + +init_local_crate() + +# Edit the manifest to include all kinds of actions +with open(alr_manifest(), "at") as manifest: + manifest.write(""" +[[actions]] +type = "pre-build" +command = ["echo", "1"] + +[[actions.'case(os)'.'...']] +type = "pre-build" +command = ["echo", "2"] + +[[actions]] +[actions.'case(os)'.'...'] +type = "pre-build" +command = ["echo", "3"] + +[[actions]] +type = "pre-build" +command = ["echo", "4"] + [actions.'case(os)'.'...'] + type = "pre-build" + command = ["echo", "5"] +""") + +# Verify actions are there +assert_match(".*" + + re.escape(""" Pre_Build run: ${CRATE_DIR}/./echo 1 + case OS is + when others => Pre_Build run: ${CRATE_DIR}/./echo 2 + case OS is + when others => Pre_Build run: ${CRATE_DIR}/./echo 3 + Pre_Build run: ${CRATE_DIR}/./echo 4 + case OS is + when others => Pre_Build run: ${CRATE_DIR}/./echo 5 +""") + ".*", + run_alr("show").out) + +# Verify actions run in the proper order +assert_eq("1\n2\n3\n4\n5\n", + run_alr("action", "pre-build").out) + +print('SUCCESS') diff --git a/testsuite/tests/action/conditional/test.yaml b/testsuite/tests/action/conditional/test.yaml new file mode 100644 index 00000000..32c747b3 --- /dev/null +++ b/testsuite/tests/action/conditional/test.yaml @@ -0,0 +1 @@ +driver: python-script diff --git a/testsuite/tests/index/environment/test.py b/testsuite/tests/index/environment/test.py index d8226e7a..e42aa005 100644 --- a/testsuite/tests/index/environment/test.py +++ b/testsuite/tests/index/environment/test.py @@ -12,9 +12,8 @@ import os # With conditionals p = run_alr('show', 'hello') +# Test that unconditional properties are in the output assert_match('.*' - ' when others => Environment: CONDVAR=uvw\n' - '.*' ' Environment: VAR1=\${VAR1}:abc\n' ' Environment: VAR2=xyz:\${VAR2}\n' ' Environment: VAR3=pqr\n' @@ -27,6 +26,13 @@ assert_match('.*' '.*', p.out, flags=re.S) +# Test that conditional properties are in the output +assert_match('.*' + ' case OS is\n' + ' when others => Environment: CONDVAR=uvw\n' + '.*', + p.out, flags=re.S) + # Check resolved conditional p = run_alr('show', 'hello', '--system') -- 2.39.5