~mil/f_scripts

ref: 0.3 f_scripts/CONTRIBUTING.md -rw-r--r-- 6.4 KiB
f29da769Miles Alan f_audio, f_youtube: Set dac to 100%, fixed muted sound by default 10 months 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, however if you're developing on another machine you may want to

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)"
}