Signed-off-by: Martin Roth <gaumless@gmail.com> Change-Id: Ib69236fb5d68272f92405512dc231fa75ecccaa6 Reviewed-on: https://review.coreboot.org/c/coreboot/+/80125 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de> Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
		
			
				
	
	
		
			313 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| set -e
 | |
| 
 | |
| VERSION="1.00"
 | |
| 
 | |
| PROGRAM=$0
 | |
| PROGNAME="$(basename "${PROGRAM}")"
 | |
| 
 | |
| MODIFIED_FILES=()
 | |
| CLEAN_DIR_LIST=(configs Documentation payloads spd src util)
 | |
| KEEP_FILES=(util/kconfig/)
 | |
| REQUIRED_MAKEFILES="util/testing\|util/crossgcc\|payloads/coreinfo\|payloads/nvramcui\|payloads/libpayload\|payloads/external/tint\|util/amdfwtool\|util/ectool\|util/futility\|util/intelmetool\|util/inteltool\|util/intelvbttool\|til/post\|util/superiotool"
 | |
| VERBOSE=
 | |
| 
 | |
| # Text STYLE variables
 | |
| BOLD="\033[1m"
 | |
| RED='\033[38;5;9m'
 | |
| GREEN='\033[38;5;2m'
 | |
| NO_COLOR='\033[0m'
 | |
| 
 | |
| ################################################################################
 | |
| 
 | |
| usage() {
 | |
| cat << EOF
 | |
| The ${PROGNAME} script is used to create a git patch that removes all files
 | |
| not used in a single build.  It does this by creating a temporary directory
 | |
| and configuring it to show the last time a file was accessed.  It then sets
 | |
| the time on all files back to midnight on 2021-01-01 and then does a full
 | |
| build. Because all Kconfig and Makefiles are accessed during the built,
 | |
| it then creates a new Kconfig file containing all of the old Kconfigs.
 | |
| The next step is to delete all of the files that have an access time still
 | |
| set to 2021.  The final step of the cleaning process is to recursively remove
 | |
| any Makefile that is alone in a directory by itself. The script then makes
 | |
| a commit and creates a patch.
 | |
| 
 | |
|   Usage: ${PROGNAME} [options]
 | |
| 
 | |
| Options:
 | |
|  -b | --blddir <dir>   Set /tmp/<dir> as the build directory
 | |
|  -h | --help            Print usage and exit
 | |
|  -D | --debug           Print debug information.  Use -DD to show all commands
 | |
|  -V | --version         Print the version and exit
 | |
|       --nocolor         Don't print color codes
 | |
| EOF
 | |
| }
 | |
| 
 | |
| _echo_color() {
 | |
|   local color="$1"
 | |
|   local text="$2"
 | |
|   local newline="$3"
 | |
|   if [[ ${newline} == "0" ]]; then
 | |
|     printf "${color}%s${NO_COLOR}" "${text}"
 | |
|   else
 | |
|     printf "${color}%s${NO_COLOR}\n" "${text}"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| _echo_error() {
 | |
|   _echo_color "${RED}" "$*" 1 >&2
 | |
| }
 | |
| 
 | |
| show_version() {
 | |
|   echo
 | |
|   _echo_color "${BOLD}${GREEN}" "${PROGNAME} version ${VERSION}"
 | |
|   echo
 | |
| }
 | |
| 
 | |
| get_args() {
 | |
|   if ! args="$(getopt -l version,help,debug,nocolor,blddir: -o b:DhV -- "$@")"; then
 | |
|     usage
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   eval set -- "${args}"
 | |
| 
 | |
|   while true; do
 | |
|     case "$1" in
 | |
|     -b | --blddir)
 | |
|       shift
 | |
|       BLD_DIR="/tmp/$1"
 | |
|       ;;
 | |
|     -D | --debug)
 | |
|       # -d prints extra debug info
 | |
|       # -dd prints all script steps
 | |
|       if [ -n "${VERBOSE}" ]; then
 | |
|         set -x
 | |
|       else
 | |
|         VERBOSE="V=1"
 | |
|       fi
 | |
|       ;;
 | |
|     -h | --help)
 | |
|       usage
 | |
|       exit 0
 | |
|       ;;
 | |
|     --nocolor)
 | |
|       BOLD=""
 | |
|       RED=""
 | |
|       GREEN=""
 | |
|       NO_COLOR=""
 | |
|       ;;
 | |
|     -V | --version) exit 0 ;;
 | |
|     --)
 | |
|       shift
 | |
|       break
 | |
|       ;;
 | |
|     *)
 | |
|       _echo_error "Unknown argument '$1'"
 | |
|       usage
 | |
|       exit 1
 | |
|       ;;
 | |
|     esac
 | |
|     shift
 | |
|   done
 | |
