Skip to content
Snippets Groups Projects
dim 46.2 KiB
Newer Older
Simona Vetter's avatar
Simona Vetter committed
#!/bin/bash

# Copyright © 2012-2016 Intel Corporation
Simona Vetter's avatar
Simona Vetter committed
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Authors:
#    Daniel Vetter <daniel.vetter@ffwll.ch>
#    Jani Nikula <jani.nikula@intel.com>
Simona Vetter's avatar
Simona Vetter committed

# drm-intel-next maintainer script

# fail on any goof-up
Simona Vetter's avatar
Simona Vetter committed

# User configuration. Set in environment or configuration file. See
# dimrc.sample for an example.
#

# dim configuration file
DIM_CONFIG=${DIM_CONFIG:-$HOME/.dimrc}
if [ -r $DIM_CONFIG ]; then
	# shellcheck source=/dev/null
	. $DIM_CONFIG
fi

# prefix for repo directories
DIM_PREFIX=${DIM_PREFIX:-$HOME/linux}

# main maintainer repo under $DIM_PREFIX
DIM_REPO=${DIM_REPO:-${DIM_DRM_INTEL:-src}}
# mail user agent. must support a subset of mutt(1) command line options:
# usage: $DIM_MUA [-s subject] [-i file] [-c cc-addr] to-addr [...]
DIM_MUA=${DIM_MUA:-mutt}

# make options (not used for C=1)
DIM_MAKE_OPTIONS=${DIM_MAKE_OPTIONS:--j20}

# command to run after dim apply
DIM_POST_APPLY_ACTION=${DIM_POST_APPLY_ACTION:-}

# greetings pull request template
DIM_TEMPLATE_HELLO=${DIM_TEMPLATE_HELLO:-$HOME/.dim.template.hello}

# signature pull request template
DIM_TEMPLATE_SIGNATURE=${DIM_TEMPLATE_SIGNATURE:-$HOME/.dim.template.signature}

# dim pull-request tag summary template
DIM_TEMPLATE_TAG_SUMMARY=${DIM_TEMPLATE_TAG_SUMMARY:-$HOME/.dim.template.tagsummary}

# GPG key id for signing tags. If unset, don't sign.
DIM_GPG_KEYID=${DIM_GPG_KEYID:+-u $DIM_GPG_KEYID}

today=$(date +%Y-%m-%d)
Simona Vetter's avatar
Simona Vetter committed

# Recipients for all dim based pull requests.
# Add To: lines to the end, Cc: lines in the beginning with -c.
pull_request_recipients=(
	-c "Daniel Vetter <daniel.vetter@ffwll.ch>"
	-c "Jani Nikula <jani.nikula@linux.intel.com>"
	-c "Joonas Lahtinen <joonas.lahtinen@linux.intel.com>"
	-c "Rodrigo Vivi <rodrigo.vivi@intel.com>"
	-c "Sean Paul <seanpaul@chromium.org>"
	-c "dri-devel@lists.freedesktop.org"
	-c "intel-gfx@lists.freedesktop.org"
	"Dave Airlie <airlied@gmail.com>"
)

# Recipients for drm-intel-testing updates.
test_request_recipients=(
	-c "Jani Nikula <jani.nikula@linux.intel.com>"
	-c "Joonas Lahtinen <joonas.lahtinen@linux.intel.com>"
	-c "Rodrigo Vivi <rodrigo.vivi@intel.com>"
	-c "intel-gfx@lists.freedesktop.org"
	"Jari Tahvanainen <jari.tahvanainen@intel.com>"
)
# integration configuration
integration_config=nightly.conf

