5.1 KiB
Contributing
pmbootstrap development is being discussed in #postmarketOS-devel.
CI scripts
Use pmbootstrap ci
inside your pmbootstrap.git
dir, to run all CI scripts
locally.
Coding style
A lot of the coding style is enforced by the CI scripts.
Python
- Use PEP8.
- Max line length: 80-100 characters (use 80 for comments and most code lines except when 100 makes much more sense; try to keep it consistent with existing code).
- Use f-strings for any new or modified code, instead of any of the other string formatting methods.
- pmbootstrap should run on any Linux distribution, so we support all active Python versions (see here).
- Docstrings below functions are formatted in
reST
style:
"""
This is a reST style.
:param param1: this is a first param
:param param2: this is a second param
:returns: this is a description of what is returned
:raises keyError: raises an exception
"""
Shell scripts
- Must be POSIX compliant, so busybox ash can interpret them. (Exception: the
local
keyword can also be used, to give variables a local scope inside functions).
Code patterns
The args
variable
This contains the arguments passed to pmbootstrap, and some additional data.
See pmb/helpers/args.py
for details. This is a legacy construct, see
#1879.
Executing commands
Use one of the following functions instead of Python's built-in subprocess
:
pmb.helpers.run.user()
pmb.helpers.run.root()
pmb.chroot.user()
pmb.chroot.root()
These functions call pmb.helpers.run_core.core()
internally to write to the
log file (that you can read with pmbootstrap log
) and timeout when there is
no output. A lot of function parameters are passed through to core()
as well,
see its docstring for a detailed description of what these parameters do.
Using shell syntax
The passed commands do not run inside a shell. If you need to use shell syntax,
wrap your command with sh -c
and use shutil.quote
on the parameters (if
they contain untrusted input):
# Does not work, the command does not run in a shell!
pmb.chroot.root(args, ["echo", "test", ">", "/tmp/test"])
# Use this instead (assuming untrusted input for text, dest)
text = "test"
dest = "/tmp/test"
shell_cmd = f"echo {shutil.quote(text)} > {shutil.quote(dest)}"
pmb.chroot.root(args, ["sh", "-c", shell_cmd])
If you need to run many commands in a shell at once, write them into a
temporary shell script and execute that with one of the pmb
command
functions.
Writing files to the chroot
The users in the chroots (root
and pmos
) have different user IDs than the
user of the host system. Therefore we can't just write a file to anywhere in
the chroot. Use one of the following methods.
Short files
pmb.chroot.user(args, ["sh", "-c", f"echo {shlex.quote(hostname)}"
" > /etc/hostname"], suffix)
Long files
Write to a temp dir first with python code, then move and chown the file.
with open("tmp/somefile", "w") as handle:
handle.write("Some long file")
handle.write("with multiple")
handle.write("lines here")
pmb.chroot.root(args, ["mv", "/tmp/somefile", "/etc/somefile"])
pmb.chroot.root(args, ["chown", "root:root", "/etc/somefile"], suffix)
Manual testing
APKBUILD parser
Besides the python tests, it's a good idea to let the APKBUILD parsing code run over all APKBUILDs that we have in pmaports.git, before and after making changes. This makes it easy to spot regressions.
$ pmbootstrap apkbuild_parse > /tmp/new
$ git checkout master
$ pmbootstrap apkbuild_parse > /tmp/old
$ colordiff /tmp/old /tmp/new | less -R
Debugging
Tab completion
When tab completion breaks, commands-line pmbootstrap build <TAB>
will simply
not return the expected list of packages anymore. Exceptions are not printed.
To change this behavior and get the exceptions, adjust the
eval "$(register-python-argcomplete pmbootstrap)"
line in your shell's rc
file.
$ register-python-argcomplete3 pmbootstrap
_python_argcomplete() {
local IFS=$'\013'
local SUPPRESS_SPACE=0
if compopt +o nospace 2> /dev/null; then
SUPPRESS_SPACE=1
fi
COMPREPLY=( $(IFS="$IFS" \
COMP_LINE="$COMP_LINE" \
COMP_POINT="$COMP_POINT" \
COMP_TYPE="$COMP_TYPE" \
_ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \
_ARGCOMPLETE=1 \
_ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \
"$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) )
if [[ $? != 0 ]]; then
unset COMPREPLY
elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "$COMPREPLY" =~ [=/:]$ ]]; then
compopt -o nospace
fi
}
complete -o nospace -o default -F _python_argcomplete "pmbootstrap"
Copy the whole output of the command to your shell's rc file instead of the
eval line, but remove 1>/dev/null 2>/dev/null
. Then it will print exceptions
to the shell.