From ed93f8450b92579dd639ae25361fa650613a5b7e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 21 Jul 2018 11:09:14 +0200 Subject: Redo manifest parsing using bash co-process facility --- .gitignore | 3 ++ build/export.build | 2 +- libbutl/buildfile | 5 ++- libbutl/manifest-parser.bash | 13 ------- libbutl/manifest-parser.bash.in | 83 ++++++++++++++++++++++++++++++++++++++++ libbutl/utility.bash.in | 14 +++++++ manifest | 5 ++- tests/.gitignore | 1 + tests/manifest-parser/driver.in | 8 +++- tests/manifest-parser/testscript | 2 + 10 files changed, 118 insertions(+), 18 deletions(-) delete mode 100644 libbutl/manifest-parser.bash create mode 100644 libbutl/manifest-parser.bash.in create mode 100644 libbutl/utility.bash.in diff --git a/.gitignore b/.gitignore index 13d880b..fbfa5a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ .bdep/ + +*.d +*.bash diff --git a/build/export.build b/build/export.build index 4f9f5c7..9981479 100644 --- a/build/export.build +++ b/build/export.build @@ -7,4 +7,4 @@ $out_root/ include libbutl/ } -export $src_root/libbutl/$import.target +export $out_root/libbutl/$import.target diff --git a/libbutl/buildfile b/libbutl/buildfile index 6509396..cd2643e 100644 --- a/libbutl/buildfile +++ b/libbutl/buildfile @@ -2,4 +2,7 @@ # copyright : Copyright (c) 2014-2018 Code Synthesis Ltd # license : MIT; see accompanying LICENSE file -./: bash{manifest-parser} +./: bash{$path.base($path.base(*.bash.in))} + +bash{utility}: in{utility} +bash{manifest-parser}: in{manifest-parser} bash{utility} diff --git a/libbutl/manifest-parser.bash b/libbutl/manifest-parser.bash deleted file mode 100644 index e726298..0000000 --- a/libbutl/manifest-parser.bash +++ /dev/null @@ -1,13 +0,0 @@ -# file : libbutl/manifest-parser.bash -# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd -# license : MIT; see accompanying LICENSE file - -function butl_parse_manifest () -{ - printf ":1\0" - printf "name:foo\0" - printf "version:1.2.3\0" - printf "description:foo\nexecutable\0" - printf "depends:libfoo\0" - printf "depends:libbar\0" -} diff --git a/libbutl/manifest-parser.bash.in b/libbutl/manifest-parser.bash.in new file mode 100644 index 0000000..e40791e --- /dev/null +++ b/libbutl/manifest-parser.bash.in @@ -0,0 +1,83 @@ +# file : libbutl/manifest-parser.bash.in +# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +# license : MIT; see accompanying LICENSE file + +if [ "$butl_manifest_parser" = true ]; then + return 0 +else + butl_manifest_parser=true +fi + +@import libbutl/utility@ + +# Parse the manifest from stdin writing the binary representation to stdout. +# +# Normally you would use the start/finish functions below. But if you don't +# care about errors, the following would be the typical usage: +# +# while IFS=: read -r -d '' n v; do +# ... +# done < <(butl_parse_manifest) +# +function butl_parse_manifest () +{ + printf ":1\0" + printf "name:foo\0" + printf "version:1.2.3\0" + printf "description:foo\nexecutable\0" + printf "depends:libfoo\0" + printf "depends:libbar\0" +} + +# Start the manifest parsing co-process setting the following "return" +# variables: +# +# butl_manifest_parser_ofd +# butl_manifest_parser_ifd +# butl_manifest_parser_pid +# +# If is not specified, then read from stdin. +# +# The typical usage: +# +# butl_manifest_parser_start +# +# while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do +# ... +# done +# +# butl_manifest_parser_finish +# +function butl_manifest_parser_start () # [] +{ + if [ "$#" -gt 0 ]; then + exec {butl_manifest_parser_ifd}<"$1" + else + exec {butl_manifest_parser_ifd}<&0 + fi + + # Note that bash co-process facility is racy: as soon as the process + # finishes, bash unsets COPROC/COPROC_PID (my guess would be it checks after + # each command in the script). This specific sequence of steps (and the one + # in *_finish()) seems to work reliably at least from bash 4.3.30 and + # up. See the following resources for details: + # + # http://wiki.bash-hackers.org/syntax/keywords/coproc + # http://tldp.org/LDP/abs/html/bashver4.html (coproc section) + # https://lists.gnu.org/archive/html/bug-bash/2014-02/msg00017.html + # https://lists.gnu.org/archive/html/bug-bash/2012-12/msg00069.html + # https://lists.gnu.org/archive/html/bug-bash/2012-10/msg00027.html + # + coproc { butl_parse_manifest; } <&"$butl_manifest_parser_ifd" + exec {butl_manifest_parser_ofd}<&"${COPROC[0]}" + butl_manifest_parser_pid="$COPROC_PID" +} + +# Finish the manifest parsing co-process. +# +function butl_manifest_parser_finish () +{ + exec {butl_manifest_parser_ofd}<&- + wait "$butl_manifest_parser_pid" + exec {butl_manifest_parser_ifd}<&- +} diff --git a/libbutl/utility.bash.in b/libbutl/utility.bash.in new file mode 100644 index 0000000..bcc0f1b --- /dev/null +++ b/libbutl/utility.bash.in @@ -0,0 +1,14 @@ +# file : libbutl/utility.bash.in +# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +# license : MIT; see accompanying LICENSE file + +if [ "$butl_utility" = true ]; then + return 0 +else + butl_utility=true +fi + +if (( BASH_VERSINFO[0] < 4 || BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 3 )); then + echo 'error: bash 4.3 or later is required' 2>&1 + exit 1 +fi diff --git a/manifest b/manifest index d9743b6..a2f24f3 100644 --- a/manifest +++ b/manifest @@ -12,6 +12,9 @@ doc-url: https://build2.org/doc.xhtml src-url: https://git.build2.org/cgit/libbutl.bash/tree/ email: users@build2.org build-email: builds@build2.org -requires: bash >= 4 +build-exclude: windows*; Requires bash +build-exclude: macos*; Requires bash >= 4.3 +build-include: * +requires: bash >= 4.3 depends: * build2 >= 0.8.0- depends: * bpkg >= 0.8.0- diff --git a/tests/.gitignore b/tests/.gitignore index 35ec43f..2e508a9 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,2 +1,3 @@ +driver test/ test-*/ diff --git a/tests/manifest-parser/driver.in b/tests/manifest-parser/driver.in index 90dc0e3..ffd9a64 100644 --- a/tests/manifest-parser/driver.in +++ b/tests/manifest-parser/driver.in @@ -9,7 +9,9 @@ set -o errtrace # Trap ERR in functions. @import libbutl/manifest-parser@ -while IFS=: read -r -d '' n v; do +butl_manifest_parser_start "$@" + +while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do if [ -z "$n" ]; then echo "$v" else @@ -17,4 +19,6 @@ while IFS=: read -r -d '' n v; do echo "$n" echo "$v" fi -done < <(butl_parse_manifest) +done + +butl_manifest_parser_finish diff --git a/tests/manifest-parser/testscript b/tests/manifest-parser/testscript index 6a95286..154b107 100644 --- a/tests/manifest-parser/testscript +++ b/tests/manifest-parser/testscript @@ -21,3 +21,5 @@ libfoo depends libbar EOO + +#@@ TODO: test reading from file instead of stdin. -- cgit v1.1