~mil/f_scripts

f_scripts/CONTRIBUTING.md -rw-r--r-- 6.4 KiB
48fcecefMiles Alan f_phone: Use any available modem & show opts for a few action prompts 10 days ago

#f_scripts: Contributing

Contributions in the form of new scripts or extra functionality or bug fixes on existing scripts are welcomed for f_scripts. Patches should be sent to the mailing list mentioned on the framebufferphone project page.

#Updating the README & Alpine package

Any time a script's metadata is modfied (e.g. the variables at top), both the README and the alpine package should be updated. 2 scripts automate the process of generating the new README and alpine package (APKBUILD).

# 1. Make changes to script
vi scripts/f_foo

# 2. Regenerate readme, commit, and send to ML
./scripts/gen_readmedocupdate.sh
git commit -m "f_foo: Changed whatever"

# 3. Once there's a new tag, regenerate APKBUILD, submit MR to aports
./scripts/gen_alpinepackage.sh > /path/to/aports/testing/f_scripts/APKBUILD

#Developing locally and uploading to your Pinephone

It's simple to develop on the Pinephone by manually changing scripts. You can directly edit each f_script via: vim $(which f_rss) and so on.

If you're developing locally (not on the Pinephone itself), you can quickly test by just rsync'ing things over / installing to /usr/bin. For this a Makfile task is defined as:

make pp

#General Development Principles and Overview

A few general high-level principles and an overview:

  • Each f_script should be designed as a standalone script
    • E.g. don't make one f_script depend on another f_script
    • If you need dependencies or common logic, make a seperate package in Alpine and flag in the DEP variable properly.
  • Assume & test against busybox utilities
    • Don't use coreutils.
  • KISS: keep it simple stupid
    • Keep things as simple as possible, don't use advanced features bash/bashisms.
    • All logic is eventually going to be migrated to Oil, so keep things simple and favor maintainability.
  • Each f_script uses Oil OSH for it shebang line
    • The choice of OSH is that Oil/OSH is statically parsed as opposed to bash/ash/dash etc.
    • Being statically parsed means we get better error messages and have syntactic clarity.
    • Syntactically OSH is just bash; don't use advanced bash features though.
  • The eventual plan to migrate from OSH to Oil
    • While currently each script uses OSH for it's shebang line, the eventual plan is for each f_script to be upgraded from OSH to Oil.
    • Oil is more maintainable and has a much more optimistic future then OSH/bash-like syntax.
    • Keeping things standalone and simple should aide in the plan to eventually upgrade to Oil.
    • Currently upgrading to Oil is blocked unfortunately because until Oil supports version numbers given feature sets, its a moving target. See this issue. Once Oil supports version numbers using shopt; the upgrade of each script will be done.

#Style Guide

All scripts within f_scripts follow a common style / pattern. Before creating a new script or modifying a script; acquaint yourself with the following style rules.

#1. The first 5 lines of all f_scripts should read as:

#!/usr/bin/env osh
shopt -s strict:all
DEP="space seperate deps"
DEC="1-line script description here"
DOC="longer documentation for script here"

#2. The last line of each f_script should be:

if [ -n "$1" ]; then "$@"; else main; fi

#3. The entire body of the script should be functions:

Good:

function foo() {
}

function bar() {
}

function main() {
  echo main
}

if test -z "$1"; then "$@"; else main; fi

#4. Functions which only have one line should be written as inline-style:

Good:

foo() { echo bar; }

Bad:

foo() {
  echo bar
}

#5. Use OSH locals wherever possible and avoid using global scope

Good:

function foo() {
  local MSG BAR
  MSG=$1
  BAR=foo
  [ $MSG = $BAR ] && echo foo
}

Bad:

function foo() {
  BAR=foo
  [ $MSG = $BAR ] && echo foo ## MSG set somewhere else
}

#6. If you must use a global - consistently name these & place in main

Really the only exception and reason to use globals are for state to access in signal handlers.

Good:

terminate() {
  echo "Referencing $GLOBAL_FOO so needs to be a global.."
  exit 0
}

function main() {
  GLOBAL_FOO=bar
  trap terminate HUP
  sleep 999
}

Bad:

function bar() {
  echo "Using $SOMEVAR"
}

function foo() {
  SOMEVAR=2
  bar
}
function main() {
  foo
}

#7. Prefer && or || operators rather then if-statements for simple logic

Good:

FOO=1
[ $FOO = 1 ] && echo yup

Bad:

FOO=1
if [ $FOO = 1 ]; then
  echo yup
fi

#8. Prefer single line-statements (when less-then 80 chars) & less-verbosity:

Good:

case "$FOO" in
  bar) echo baz;;
  bil) echo dil;;
esac

Bad:

case "$FOO" in
  bar)
    echo baz
    ;;
  bil)
    echo dil
    ;;
esac

#9. Variables should be written in UPPER_CASE_AND_UNDERSCORE_DELINITATED

Good:

FOO=1
BAR_BAZ=2

Bad:

foo=1
Bar_Baz=2

#10. Functions should be written in lowercase

Underscore deliniation is optional.

Good:

foobar() {
  echo bil
}

Bad:

FooBar() {
  echo baz
}

#11. Handling user-modifiable variables

Right below first 5 lines referenced in (1), if you want to define user-modifiable variables the defaults should be set in "$VAR" and then in main() you should eval the default $VAR if the variable of the script name is unset. As such, if a user sets F_SCRIPTNAME they will be able to override, all variables defined; if not, the defaults set in $VAR apply. Make sure to prefix all modifiable variables appearing in $VAR as with F_SCRIPTNAME_, e.g. for example: F_SCRIPTNAME_VARNAME.

Example:

VAR='
  F_FOO_VARIABLENAME=default
'

main() {
  env | grep -q "^$(basename "$0" | tr '[a-z]' '[A-Z]')=" || eval "$VAR"
  echo "$F_FOO_VARIABLENAME"
}

#12. Handling device-specific logic

If a script only supports the pinephone or some device for some piece of logic use /etc/deviceinfo to determine this and write a seperate function for each supported device as device${device_info_codename_hypen_stripped}.

devicepine64pinephone() {
  echo "Execute pinephone specific logic here"
}

main() {
  eval "$(grep deviceinfo_codename /etc/deviceinfo | cut -d= -f2 | tr -d \"- | xargs -ID echo deviceD)"
}