#!/usr/bin/env bash # # Recursively verify that every directory in edx-platform that contains # Python source code also contains an __init__.py file (aka a "dunder-init file"). # # Even though the Python 3 runner does not require that an __init__.py file # exist in every Python directory, some of our tooling (namely, pylint and # import-linter) depend on it existing, and will report false-positive success # otherwise. # # Run from root of directory with no args. # Example: # scripts/verify-dunder-init.sh # # Exits 0 if no errors, 1 otherwise. # Missing __init__.py files are printed to STDOUT. # Extra info is printed to STDIN. set -euo pipefail # Strict mode. ## Directories that contain Python source code, but for which we don't care ## whether or not there's a __init__.py file. exclude='' # Exclude repo root. exclude+='^\.$' # Exclude test data that includes Python (do NOT exclude unit test source code, though). exclude+='|^xmodule/capa/safe_exec/tests/test_files/?.*$' exclude+='|^common/test/data/?.*$' # xmodule data folder exclude+='|^xmodule/tests/data/xml-course-root/capa$' exclude+='|^xmodule/tests/data/xml-course-root/uploads/python_lib_zip$' # Docs, scripts. exclude+='|^docs/.*$' exclude+='|^lms/djangoapps/monitoring/scripts$' exclude+='|^scripts/?.*$' ## Counters for directories. no_python=0 excluded=0 errored=0 confirmed=0 ## Loop through all directories that are under version control. >&2 echo >&2 echo "============== begin list of missing files ==============" for directory in $(git ls-files | xargs dirname | sort | uniq) ; do if ! ls "$directory"/*.py &>/dev/null ; then # No Python in this directory; skip it. no_python=$(( no_python+1 )) continue fi if [[ "$directory" =~ $exclude ]]; then excluded=$(( excluded+1 )) # Directory is specifically excluded; skip it. continue fi if [[ -f "$directory"/__init__.py ]] ; then # Directory contains __init__.py; all good! confirmed=$(( confirmed+1 )) continue fi # Error! Print missing file to STDOUT. errored=$(( errored+1 )) echo "$directory/__init__.py" done >&2 echo "=============== end list of missing files ===============" ## Report results (to STDERR) >&2 echo >&2 echo "${no_python} directories do not contain Python source code." >&2 echo "${excluded} directories contain Python source code, but are excluded." >&2 echo >&2 echo "${confirmed} Python source directories DO contain an __init__.py file." >&2 echo "${errored} Python source directories do NOT contain an __init__.py file." >&2 echo ## Succeed or fail. if ! [[ errored -eq 0 ]] ; then >&2 echo "Check failed! All directories with Python source code must contain __init__.py (unless excluded)." exit 1 else >&2 echo "Check passed!" exit 0 fi