| #!/usr/bin/env bash |
| # |
| # Pull in linux-stable updates to a kernel tree |
| # |
| # Copyright (C) 2017 Nathan Chancellor |
| # |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/> |
| |
| |
| # Get main tree location |
| TREE=$( cd $( dirname $( readlink -f "${BASH_SOURCE[0]}" ) )/../../.. && pwd ) |
| |
| |
| # Colors for script |
| BOLD="\033[1m" |
| GRN="\033[01;32m" |
| RED="\033[01;31m" |
| RST="\033[0m" |
| YLW="\033[01;33m" |
| |
| |
| # Alias for echo to handle escape codes like colors |
| function echo() { |
| command echo -e "$@" |
| } |
| |
| |
| # Prints a formatted header to point out what is being done to the user |
| function header() { |
| if [[ -n ${2} ]]; then |
| COLOR=${2} |
| else |
| COLOR=${RED} |
| fi |
| echo ${COLOR} |
| echo "====$(for i in $(seq ${#1}); do echo "=\c"; done)====" |
| echo "== ${1} ==" |
| echo "====$(for i in $(seq ${#1}); do echo "=\c"; done)====" |
| echo ${RST} |
| } |
| |
| |
| # Prints an error in bold red |
| function report_error() { |
| echo |
| echo ${RED}${1}${RST} |
| if [[ ${2} = "-h" ]]; then |
| ${0} -h |
| fi |
| exit 1 |
| } |
| |
| |
| # Prints a warning in bold yellow |
| function report_warning() { |
| echo |
| echo ${YLW}${1}${RST} |
| if [[ -z ${2} ]]; then |
| echo |
| fi |
| } |
| |
| |
| # Parse the provided parameters |
| function parse_parameters() { |
| while [[ $# -ge 1 ]]; do |
| case ${1} in |
| # Use git cherry-pick |
| "-c"|"--cherry-pick") |
| UPDATE_METHOD=cherry-pick ;; |
| |
| # Only update the linux-stable remote |
| "-f"|"--fetch-only") |
| FETCH_REMOTE_ONLY=true ;; |
| |
| # Help menu |
| "-h"|"--help") |
| echo |
| echo "${BOLD}Script description:${RST} Merges/cherry-picks Linux upstream into a kernel tree" |
| echo |
| echo "${BOLD}Required parameters:${RST}" |
| echo " -c | --cherry-pick" |
| echo " -m | --merge" |
| echo " Call either git cherry-pick or git merge when updating from upstream" |
| echo |
| echo " -k | --kernel-folder" |
| echo " The device's kernel source's location relative to the \"kernel\" folder in the root of the ROM tree" |
| echo " If unsure, run \"croot; cd kernel; ls --directory */*\" in your terminal (assuming you ran \". build/envsetup.sh\"" |
| echo |
| echo "${BOLD}Optional parameters" |
| echo " -f | --fetch-only" |
| echo " Simply fetches the tags from linux-stable then exits" |
| echo |
| echo " -l | --latest" |
| echo " Updates to the latest version available for the current kernel tree" |
| echo |
| echo " -p | --print-latest" |
| echo " Prints the latest version available for the current kernel tree then exits" |
| echo |
| echo " -v | --version" |
| echo " Updates to the specified version (e.g. -v 3.18.78)" |
| echo |
| echo " By default, only ONE version is picked at a time (e.g. 3.18.31 to 3.18.32)" |
| echo |
| exit 1 ;; |
| |
| # Kernel source location |
| "-k"|"--kernel-folder") |
| shift |
| if [[ $# -lt 1 ]]; then |
| report_error "Please specify a device directory!" |
| fi |
| |
| KERNEL_FOLDER=${TREE}/kernel/${1} ;; |
| |
| # Update to the latest version upstream unconditionally |
| "-l"|"--latest") |
| UPDATE_MODE=1 ;; |
| |
| # Use git merge |
| "-m"|"--merge") |
| UPDATE_METHOD=merge ;; |
| |
| # Print the latest version from kernel.org |
| "-p"|"--latest") |
| PRINT_LATEST=true ;; |
| |
| # Update to the specified version |
| "-v"|"--version") |
| shift |
| if [[ $# -lt 1 ]]; then |
| report_error "Please specify a version to update!" |
| fi |
| |
| TARGET_VERSION=${1} ;; |
| |
| *) |
| report_error "Invalid parameter!" ;; |
| esac |
| |
| shift |
| done |
| |
| # Sanity checks |
| if [[ ! ${UPDATE_METHOD} ]]; then |
| report_error "Neither cherry-pick nor merge were specified, please supply one!" -h |
| elif [[ ! -d ${KERNEL_FOLDER} ]]; then |
| report_error "Invalid kernel source location specified! Folder does not exist" -h |
| elif [[ ! -f ${KERNEL_FOLDER}/Makefile ]]; then |
| report_error "Invalid kernel source location specified! No Makefile present" -h |
| fi |
| |
| # Default update mode is one version at a time |
| if [[ -z ${UPDATE_MODE} ]]; then |
| UPDATE_MODE=0 |
| fi |
| } |
| |
| |
| # Update the linux-stable remote (and add it if it doesn't exist) |
| function update_remote() { |
| header "Updating linux-stable" |
| |
| # Add remote if it isn't already present |
| cd ${KERNEL_FOLDER} |
| |
| git fetch --tags https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/ |
| |
| if [[ $? -ne 0 ]]; then |
| report_error "linux-stable update failed!" |
| else |
| echo "linux-stable updated successfully!" |
| fi |
| |
| if [[ ${FETCH_REMOTE_ONLY} ]]; then |
| echo |
| exit 0 |
| fi |
| } |
| |
| |
| # Generate versions |
| function generate_versions() { |
| header "Calculating versions" |
| |
| # Full kernel version |
| CURRENT_VERSION=$(make kernelversion) |
| # First two numbers (3.4 | 3.10 | 3.18 | 4.4) |
| CURRENT_MAJOR_VERSION=$(echo ${CURRENT_VERSION} | cut -f 1,2 -d .) |
| # Last number |
| CURRENT_SUBLEVEL=$(echo ${CURRENT_VERSION} | cut -d . -f 3) |
| |
| # Get latest update from upstream |
| LATEST_VERSION=$(git tag --sort=-taggerdate -l v${CURRENT_MAJOR_VERSION}* | head -n 1 | sed s/v//) |
| LATEST_SUBLEVEL=$(echo ${LATEST_VERSION} | cut -d . -f 3) |
| |
| # Print the current/latest version and exit if requested |
| echo "${BOLD}Current kernel version:${RST} ${CURRENT_VERSION}" |
| echo |
| echo "${BOLD}Latest kernel version:${RST} ${LATEST_VERSION}" |
| if [[ ${PRINT_LATEST} ]]; then |
| echo |
| exit 0 |
| fi |
| |
| # UPDATE_MODES: |
| # 0. Update one version |
| # 1. Update to the latest version |
| case ${UPDATE_MODE} in |
| 0) |
| TARGET_SUBLEVEL=$((${CURRENT_SUBLEVEL} + 1)) |
| TARGET_VERSION=${CURRENT_MAJOR_VERSION}.${TARGET_SUBLEVEL} ;; |
| 1) |
| TARGET_VERSION=${LATEST_VERSION} ;; |
| esac |
| |
| # Make sure target version is between current version and latest version |
| TARGET_SUBLEVEL=$(echo ${TARGET_VERSION} | cut -d . -f 3) |
| if [[ ${TARGET_SUBLEVEL} -le ${CURRENT_SUBLEVEL} ]]; then |
| report_error "${TARGET_VERSION} is already present in ${CURRENT_VERSION}!\n" |
| elif [[ ${TARGET_SUBLEVEL} -gt ${LATEST_SUBLEVEL} ]]; then |
| report_error "${CURRENT_VERSION} is the latest!\n" |
| fi |
| |
| RANGE=v${CURRENT_VERSION}..v${TARGET_VERSION} |
| |
| echo |
| echo "${BOLD}Target kernel version:${RST} ${TARGET_VERSION}" |
| echo |
| } |
| |
| |
| function update_to_target_version() { |
| case ${UPDATE_METHOD} in |
| "cherry-pick") |
| git cherry-pick ${RANGE} |
| if [[ $? -ne 0 ]]; then |
| report_error "Cherry-pick needs manual intervention! Resolve conflicts then run: |
| |
| git add . && git cherry-pick --continue" |
| else |
| header "${TARGET_VERSION} PICKED CLEANLY!" ${GRN} |
| fi ;; |
| |
| "merge") |
| GIT_MERGE_VERBOSITY=1 git merge --no-edit v${TARGET_VERSION} |
| if [[ $? -ne 0 ]]; then |
| report_error "Merge needs manual intervention! |
| |
| Resolve conflicts then run git merge --continue!" |
| else |
| header "${TARGET_VERSION} MERGED CLEANLY!" ${GRN} |
| fi ;; |
| esac |
| } |
| |
| |
| parse_parameters $@ |
| update_remote |
| generate_versions |
| update_to_target_version |