From e44edfb832e2491cd17edaa3dc8dc7b9e9265356 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 17 Oct 2016 17:19:59 +0200 Subject: Add bash style guide --- doc/.gitignore | 1 + doc/bash-style.cli | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/cli.sh | 24 ++++ 3 files changed, 339 insertions(+) create mode 100644 doc/.gitignore create mode 100644 doc/bash-style.cli create mode 100755 doc/cli.sh (limited to 'doc') diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..a5873dc --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +build2-bash-style.xhtml diff --git a/doc/bash-style.cli b/doc/bash-style.cli new file mode 100644 index 0000000..67f9da2 --- /dev/null +++ b/doc/bash-style.cli @@ -0,0 +1,314 @@ +// file : doc/bash-style.cli +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +"\title=Bash Style Guide" + +// NOTES +// +// - Maximum
 line is 70 characters.
+//
+
+"\h1|Contents|"
+"\$TOC$"
+
+"
+\h1#intro|Introduction|
+
+Bash works best for simple tasks. Needing arrays, arithmetic, and so on, is
+usually a good indication that the task at hand is too complex for Bash.
+
+Most of the below rules can be broken if there is a good reason for it.
+Besides making things consistent, rules free you from having to stop and think
+every time you encounter a particular situation. But if it feels that the
+prescribed way is clearly wrong, then it probably makes sense to break it.
+You just need to be clear on why you are doing it.
+
+See also \l{https://google.github.io/styleguide/shell.xml Google's Bash Style
+Guide}; we agree with quite a few (but not all) items in there. In particular,
+it provides a lot more rationale compared to this guide.
+
+\h1#style|Style|
+
+Don't use any extensions for your scripts. That is, call it just \c{foo}
+rather than \c{foo.sh} or \c{foo.bash}. Use lower-case letters and dash
+to separate words, for example \c{foo-bar}.
+
+Indentation is two spaces (not tabs). Maximum line length is 79 characters
+(excluding newline). Use blank lines between logical blocks to improve
+readability.
+
+Variable and function names should use lower-case letters with underscores
+separating words.
+
+For \c{if}/\c{while} and \c{for}/\c{do} the corresponding \c{then} or \c{do}
+is written on the same line after a semicolon, for example:
+
+\
+if [ ... ]; then
+fi
+
+for x in ...; do
+done
+\
+
+For \c{if} use \c{[ ]} for basic tests and \c{[[ ]]} only if the previous form
+is not sufficient. Never use \c{test}. Do use \c{elif}.
+
+\h1#struct|Structure|
+
+The overall structure of the script should be as follows:
+
+\
+#! /usr/bin/env bash
+
+# 
+#
+# []
+#
+# []
+#
+usage=\"usage: $0 \"
+
+owd=\"$(pwd)\"
+trap \"{ cd '$owd'; exit 1; }\" ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo \"$*\" 1>&2; }
+function error () { info \"$*\"; exit 1; }
+
+[]
+
+[]
+
+[]
+
+
+\
+
+\h#struct-summary|SUMMARY|
+
+One-two sentences describing what the script does.
+
+\h#struct-func-desc|FUNCTIONALITY-DESCRIPTION|
+
+More detailed functionality description for more complex scripts.
+
+\h#struct-opt-desc|OPTIONS-DESCRIPTION|
+
+Description of command line options. For example:
+
+\
+# -q
+#   Run quiet.
+#
+# -t 
+#   Specify the alternative toolchain installation directory.
+\
+
+\h#struct-opt|OPTIONS|
+
+Command line options summary. For example:
+
+\
+usage=\"usage: $0 [-q] [-t ] \"
+\
+
+\h#struct-opt-arg-default|OPTIONS-ARGUMENTS-DEFAULTS|
+
+Set defaults to variables that will contain option/argument values. For
+example:
+
+\
+quiet=\"n\"
+tools=\"/usr/local\"
+file=
+\
+
+\h#struct-opt-arg-parse|OPTIONS-ARGUMENTS-PARSING|
+
+Parse the command line options/arguments. For example:
+
+\
+while [ \"$#\" -gt 0 ]; do
+  case \"$1\" in
+    -q)
+      quiet=\"y\"
+      shift
+      ;;
+    -t)
+      shift
+      tools=\"${1%/}\"
+      shift
+      ;;
+    *)
+      if [ -n \"$1\" ]; then
+        error \"$usage\"
+      fi
+
+      file=\"$1\"
+      shift
+      ;;
+  esac
+done
+\
+
+\h#struct-opt-arg-valid|OPTIONS-ARGUMENTS-VALIDATION|
+
+Validate option/argument values. For example:
+
+\
+if [ -z \"$file\" ]; then
+  error \"$usage\"
+fi
+
+if [ ! -d \"$file\" ]; then
+  fail \"'$file' does not exist or is not a directory\"
+fi
+\
+
+\h#struct-func|FUNCTIONALITY|
+
+Implement script logic. For diagnostics use the \c{info()} and \c{error()}
+functions defined above (so that it goes to stderr, not stdout). If using
+functions, then define them just before use.
+
+\h1#quote|Quoting|
+
+We quote every variable expansion, no exceptions. For example:
+
+\
+if [ -n \"$foo\" ]; then
+  ...
+fi
+\
+
+We also quote every variable assignment:
+
+\
+quiet=\"y\"
+\
+
+This also applies to command substitution (which we always write as
+\c{$(foo arg)} rather than \c{`foo arg`}), for example:
+
+\
+list=\"$(cat foo)\"
+\
+
+Note that a command substitution creates a new quoting context, for example:
+
+\
+list=\"$(basename \"$1\")\"
+\
+
+Note that quoting will inhibit globbing so you may end up with expansions
+along these lines:
+
+\
+rm -f \"$dir/$name\".*
+\
+
+If you have multiple values (e.g., program arguments) that may contain spaces,
+don't try to handle them with quoting and use arrays instead. Here is a
+typical example of a space-aware argument handling:
+
+\
+files=()
+
+while [ \"$#\" -gt 0 ]; do
+  case \"$1\" in
+
+    ...
+
+    *)
+      shift
+      files=(\"${files[@]}\" \"$1\")
+      shift
+      ;;
+  esac
+done
+
+rm -f \"${files[@]}\"
+\
+
+In the same vein, never write:
+
+\
+cmd $*
+\
+
+Instead always write:
+
+\
+cmd \"$@\"
+\
+
+\h1#trap|Trap|
+
+Our scripts use the error trap to automatically terminate the script in case
+any command fails. If you need to check the exit status of a command, use
+\c{if}, for example:
+
+\
+if grep \"foo\" \"bar\"; then
+  info \"found\"
+fi
+
+if ! grep \"foo\" \"bar\"; then
+  info \"not found\"
+fi
+\
+
+If you need to ignore the exit status, you can use \c{|| true}, for example:
+
+\
+foo || true
+\
+
+\h1#function|Functions|
+
+If a function takes arguments, provide a brief usage after the function
+header, for example:
+
+\
+function dist() #  
+{
+  ...
+}
+\
+
+For non-trivial/obvious functions also provide a short description of its
+functionality/purpose, for example:
+
+\
+# Prepare a distribution of the specified packages and place it into the
+# specified directory.
+#
+function dist() #  
+{
+  ...
+}
+\
+
+Inside functions use local variables, for example:
+
+\
+function dist()
+{
+  local x=\"foo\"
+}
+\
+
+If the evaluation of the value may fail (e.g., it contains a program
+substitution), then place the assignment on a separate line since \c{local}
+will ignore the error. For example
+
+\
+function dist()
+{
+  local b
+  b=\"$(basename \"$2\")\"
+}
+\
+"
diff --git a/doc/cli.sh b/doc/cli.sh
new file mode 100755
index 0000000..44d311a
--- /dev/null
+++ b/doc/cli.sh
@@ -0,0 +1,24 @@
+#! /usr/bin/env bash
+
+trap 'exit 1' ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo "$*" 1>&2; }
+function error () { info "$*"; exit 1; }
+
+while [ $# -gt 0 ]; do
+  case $1 in
+    --clean)
+      rm -f build2-bash-style.xhtml
+      exit 0
+      ;;
+    *)
+      error "unexpected $1"
+      ;;
+  esac
+done
+
+cli --generate-html --html-suffix .xhtml \
+--html-prologue-file doc-prologue.xhtml \
+--html-epilogue-file doc-epilogue.xhtml \
+--output-prefix build2- bash-style.cli
-- 
cgit v1.1