path: root/HACKING/
diff options
Diffstat (limited to 'HACKING/')
1 files changed, 134 insertions, 0 deletions
diff --git a/HACKING/ b/HACKING/
new file mode 100644
index 0000000..a520ce5
--- /dev/null
+++ b/HACKING/
@@ -0,0 +1,134 @@
+Code content
+Be aware of the `librelib(7)` library suite, which lives `src/lib`.
+It is a suite of Bash libraries that will help you out. Most of the
+people looking at the libretools code are familiar with the `messages`
+part of it, which actually contains a bunch of utility routines, not
+just message printing. There is also a library for dealing with
+`blacklist.txt`, and one for loading configuration files and
+PKGBUILDs. These are common tasks, but are tricky to handle
+consistently--the libraries are there to make things easier. Take a
+look at the man pages.
+Message printing: All of the message printing routines, except for
+`term_title` and `flag`, take printf-type arguments. Take advantage
+of that; don't use string interpolation (don't do `"foo ${var}
+bar"`). The reason for this is that if you don't do string
+interpolation, messages can be automatically internationalized.
+(Internationalization is incomplete at the momement)
+Message printing: The in `--help`/`-h` text, use `print` to print
+lines that should not wrap, `echo` to print blank lines, `prose` to
+print paragraphs, `bullet` to print bullet points, and `flag` to print
+option flags. The text should follow this general format:
+ print "Usage: %s [OPTIONS] VARS_ARE_UNDERSCORE_AND_CAPITAL" "${program_name}"
+ print "One line description of program, no period"
+ echo
+ prose "More details. This is a paragraph."
+ echo
+ print "Options:"
+ flag "-h" "Show this message"
+In the "Usage:" line, use printf `%s` and the value `"${0##*/}"` to
+determine the program name at runtime.
+There used to be guidelines for how to align the option flags and
+descriptions, but now the `flag` command exists takes care of it for
+you. Yay for things being easier!
+When using `set -u`, `set -e`, or `trap`, you should also use `set -E`
+to have the error handling be passed down to subshells.
+Feel free to use `set -e` (fail on error), but be careful of the
+caveats (there are a bunch of them); don't assume all errors are
+checked because of it.
+Use `set -u` if you can; it makes using an unset variable an error.
+ - If a variable not being set is valid (perhaps a configuration
+ option), use `${var:-}` when accessing it to suppress the error.
+ - An empty array counts as unset, so if you have an array that may be
+ empty, use `set +u` before accessing it.
+ - The reason for this is that a normal string variable is basically
+ an array with length=1; an unset variable looks like an array
+ with length=0. Weird stuff.
+In the shebang, use `#!/usr/bin/env bash`. This allows us to not
+hardcode the location of bash (I'm not sure why this is useful for
+something distro-dependent like libretools, but fauno seems to have a
+use-case for it).
+In the shebang, don't pass flags to bash, besides breaking `env`
+(above), it means people will make mistakes when debugging, and
+running things with `bash FILENAME`. Instead, use `set` to adjust the
+flags inside of the program.
+Obey `$TMPDIR`. It's usually as easy as passing `--tmpdir` to
+Use `trap` to clean up your temporary files. This way, even if your
+program terminates early, things will be cleaned up.
+Bash best practices
+Basically, know what you are doing, and be safe with it. The problem
+is that most people don't know about safe bash scripting.
+A lot of people look at the "Advanced Bash Scripting" ebook--DO NOT do
+that, it is trash... though it contains a "reference card" page that
+may be useful and isn't trash.
+Take a look at Gentoo's Bash guidelines
+They're pretty good, and cover most of the "gotcha's" about Bash
+syntax. It mentions but discourages the use of Bash 3
+features... why? Who still uses Bash 2? Feel free to use Bash 4
+I wrote an article on Bash arrays
+<>. A lot of people think
+they're tricky, but they're simple once you know how they work. It's
+short enough that you should read the whole thing. Know the
+difference between `"${array[@]}"` and `"${array[*]}"`. And I'll say
+it again here, ALWAYS wrap those in double quotes; there is no reason
+I can think of that the unquoted behavior would ever be the correct
+My brief rules of thumb:
+ - Quote every variable.
+ - That includes arrays: `"${array[@]}"` and `"${array[*]}"`.
+ - In most (but not all!) cases inside of `[[ ... ]]` conditions,
+ variables don't need to be quoted. When in doubt, quote them.
+ - When assigning one variable to another, you don't need quotes;
+ you don't need quotes for `foo=$bar`
+ - Try to avoid global variables; declare all variables in functions
+ with `local`.
+ - Or `declare`; inside of a function, unless you pass the `-g`
+ flag, `declare` makes the variable local.
+ - Use `local VAR` before a `for VAR in LIST` loop--the variable is created in the
+ current scope, not the scope of the loop.
+ - Feeding input to `while` loops is weird because of how subshells
+ work:
+ # Input from a file
+ # BAD
+ cat file | while read line; do
+ ...
+ done
+ # GOOD
+ while read line; do
+ ...
+ done <file
+ # Input from a program
+ # BAD
+ prog | while read line; do
+ ...
+ done
+ # GOOD
+ while read line; do
+ ...
+ done < <(prog)