aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-07-21 11:09:14 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-07-21 11:14:52 +0200
commited93f8450b92579dd639ae25361fa650613a5b7e (patch)
treec43b07d3d7723034fcbdbdf8e5ae805b6c361309
parent357172f4409c74d7a2ac963290fc70c7ae10e3b1 (diff)
Redo manifest parsing using bash co-process facility
-rw-r--r--.gitignore3
-rw-r--r--build/export.build2
-rw-r--r--libbutl/buildfile5
-rw-r--r--libbutl/manifest-parser.bash13
-rw-r--r--libbutl/manifest-parser.bash.in83
-rw-r--r--libbutl/utility.bash.in14
-rw-r--r--manifest5
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/manifest-parser/driver.in8
-rw-r--r--tests/manifest-parser/testscript2
10 files changed, 118 insertions, 18 deletions
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 <file> 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 () # [<file>]
+{
+ 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.