| 
 | |
|   if [[ -n $1 ]]; then
 | |
|     _echo_error "Unknown command '$1'"
 | |
|     usage
 | |
|     exit 1
 | |
|   fi
 | |
| 
 | |
|   BLD_DIR="${BLD_DIR:-$(mktemp -d)}"
 | |
| }
 | |
| 
 | |
| recursively_rm_dir_onlyfile() {
 | |
|   local dir=$1
 | |
|   local beforecount
 | |
|   local aftercount
 | |
| 
 | |
|   while true; do
 | |
|     if [[ ! -d ${dir} ]]; then
 | |
|       break
 | |
|     fi
 | |
|     beforecount="$(find "${dir}" | wc -l)"
 | |
|     while read -r file; do
 | |
| 	# Don't delete any of the makefiles required for building.
 | |
|       if echo "${file}" | grep -q "${REQUIRED_MAKEFILES}"; then
 | |
|         break
 | |
|       fi
 | |
|       # Remove the directory if a makefile is the only file present.
 | |
|       if [[ "$(cd "${file}" && find . -maxdepth 1 | grep -v "./Makefile")" == "." ]]; then
 | |
|         rm -rf "${file}"
 | |
|       fi
 | |
|     done < <(find "${dir}" -depth -type d)
 | |
|     if [[ ! -d ${dir} ]]; then
 | |
|       break
 | |
|     fi
 | |
|     find "${dir}" -type d -empty -delete
 | |
|     if [[ ! -d ${dir} ]]; then
 | |
|       break
 | |
|     fi
 | |
|     aftercount="$(find "${dir}" | wc -l)"
 | |
|     if [[ ${aftercount} -eq ${beforecount} ]]; then
 | |
|       break
 | |
|     fi
 | |
|   done
 | |
| }
 | |
| 
 | |
| verify_atime_enabled() {
 | |
|   local testfile
 | |
|   # Make sure the build directory is mounted correctly
 | |
|   if [ ! -d "${BLD_DIR}" ]; then
 | |
|     mkdir "${BLD_DIR}"
 | |
|   fi
 | |
|   if ! grep -q "${BLD_DIR}" /proc/mounts; then
 | |
|     echo "Mounting the ${BLD_DIR} directory with atime enabled"
 | |
|     sudo mount -t tmpfs -o rw,relatime tmpfs "${BLD_DIR}"
 | |
|   elif ! grep "${BLD_DIR}" /proc/mounts | grep -q relatime; then
 | |
|     echo "Remounting the ${BLD_DIR} directory with relatime enabled"
 | |
|     sudo mount -o remount,relatime "${BLD_DIR}"
 | |
|   fi
 | |
| 
 | |
|   testfile="$(mktemp -p "${BLD_DIR}")"
 | |
|   touch -a --date="2020-01-01 00:00:00" "${testfile}"
 | |
|   if ! stat "${testfile}" | grep -q "Access: 2020-01-01"; then
 | |
|     _echo_error "Error: could not set access time."
 | |
|     sudo umount "${BLD_DIR}"
 | |
|     rm -rf "${BLD_DIR}"
 | |
|     exit 1
 | |
|   fi
 | |
|   rm -f "${testfile}"
 | |
| }
 | |
| 
 | |
| update_codebase() {
 | |
|   local tempconfig
 | |
|   tempconfig="$(mktemp)"
 | |
|   if [ ! -f "${BLD_DIR}/COPYING" ]; then
 | |
|     echo "Downloading coreboot tree"
 | |
|     git clone https://review.coreboot.org/coreboot.git "${BLD_DIR}"
 | |
|     make -C "${BLD_DIR}" build/xcompile
 | |
|   fi
 | |
| 
 | |
|   # Start from a completely clean tree or we'll miss anything that
 | |
|   # doesn't need to be rebuilt.  Save the config if it exists.
 | |
|   if [[ -f .config ]]; then
 | |
|     mv .config "${tempconfig}"
 | |
|   fi
 | |
|   _echo_color "${GREEN}" "Cleaning coreboot tree"
 | |
|   make -s -C "${BLD_DIR}" distclean
 | |
|   if [[ -f ${tempconfig} ]]; then
 | |
|     mv "${tempconfig}" .config
 | |
|   fi
 | |
| 
 | |
|   # force a refresh of all submodules
 | |
|   _echo_color "${GREEN}" "Refreshing all submodules..."
 | |
|   git submodule update --recursive --remote --init --checkout
 | |
| }
 | |
| 
 | |
| save_kconfig() (
 | |
|   cd "${BLD_DIR}" && util/lint/kconfig_lint -w -p -o kconfig.tmp
 | |
| )
 | |
| 
 | |