function read_integration_config
{
	# clear everything first to allow configuration reload
	unset drm_tip_repos drm_tip_config
	declare -g -A drm_tip_repos
	declare -g -a drm_tip_config

	if [ -r $DIM_PREFIX/drm-rerere/$integration_config ]; then
		# shellcheck source=/dev/null
		source $DIM_PREFIX/drm-rerere/$integration_config

		if [[ "${#drm_tip_repos[@]}" = "0" ]] || [[ "${#drm_tip_config[@]}" = "0" ]]; then
			echoerr "$integration_config not set up correctly, please fix manually"
			exit 1
		fi
	else
		echoerr "$integration_config is missing, please check your configuration and/or run dim setup"
		exit 1
	fi

	dim_branches=
	for conf in "${drm_tip_config[@]}"; do
		local repo branch override
Jani Nikula's avatar
Jani Nikula committed
		read -r repo branch override <<< $conf
		if [[ "$repo" = "drm-intel" || "$repo" = "drm-misc" ]]; then
			dim_branches="$dim_branches $branch"
		fi
	done
}

	echo "$dim: $*" >&2
Simona Vetter's avatar
Simona Vetter committed
function warn_or_fail
{
	if [[ $FORCE ]] ; then
		echoerr "WARNING: $1, but continuing"
	elif [[ $DRY ]] ; then
		echoerr "WARNING: $1, but continuing dry-run"
Simona Vetter's avatar
Simona Vetter committed
	else
		echoerr "ERROR: $1, aborting"
function pause
{
	read -rsp "Press any key to continue..." -n1 key2
	echo
}

#
# Command line options.
#

DRY_RUN=
INTERACTIVE=
DRY=
FORCE=
HELP=

while getopts hdfis opt; do
	case "$opt" in
		d)
			DRY_RUN=--dry-run
			DRY=echo
			;;
Simona Vetter's avatar
Simona Vetter committed
		i)
Simona Vetter's avatar
Simona Vetter committed
			;;
		s)
			# FIXME: transitional, do unconditionally at the top
			# when there are no more errors about unbound variables
			set -u
			;;
			echoerr "See '$dim help' for more information."
shift $((OPTIND - 1))

# first positional argument is the subcommand
if [ -n "$HELP" ] || [ "$#" = "0" ]; then
else
    subcommand="$1"
    shift
fi
# generic usage to be used for ${1:?$usage} style argument references
usage="Missing arguments(s) for '$dim $subcommand'. See '$dim help' for usage."

# Make sure we use 'dim_foo' within dim instead of 'dim foo'.
if [[ -n "${__dim_running:-}" ]]; then
	echoerr "INTERNAL ERROR: do not recurse back to dim"
	exit 1
fi
export __dim_running=1

if [ "$subcommand" != "setup" ] && [ "$subcommand" != "help" ] && [ "$subcommand" != "usage" ]; then
	for d in $DIM_PREFIX $DIM_PREFIX/$DIM_REPO $DIM_PREFIX/drm-rerere $DIM_PREFIX/drm-tip; do
		if [ ! -d $d ]; then
			echoerr "$d is missing, please check your configuration and/or run dim setup"

	read_integration_config
#
# Only function and alias definitions until the subcommand handling at the end.
#

#
# Variable naming convetion:
#
# repo:
#	symbolic git repository name from $integration_config
# remote:
#	local remote name in the git repository for the current path
# branch:
#	git branch name - dim assumes that the remote and local name match
# url:
#	url to a repo, using ssh:// protocol
# git_url:
#	url to a repo, but using anonymous git:// protocol
#
# The below functions map between these.
#

