summaryrefslogtreecommitdiff
path: root/spice-server/rebase
blob: 23a52492fbc9312bf28cd29fa1c9c64addf5057a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/bin/bash

# script to help rebase trees of branches
# Git configuration
# -----------------
#   rebasepp.start-commit
#     Required.
#     Attemps to rebase all branches child of this commit.
#   rebasepp.rebase-to
#     Required.
#     Rebase the branches on this commit (usually origin/master)
#   rebasepp.remote
#     Optional.
#     Attempt to push to this remote if the upstream is set to it
#   rebasepp.filter
#     Optional.
#     "grep -v" filter applied to the branch names. Allows to
#     exclude some branches.
#   rebasepp.custom-script
#     Optional.
#     Script to source for customizations.
#
# Custom script
# -------------
# The script is sourced (shell). The current directory will be
# the git root.
# Environment passes
#   COMPILE
#     yes/no/full
#   REBASE_TO
#     rebasepp.rebase-to option
#
# You can define a post_process function that will be called
# if the rebase is successful.
# You can define a build_it function that will be called to build,
# this function is executed in a different process so any directory
# changes or other won't affect caller environment
# The name of the branch will be passed as first argument.

error() {
    echo "$*" >&2
    exit 1
}

# git remove where to push our branches
REMOTE_PUSH="$(git config rebasepp.remote)"
FILTER="$(git config rebasepp.filter)"
CUSTOM_SCRIPT="$(git config rebasepp.custom-script)"

set -e
REBASE_TO="$(git config rebasepp.rebase-to)" || error "rebase-to not configured"
START_COMMIT="$(git config rebasepp.start-commit)" || error "start-commit not configured"

export REBASE_TO

cd "$(git rev-parse --show-toplevel)"

if [ -n "$FILTER" ]; then
    filter() {
        exec grep -v "$FILTER"
    }
else
    filter() {
        cat
    }
fi

post_process() { :; }

build_it() {
    make -j5
}

if [ -n "$CUSTOM_SCRIPT" ]; then
    test -r "$CUSTOM_SCRIPT" || error "Cannot read $CUSTOM_SCRIPT"
    source "$CUSTOM_SCRIPT"
fi

get_id() {
    git rev-parse --revs-only "refs/$1" --
}

COMPILE=${COMPILE:=no}
export COMPILE
case $COMPILE in
yes | full | no )
	;;
* )
	error "$COMPILE option not supported"
	;;
esac
failed=''
failed_compile=''
processed=''

declare -A commits

try_compile() {
    local last_failed=''
    if test "$COMPILE" = "no"; then
        return
    fi
    echo "processed:$processed"
    echo "failed:$failed_compile"
    echo "compiling $branch ..."
    if test $COMPILE = full; then
        for commit in $(git rev-list ${REBASE_TO}..$branch --reverse); do
            echo "checking branch $branch commit $commit"
            git checkout $commit &> /dev/null
            if [ "${commits[$commit]}" = "" ]; then
                if ! (build_it) &> compile_errtmp.txt; then
                    mv -f compile_errtmp.txt compile_err_$branch.txt
                    commits[$commit]='no'
                else
                    rm -f compile_errtmp.txt
                    commits[$commit]='yes'
                fi
            fi
            if [ "${commits[$commit]}" = "no" ]; then
                subject="$(git log -1 --pretty=%s $commit)"
                failed_compile+="
    $branch:$commit $subject"
                last_failed='+'
            else
                last_failed=''
            fi
        done
        failed_compile+="$last_failed"
    else
        if ! (build_it) &> compile_errtmp.txt; then
            mv -f compile_errtmp.txt compile_err_$branch.txt
            failed_compile+="
    $branch"
        else
            rm -f compile_errtmp.txt
        fi
    fi
}

all_branches() {
    git show-ref --heads | perl -ne 'print $1 if m, refs/heads/(.*)$,s'
}

# get remote based on branch
branch_get_remote() {
    local branch="$1"
    {
        git config "branch.${branch}.pushRemote" || \
        git config "remote.pushDefault" || \
        git config "branch.${branch}.remote";
    } 2> /dev/null
}

branch_need_push() {
    local branch="$1" remote
    if [ -n "$REMOTE_PUSH" ]; then
        # check that the upstream for this branch is our specified remote
        remote=$(branch_get_remote "$branch") && [ "$REMOTE_PUSH" = "$remote" ] && {
            remote=$(get_id "remotes/$REMOTE_PUSH/$branch" 2> /dev/null) && {
                if [ "$remote" != "" -a "$(get_id heads/$branch)" != "$remote" ]; then
                    return 0
                fi
            }
        }
    fi
    return 1
}

for branch in $(git branch --contains "$START_COMMIT" --no-color | \
                sed 's,^..,,' | filter | LANG=C sort)
do
    # exclude invalid branches (ie when we checked out a commit id)
    if ! get_id "heads/$branch" &> /dev/null; then
        continue
    fi

    # check if already in sync (so no need to checkout)
    if ! branch_need_push "$branch" && test "$COMPILE" = no -a "$(git rev-list "heads/$branch..${REBASE_TO}" | wc -l)" = 0; then
        processed+=" $branch"
        continue
    fi

    # try to rebase on top of specified branch
    git checkout "$branch"
    if git rebase ${REBASE_TO}; then
        post_process "$branch"
        # if there is a remote on the git remote specified push to it
        if branch_need_push "$branch"; then
            echo "Pushing branch $branch ..."
            git push -f
        fi
        try_compile
    else
        failed+=" $branch"
        git rebase --abort
    fi
    processed+=" $branch"
done

if [ "$failed_compile" != "" ]; then
    echo "FAILED TO COMPILE:$failed_compile"
fi

if [ "$failed" != "" ]; then
    echo "FAILED BRANCHES:$failed"
    exit 1
else
    echo "All branches are in sync"
fi