| update_times() {
 | |
|   _echo_color "${GREEN}" "Updating access time of all files"
 | |
|   git ls-files | xargs touch -a -m -t 202001010000
 | |
|   if ! stat "${BLD_DIR}/COPYING" | grep -q "Access: 2020-01-01"; then
 | |
|     _echo_error "Error: could not set access time."
 | |
|     _echo_error "       One of the following processes may be accessing it."
 | |
|     fuser -uvm "${BLD_DIR}/COPYING"
 | |
|     exit 1
 | |
|   fi
 | |
| }
 | |
| 
 | |
| mark_files_to_keep() {
 | |
|   for file in "${KEEP_FILES[@]}"; do
 | |
|     find "${BLD_DIR}/${file}" -depth -exec touch {} \;
 | |
|   done
 | |
| }
 | |
| 
 | |
| build_platform() {
 | |
|   local extra_text="$1"
 | |
|   _echo_color "${GREEN}" "Building platform ${extra_text}"
 | |
|   if [[ ! -f "${BLD_DIR}/.config" ]]; then
 | |
|     if [[ -n ${CONFIG_FILE} ]]; then
 | |
|       cp "${CONFIG_FILE}" "${BLD_DIR}/.config"
 | |
|     fi
 | |
|     echo "CONFIG_PAYLOAD_NONE=y" >>"${BLD_DIR}/.config"
 | |
|   fi
 | |
| 
 | |
|   make -C "${BLD_DIR}" -s clean UPDATED_SUBMODULES=1 BUILD_TIMELESS=1
 | |
|   make -C "${BLD_DIR}" -s olddefconfig
 | |
|   make -C "${BLD_DIR}" -s UPDATED_SUBMODULES=1 BUILD_TIMELESS=1 ${VERBOSE}
 | |
|   HASH="$(sha256sum build/coreboot.rom)"
 | |
|   make -C "${BLD_DIR}" -s clean UPDATED_SUBMODULES=1 BUILD_TIMELESS=1
 | |
| }
 | |
| 
 | |
| show_modified() {
 | |
|   readarray MODIFIED_FILES < <(find "${BLD_DIR}" -atime -1 -type f -path ./.git -prune)
 | |
|   echo "Files changed: ${#MODIFIED_FILES[@]}"
 | |
| }
 | |
| 
 | |
| remove_kconfigs() {
 | |
|   # Dump all Kconfigs into a single file so that directories
 | |
|   # can be removed, while maintaining the entire Kconfig
 | |
|   # structure.
 | |
|   find "${BLD_DIR}/src" -name 'Kconfig*' -delete
 | |
|   mv "${BLD_DIR}/kconfig.tmp" "${BLD_DIR}/src/Kconfig"
 | |
| }
 | |
| 
 | |
| remove_unused() {
 | |
|   local dir
 | |
|   # Most files can be removed simply by looking at the time, but
 | |
|   # all Kconfig and Makefiles in the entire tree are accessed
 | |
|   # whether they're used or not.
 | |
|   remove_kconfigs
 | |
| 
 | |
|   echo
 | |
|   _echo_color "${GREEN}" "Checking access time and removing unused files in:"
 | |
|   for dir in "${CLEAN_DIR_LIST[@]}"; do
 | |
|     printf "%s\n" "${BLD_DIR}/${dir}"
 | |
|     # find and remove all files without updated times.
 | |
|     find "${BLD_DIR}/${dir}" -atime +5 -type f -delete
 | |
| 
 | |
|     recursively_rm_dir_onlyfile "${BLD_DIR}/${dir}"
 | |
|   done
 | |
|   printf "\n\n"
 | |
| }
 | |
| 
 | |
| create_patch() {
 | |
|   _echo_color "${GREEN}" "Creating patch"
 | |
|   (
 | |
|     cd "${BLD_DIR}"
 | |
|     git add -A
 | |
|     git commit -m "remove unused files" --no-verify
 | |
|     git format-patch HEAD^
 | |
|   )
 | |
| }
 | |
| 
 | |
| main() {
 | |
|   show_version
 | |
|   get_args "$@"
 | |
| 
 | |
|   verify_atime_enabled
 | |
|   update_codebase
 | |
|   save_kconfig
 | |
|   update_times
 | |
|   mark_files_to_keep
 | |
|   build_platform "to mark used files"
 | |
|   OLDHASH="${HASH}"
 | |
|   HASH=""
 | |
|   #show_modified
 | |
|   remove_unused
 | |
|   create_patch
 | |
|   build_platform "to verify the build still works"
 | |
|   NEWHASH="${HASH}"
 | |
| 
 | |
|   echo
 | |
|   _echo_color "${GREEN}" "Checksums:"
 | |
|   echo "Old: ${OLDHASH}"
 | |
|   echo "New: ${NEWHASH}"
 | |
| }
 | |
| 
 | |
| main "$@"
 |