function url_to_remote # url [url ...]
	if [[ "$#" = "0" ]]; then
		echoerr "url_to_remote without URLs"
	for url; do
		remote=$(git remote -v | grep -m 1 "$url" | cut -f 1)
		if [[ -n "$remote" ]]; then
			echo "$remote"
			return 0
		fi
	done
	echoerr "No git remote for any of the URLs $* found in $(pwd)"
	url=$1
	remote=${url%.git}
	remote=${remote##*/}
	read -r -i "$remote" -e -p "Enter a name to auto-add this remote, leave blank to abort: " remote
	if [[ -z "$remote" ]]; then
		echoerr "Please set it up yourself using:"
		echoerr "    $ git remote add <name> $url"
		echoerr "with a name of your choice."
function pick_protocol_url # (git|ssh|https|whatever) url [url ...]
	local url protocol protocol_url
	if [[ "$#" -lt "2" ]]; then
		echoerr "pick_protocol_url without protocol or URLs"
	protocol=$1
	shift

	# Find the URL that has given protocol
			${protocol}://*)
				protocol_url=$url
	if [[ -z "$protocol_url" ]]; then
		echoerr "No $protocol URL in any of the URLs: $*"
function branch_to_remote # branch
{
	local branch remote
	branch=$1
	remote=$(git rev-parse --abbrev-ref --symbolic-full-name "$branch@{upstream}")
	remote=${remote%%/*}

	echo $remote
}

function repo_to_remote # repo
{
	local repo url_list

	repo=$1
	url_list=${drm_tip_repos[$repo]}

	if [[ -z "$url_list" ]]; then
		echoerr "unknown repo $repo"
		return 1
	fi

	url_to_remote $url_list
function branch_to_repo # branch
{
	for conf in "${drm_tip_config[@]}"; do
		local repo branch override
Jani Nikula's avatar
Jani Nikula committed
		read -r repo branch override <<< $conf
		if [[ "$branch" == "$1" ]] ; then
function dim_uptodate
{
	local using

	using="${BASH_SOURCE[0]}"

	if [[ ! -e "$using" ]]; then
		echoerr "could not figure out the version being used ($using)."
	fi

	if [[ ! -e "$DIM_PREFIX/maintainer-tools/.git" ]]; then
		echoerr "could not find the upstream repo for $dim."
	if ! git --git-dir=$DIM_PREFIX/maintainer-tools/.git show "@{upstream}:dim" |\
			diff "$using" - >& /dev/null; then
		echoerr "not running upstream version of the script."
Simona Vetter's avatar
Simona Vetter committed
function git_fetch_helper # remote
{
	local remote

	remote=$1

	if ! git fetch --prune -q $remote ; then
Simona Vetter's avatar
Simona Vetter committed
		# old git versions returned 128 if there was nothing to fetch
		if [[ $? -ne "128" ]] ; then
			echoerr "Failed to fetch $remote"
			return 1
		fi
	fi
}

function git_current_branch
{
	git symbolic-ref -q --short HEAD
}

function git_is_current_branch # branch
{
	test "$(git_current_branch)" = "$1"
function git_branch_exists # branch
{
	if [[ "$(git branch --list $1)" == "" ]] ; then
function git_committer_email
{
	if ! committer_email=$(git config --get user.email) ; then
Jani Nikula's avatar
Jani Nikula committed
		committer_email=${EMAIL-}
	fi

	echo $committer_email
}

# get message id from file
# $1 = file
message_get_id ()
{
	python <<EOF
from email.parser import Parser
headers = Parser().parse(open('$1', 'r'))
message_id = headers['message-id']
if message_id is not None:
    print(message_id.strip('<>'))
EOF
}

message_print_body ()
{
	python2 <<EOF
import email

def print_part(part):
    mtype = part.get_content_maintype()
    if mtype == 'text':
        print(part.get_payload(decode=True))

def print_msg(file):
    msg = email.message_from_file(file)
    if msg.is_multipart():
        for part in msg.get_payload():
            print_part(part)
    else:
        print_part(msg)

print_msg(open('$1', 'r'))
EOF
}

# append all arguments as tags at the end of the commit message of HEAD
function dim_commit_add_tag
	for arg; do
		# the first sed deletes all trailing blank lines at the end
		git log -1 --pretty=%B | \
			sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' | \
			sed "\$a${arg}" | \
			git commit --amend -F-
	done
# $1: branch [optional]
function git_find_tip
{
	git log $1 -1 --format=%H --grep="^drm-tip: .* integration manifest$"
}

# $1: branch [optional]
function dim_retip
{
	local branch upstream remote

	branch="$1"

	if [ -n "$branch" ] ; then
		shift
	else
		branch=$(git symbolic-ref --short HEAD)
	fi

	remote=$(repo_to_remote drm-tip)
	upstream=$(git_find_tip "$branch")

	if [[ -z "$upstream" ]]; then
		echoerr "$branch is not based on drm-tip"
		return 1
	fi

	git rebase --onto $remote/drm-tip $upstream $branch "$@"
}

# update for-linux-next and for-linux-next-fixes branches
function update_linux_next # branch next next-fixes fixes
Simona Vetter's avatar
Simona Vetter committed
{
	local branch linux_next linux_next_fixes linux_fixes repo remote

	cd $DIM_PREFIX/drm-tip
	branch=$1
	linux_next=$2
	linux_next_fixes=$3
	linux_fixes=$4
	repo=$(branch_to_repo $branch)
	if [[ $repo != $(branch_to_repo $linux_next) ]] ; then
	remote=$(repo_to_remote $repo)
Simona Vetter's avatar
Simona Vetter committed
	git_fetch_helper $remote
	# always update drm-intel-fixes
	echo -n "Pushing $linux_fixes to for-linux-next-fixes... "
	git push $DRY_RUN $remote +$remote/$linux_fixes:for-linux-next-fixes # >& /dev/null
	if git merge-base --is-ancestor $remote/$linux_next_fixes $remote/$linux_fixes ; then
		# -fixes has caught up to dinf, i.e. we're out of the merge
		# window. Push the next queue.
		echo -n "Out of merge window. Pushing $linux_next to for-linux-next... "
		git push $DRY_RUN $remote +$remote/$linux_next:for-linux-next >& /dev/null
Simona Vetter's avatar
Simona Vetter committed
	else
		# dinf is ahead of -fixes, i.e. drm-next has already closed for
		# the next merge window and we've started to gather new fixes
		# for the current -next cycle. Push dinf
		echo -n "Pushing $linux_next_fixes to for-linux-next... "
		git push $DRY_RUN $remote +$remote/$linux_next_fixes:for-linux-next >& /dev/null
Simona Vetter's avatar
Simona Vetter committed
	fi
}

function check_conflicts # tree
Simona Vetter's avatar
Simona Vetter committed
{
Simona Vetter's avatar
Simona Vetter committed
	if git diff | grep -q '\(<<<<<<<\|=======\|>>>>>>>\||||||||\)' ; then
		# we need an empty line to make it look pretty
		echoerr ""
		echoerr "FAILURE: Could not merge $1"
		echoerr "See the section \"Resolving Conflicts when Rebuilding drm-tip\""
		echoerr "in the drm-intel.rst documentation for how to handle this situation."
Simona Vetter's avatar
Simona Vetter committed
		exit 1
	fi
	true
}

function rr_cache_dir
{
Simona Vetter's avatar
Simona Vetter committed
	if [ -d $DIM_PREFIX/drm-tip/.git/ ] ; then
		echo $DIM_PREFIX/drm-tip/.git/rr-cache
		echo $DIM_PREFIX/$DIM_REPO/.git/rr-cache
function update_rerere_cache
{
	echo -n "Updating rerere cache... "

	cd $DIM_PREFIX/drm-rerere/
	if ! git pull -q ; then
		echoerr "Failed to update the rerere cache."
		echoerr "Please manually run"
		echoerr "	$ cd $DIM_PREFIX/drm-rerere ; git pull"
		echoerr "and fixup any issues."

		return 1
	fi
	if [ ! -L $(rr_cache_dir) ] ; then
		if [ -d $(rr_cache_dir) ] ; then
			rm -Rf $(rr_cache_dir)
		fi
		ln -s "$DIM_PREFIX/drm-rerere/rr-cache" $(dirname $(rr_cache_dir))
	fi

	cd - > /dev/null

	echo "Done."
}

function commit_rerere_cache
{
	echo -n "Updating rerere cache... "

	cd $DIM_PREFIX/drm-rerere/
	if git_is_current_branch rerere-cache ; then
		remote=$(branch_to_remote rerere-cache)

		if ! git pull -q ; then
			echoerr "Failed to update the rerere cache."
			echoerr "Please manually run"
			echoerr "	$ cd $DIM_PREFIX/drm-rerere ; git pull"
			echoerr "and fixup any issues."

			return 1
		fi
		git add ./*.patch >& /dev/null || true
		for file  in $(git ls-files -- rr-cache); do
			if ! git log --since="60 days ago" --name-only -- $file | grep $file &> /dev/null; then
				git rm $file &> /dev/null || true
		find rr-cache/ -mtime -1 -type f -not -name "thisimage*" -print0 | xargs -0 git add > /dev/null || true
		git rm rr-cache/rr-cache &> /dev/null || true
		if git commit -m "$time: $integration_branch rerere cache update" >& /dev/null; then
			echo -n "New commit. "
		else
			echo -n "Nothing changed. "
		fi
		echo -n "Pushing rerere cache... "
		git push $DRY_RUN $remote HEAD >& /dev/null && echo "Done."
	else
		echo "Fail: Branch setup for the rerere-cache is borked."
		exit 1
	fi
function dim_rebuild_tip
Simona Vetter's avatar
Simona Vetter committed
{
	local integration_branch specfile time first rerere repo remote
Simona Vetter's avatar
Simona Vetter committed

	integration_branch=drm-tip
	specfile=$(mktemp)
	time="$(date --utc +%Yy-%mm-%dd-%Hh-%Mm-%Ss) UTC"
	first=1

	rerere=$DIM_PREFIX/drm-rerere
	if git status --porcelain | grep -q -v "^[ ?][ ?]"; then
		warn_or_fail "integration configuration file $integration_config not commited"
	update_rerere_cache
	echo -n "Reloading $integration_config... "
	echo "Done."
	cd $DIM_PREFIX/$integration_branch
	if ! git_is_current_branch $integration_branch ; then
		echo "Branch setup for the integration repo is borked"
		exit 1
	fi

	# rerere uses sha1 of the diff to identify conflicts, we must ensure
	# that they look the same for everyone
	git config merge.conflictstyle merge

	for repo in "${!drm_tip_repos[@]}"; do
		remote=$(repo_to_remote $repo)
		echo -n "Fetching $repo (local remote $remote)... "
Simona Vetter's avatar
Simona Vetter committed
		git_fetch_helper $remote
Simona Vetter's avatar
Simona Vetter committed
	# merge -fixes
	for conf in "${drm_tip_config[@]}"; do
		local branch override sha1 fixup_file

Jani Nikula's avatar
Jani Nikula committed
		read -r repo branch override <<< $conf
		remote=$(repo_to_remote $repo)
		echo -n "Merging $repo (local remote $remote) $branch... "
		if [[ -n "$override" ]]; then
			sha1=$override
			echo -n "Using override sha1: $sha1... "
Simona Vetter's avatar
Simona Vetter committed
		if [ $first == 1 ] ; then
			git reset --hard $sha1 &> /dev/null
			echo "Reset. Done."
Simona Vetter's avatar
Simona Vetter committed
			first=0
		elif git merge --rerere-autoupdate --ff-only $sha1 >& /dev/null ; then
			# nothing to do if just fast-forward
			echo "Fast-forward. Done."
Simona Vetter's avatar
Simona Vetter committed
		else
			fixup_file=$rerere/$repo-${branch//\//-}-fixup.patch
Simona Vetter's avatar
Simona Vetter committed
			echo $fixup_file > .fixup_file_path

			git merge --rerere-autoupdate --no-commit $sha1 >& /dev/null || true
			# normalize conflict markers
			if git grep -l '^>>>>>>> ' &> /dev/null ; then
				git grep -l '^>>>>>>> ' | xargs sed -e "s|^>>>>>>> .*$|>>>>>>> $repo\/$branch|" -i
Simona Vetter's avatar
Simona Vetter committed
			if [ -f $fixup_file ] ; then
				echo -n "Applying manual fixup patch for $integration_branch merge... "
Simona Vetter's avatar
Simona Vetter committed
				patch -p1 -i $fixup_file
Simona Vetter's avatar
Simona Vetter committed
			fi
			check_conflicts "$repo/$branch"
Simona Vetter's avatar
Simona Vetter committed
			git add -u

			# because we filter out fast-forward merges there will
			# always be something to commit
			git commit --no-edit --quiet
			echo "Done."
Simona Vetter's avatar
Simona Vetter committed
		fi

		echo -e "$repo $branch $(git rev-parse $sha1)\n\t$(git log -1 $sha1 --pretty=format:%s)" >> $specfile
Simona Vetter's avatar
Simona Vetter committed

		$INTERACTIVE
Simona Vetter's avatar
Simona Vetter committed
	done

	echo -n "Adding integration manifest $integration_branch: $time... "
Simona Vetter's avatar
Simona Vetter committed
	mv $specfile integration-manifest
	git add integration-manifest
	git commit --quiet -m "$integration_branch: $time integration manifest"
	echo "Done."
Simona Vetter's avatar
Simona Vetter committed

	remote=$(repo_to_remote drm-tip)
	echo -n "Pushing $integration_branch... "
	git push $DRY_RUN $remote +HEAD >& /dev/null && echo "Done."
Simona Vetter's avatar
Simona Vetter committed

	commit_rerere_cache
Simona Vetter's avatar
Simona Vetter committed
}

# additional patch checks before pushing, e.g. for r-b tags
function checkpatch_commit_push
{
	local sha1

	sha1=$1

	# use real names for people with many different email addresses
	author=$(git show -s $sha1 --format="format:%an")
	committer=$(git show -s $sha1 --format="format:%cn")
	# outlook mangles mails into "Last, First"
	author_outlook=$(git show -s $sha1 --format="format:%an" | sed -e 's/\([^ ]*\) \(.*\)/\2, \1/')
	if ! git show -s $sha1 | grep -qi "S.*-by:.*\\($author\\|$author_outlook\\)" ; then
		warn_or_fail "$sha1 is lacking author of sign-off"
	fi

	# check for committer sign-off
	if ! git show -s $sha1 | grep -qi "S.*-by:.*$committer"  ; then
		warn_or_fail "$sha1 is lacking committer of sign-off"
	fi

	# check for Link tag
	if ! git show -s $sha1 | grep -qi 'Link:'  ; then
		warn_or_fail "$sha1 is lacking of link tag"
	fi

	# check for a-b/r-b tag
	if git show -s $sha1 | grep -qi '\(reviewed\|acked\)\S*-by:'  ; then
		return
	fi

	# check for committer != author
Jani Nikula's avatar
Jani Nikula committed
	if [[ "$committer" != "$author" ]]; then
		return
	fi

	warn_or_fail "$sha1 is lacking mandatory review"
}

# push branch $1, rebuild drm-tip. the rest of the arguments are passed to git
function dim_push_branch
	local branch remote committer_email
	remote=$(branch_to_remote $branch)
	committer_email=$(git_committer_email)

Jani Nikula's avatar
Jani Nikula committed
	for sha1 in $(git rev-list "$branch@{u}..$branch" --committer="$committer_email" --no-merges) ; do
		checkpatch_commit_push $sha1
	done

	git push $DRY_RUN $remote $branch "$@"
	update_linux_next $branch drm-intel-next-queued drm-intel-next-fixes drm-intel-fixes
	update_linux_next $branch drm-misc-next drm-misc-next-fixes drm-misc-fixes
Simona Vetter's avatar
Simona Vetter committed
	update_linux_next $branch drm-amd-next drm-amd-next-fixes drm-amd-fixes
	dim_rebuild_tip
Jani Nikula's avatar
Jani Nikula committed
dim_alias_pq=push-queued
function dim_push_queued
{
	dim_push_branch drm-intel-next-queued "$@"
}

dim_alias_pnf=push-next-fixes
function dim_push_next_fixes
{
	dim_push_branch drm-intel-next-fixes "$@"
}

dim_alias_pf=push-fixes
function dim_push_fixes
{
	dim_push_branch drm-intel-fixes "$@"
}

function dim_push
{
	dim_push_branch $(git_current_branch) "$@"
}

function apply_patch #patch_file
	local patch message_id committer_email patch_from sob rv
	message_id=$(message_get_id $patch)
	committer_email=$(git_committer_email)
	patch_from=$(grep "From:" "$patch" | head -1)
	if [[ "$patch_from" != *"$committer_email"* ]] ; then
	git am --scissors -3 $sob "$@" $patch
	if [ -n "$message_id" ]; then
		dim_commit_add_tag "Link: https://patchwork.freedesktop.org/patch/msgid/$message_id"
		echoerr "WARNING: No message-id found in the patch file."
		rv=1
	if ! checkpatch_commit HEAD; then
		rv=1
	fi
	if ! check_maintainer $branch HEAD; then
		rv=1
	fi
	return $rv
}

# ensure we're on branch $1, and apply patches. the rest of the arguments are
# passed to git am.
dim_alias_ab=apply-branch
dim_alias_sob=apply-branch
function dim_apply_branch
{
	local branch file rv

	branch=${1:?$usage}
	shift
	file=$(mktemp)
	dir=$(mktemp -d)

	assert_branch $branch
	assert_repo_clean

	cat > $file
	git mailsplit -b -o$dir $file > /dev/null

	for patch in $dir/*; do
		if ! apply_patch $patch "$@"; then
			rv=1
		fi
	done
	rm -rf $file $dir
function dim_apply_pull
{
	local branch file message_id pull_branch rv

	branch=${1:?$usage}
	file=$(mktemp)

	assert_branch $branch
	assert_repo_clean

	cat > $file

	pull_branch=$(sed -e '0,/git repository at:$/d' $file | head -n 2 | tail -n 1)

	echo $pull_branch

	git pull $pull_branch

	message_id=$(message_get_id $file)

	git commit --amend -s --no-edit
	if [ -n "$message_id" ]; then
		dim_commit_add_tag "Link: https://patchwork.freedesktop.org/patch/msgid/$message_id"
	else
		echoerr "WARNING: No message-id found in the patch file."
		rv=1
	fi


	eval $DRY $DIM_POST_APPLY_ACTION
Simona Vetter's avatar
Simona Vetter committed
function dim_backmerge
{
	local branch upstream patch_file

	branch=${1:?$usage}
	upstream=${2:?$usage}

	cd $DIM_PREFIX/drm-tip
	tip_remote=$(repo_to_remote drm-tip)
Simona Vetter's avatar
Simona Vetter committed
	git fetch -q $tip_remote || true

	if ! git merge-base --is-ancestor $upstream $tip_remote/drm-tip ; then
		echoerr "Upstream $upstream not merged into drm-tip, aborting."
		echoerr "Please make sure any backmerge is tested in drm-tip,"
		echoerr "to give all the CI bots some time to find bugs."
		exit 1
	fi

	assert_branch $branch
	assert_repo_clean

	git merge --rerere-autoupdate --no-commit $upstream >& /dev/null || true

	if [[ -d .git ]]; then
		patch_file=".git"
	else
		patch_file=$(cut -d ' ' -f 2 .git)
	fi
	patch_file=$patch_file/MERGE_MSG


	cat > $patch_file <<-HERE
		Merge $upstream into $branch

		*** DETAILED BACKMERGE RATIONALE HERE ***
Simona Vetter's avatar
Simona Vetter committed

		HERE

	if git diff | grep -q '\(<<<<<<<\|=======\|>>>>>>>\||||||||\)' ; then
		echoerr "Conflicts found while merging $upstream into $branch."
		echoerr "This should only happen when git rerere gets confused"
		echoerr "or if there's a manual fixup patch in drm-rerere."
		echoerr "Please proceed with extreme caution."
		echoerr "Once the conflict is resolved, commit it with"
		echoerr "   git commit -a"
	fi

	git add -u
	git commit -s
}

function dim_add_link
{
	local branch file message_id

	shift
	file=$(mktemp)

	assert_branch $branch
	assert_repo_clean

	cat > $file

	message_id=$(message_get_id $file)

	rm -f $file

	if [[ -n "$message_id" ]]; then
		dim_commit_add_tag "Link: https://patchwork.freedesktop.org/patch/msgid/$message_id"
	else
		echoerr "No message-id found in the patch file."
	fi
}

function dim_add_link_queued
{
	dim_add_link drm-intel-next-queued "$@"
}

function dim_add_link_fixes