]> git.zndr.dk Git - dotfiles.git/commitdiff
Add cygwin batch and other script files
authorJannik ZANDER <jannikz@gmail.com>
Sun, 1 May 2016 07:59:49 +0000 (09:59 +0200)
committerJannik Zander <jannikz@Janniks-MBP.opasia.dk>
Mon, 2 May 2016 19:34:32 +0000 (21:34 +0200)
31 files changed:
bat/cyg_batch.bat [new file with mode: 0644]
bat/git_add.bat [new file with mode: 0644]
bat/git_bd.bat [new file with mode: 0644]
bat/git_blame.bat [new file with mode: 0644]
bat/git_br.bat [new file with mode: 0644]
bat/git_clean.bat [new file with mode: 0644]
bat/git_co.bat [new file with mode: 0644]
bat/git_co_file_head.bat [new file with mode: 0644]
bat/git_com.bat [new file with mode: 0644]
bat/git_commit_amend.bat [new file with mode: 0644]
bat/git_difftool.bat [new file with mode: 0644]
bat/git_difftool_headhat.bat [new file with mode: 0644]
bat/git_logp.bat [new file with mode: 0644]
bat/git_lola.bat [new file with mode: 0644]
bat/git_rebase.bat [new file with mode: 0644]
bat/git_reset.bat [new file with mode: 0644]
bat/git_reset_file_head.bat [new file with mode: 0644]
bat/git_review_diffpatch.bat [new file with mode: 0644]
bat/git_review_download.bat [new file with mode: 0644]
bat/git_review_finish.bat [new file with mode: 0644]
bat/git_review_list.bat [new file with mode: 0644]
bat/git_review_pushchange.bat [new file with mode: 0644]
bat/git_stat.bat [new file with mode: 0644]
bat/gitk.bat [new file with mode: 0644]
bat/sync_gitcache.bat [new file with mode: 0644]
bin/git-diffall.sh [new file with mode: 0755]
bin/git-difftool.sh [new file with mode: 0755]
bin/git-editor.sh [new file with mode: 0755]
bin/git-mergetool.sh [new file with mode: 0755]
bin/git-proxy.sh [new file with mode: 0755]
bin/git-review [new file with mode: 0755]

diff --git a/bat/cyg_batch.bat b/bat/cyg_batch.bat
new file mode 100644 (file)
index 0000000..475cbc9
--- /dev/null
@@ -0,0 +1,7 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+set CYGWIN=mintty\r
+start cmd /c C:\cygwin\bin\bash.exe --login\r
+\r
diff --git a/bat/git_add.bat b/bat/git_add.bat
new file mode 100644 (file)
index 0000000..570f48a
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git add %2"\r
+\r
diff --git a/bat/git_bd.bat b/bat/git_bd.bat
new file mode 100644 (file)
index 0000000..690a944
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git brd %2"\r
+\r
diff --git a/bat/git_blame.bat b/bat/git_blame.bat
new file mode 100644 (file)
index 0000000..082e627
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git blame %2"\r
+\r
diff --git a/bat/git_br.bat b/bat/git_br.bat
new file mode 100644 (file)
index 0000000..1517259
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git branch"\r
+\r
diff --git a/bat/git_clean.bat b/bat/git_clean.bat
new file mode 100644 (file)
index 0000000..e6663ec
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git clean -f -d"\r
+\r
diff --git a/bat/git_co.bat b/bat/git_co.bat
new file mode 100644 (file)
index 0000000..fec4ab0
--- /dev/null
@@ -0,0 +1,13 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+IF %3 == 1 GOTO CREATE\r
+C:\cygwin\bin\bash.exe --login -c "git co %2"\r
+GOTO END\r
+\r
+:CREATE\r
+C:\cygwin\bin\bash.exe --login -c "git co -b %2"\r
+\r
+:END\r
+\r
diff --git a/bat/git_co_file_head.bat b/bat/git_co_file_head.bat
new file mode 100644 (file)
index 0000000..3a4805d
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git co HEAD -- %2"\r
+\r
diff --git a/bat/git_com.bat b/bat/git_com.bat
new file mode 100644 (file)
index 0000000..85d1a1f
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git commit"\r
+\r
diff --git a/bat/git_commit_amend.bat b/bat/git_commit_amend.bat
new file mode 100644 (file)
index 0000000..a959903
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git commit --amend"\r
+\r
diff --git a/bat/git_difftool.bat b/bat/git_difftool.bat
new file mode 100644 (file)
index 0000000..8ef72d1
--- /dev/null
@@ -0,0 +1,21 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+\r
+IF NOT "%2"=="" GOTO P1\r
+C:\cygwin\bin\bash.exe --login -i -c "git diffall"\r
+GOTO END\r
+\r
+:P1\r
+IF NOT "%3"=="" GOTO P2\r
+C:\cygwin\bin\bash.exe --login -i -c "git diffall %2"\r
+GOTO END\r
+\r
+:P2\r
+C:\cygwin\bin\bash.exe --login -i -c "git diffall %2 %3"\r
+\r
+:END\r
+\r
+\r
+\r
diff --git a/bat/git_difftool_headhat.bat b/bat/git_difftool_headhat.bat
new file mode 100644 (file)
index 0000000..ad72336
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git diffall HEAD^"\r
+\r
diff --git a/bat/git_logp.bat b/bat/git_logp.bat
new file mode 100644 (file)
index 0000000..67ed2f5
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git log -p -1 %2"\r
+\r
diff --git a/bat/git_lola.bat b/bat/git_lola.bat
new file mode 100644 (file)
index 0000000..fb0d7fd
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git lola"\r
+\r
diff --git a/bat/git_rebase.bat b/bat/git_rebase.bat
new file mode 100644 (file)
index 0000000..95a7923
--- /dev/null
@@ -0,0 +1,14 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+IF %3 == 1 GOTO INTERACTIVE\r
+C:\cygwin\bin\bash.exe --login -i -c "git rebase refs/tags/ste-m74x0_%2"\r
+C:\cygwin\bin\bash.exe --login -i -c "git mergetool -y"\r
+C:\cygwin\bin\bash.exe --login -i -c "git rebase --continue"\r
+GOTO END\r
+\r
+:INTERACTIVE\r
+C:\cygwin\bin\bash.exe --login -i -c "git rebase -i %2"\r
+\r
+:END
\ No newline at end of file
diff --git a/bat/git_reset.bat b/bat/git_reset.bat
new file mode 100644 (file)
index 0000000..fad93db
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git reset --hard"\r
+\r
diff --git a/bat/git_reset_file_head.bat b/bat/git_reset_file_head.bat
new file mode 100644 (file)
index 0000000..f462b53
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git reset HEAD -- %2"\r
+\r
diff --git a/bat/git_review_diffpatch.bat b/bat/git_review_diffpatch.bat
new file mode 100644 (file)
index 0000000..7f3e323
--- /dev/null
@@ -0,0 +1,13 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+IF "%4"=="" GOTO LATEST\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -R -m %2,%3-%4"\r
+\r
+GOTO END\r
+\r
+:LATEST\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -R -m %2,%3"\r
+\r
+:END\r
diff --git a/bat/git_review_download.bat b/bat/git_review_download.bat
new file mode 100644 (file)
index 0000000..9cdec36
--- /dev/null
@@ -0,0 +1,15 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+IF NOT "%3"=="" GOTO CUSTOMNAME\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -d %2"\r
+GOTO END\r
+\r
+:CUSTOMNAME\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -b %3 -d %2"\r
+\r
+:END\r
+\r
+\r
+\r
diff --git a/bat/git_review_finish.bat b/bat/git_review_finish.bat
new file mode 100644 (file)
index 0000000..0a5c844
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -f"\r
+\r
diff --git a/bat/git_review_list.bat b/bat/git_review_list.bat
new file mode 100644 (file)
index 0000000..f613e0c
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -B -l"\r
+\r
diff --git a/bat/git_review_pushchange.bat b/bat/git_review_pushchange.bat
new file mode 100644 (file)
index 0000000..ee3fdb4
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "git review -c -p"\r
+\r
diff --git a/bat/git_stat.bat b/bat/git_stat.bat
new file mode 100644 (file)
index 0000000..e7c25be
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -c "git status"\r
+\r
diff --git a/bat/gitk.bat b/bat/gitk.bat
new file mode 100644 (file)
index 0000000..0fd3c49
--- /dev/null
@@ -0,0 +1,6 @@
+@echo off\r
+\r
+cd %1\r
+set CHERE_INVOKING=1\r
+C:\cygwin\bin\bash.exe --login -i -c "gitk %2"\r
+\r
diff --git a/bat/sync_gitcache.bat b/bat/sync_gitcache.bat
new file mode 100644 (file)
index 0000000..cddc8ce
--- /dev/null
@@ -0,0 +1,2 @@
+rem Cache in ~/gitcache\r
+C:\cygwin\bin\bash.exe --login -i -c "cd ~/gitcache; repo sync"\r
diff --git a/bin/git-diffall.sh b/bin/git-diffall.sh
new file mode 100755 (executable)
index 0000000..2ae11ea
--- /dev/null
@@ -0,0 +1,277 @@
+#!/bin/sh
+# Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com>
+#
+# 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 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.
+
+
+# Perform a directory diff between commits in the repository using
+# the external diff or merge tool specified in the user's config.
+
+USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
+
+    --cached     Compare to the index rather than the working tree.
+
+    --copy-back  Copy files back to the working tree when the diff
+                 tool exits (in case they were modified by the
+                 user).  This option is only valid if the diff
+                 compared with the working tree.
+
+    -x=<command>
+    --extcmd=<command>  Specify a custom command for viewing diffs.
+                 git-diffall ignores the configured defaults and
+                 runs $command $LOCAL $REMOTE when this option is
+                 specified. Additionally, $BASE is set in the
+                 environment.
+'
+
+SUBDIRECTORY_OK=1
+. "$(git --exec-path)/git-sh-setup"
+
+TOOL_MODE=diff
+. "$(git --exec-path)/git-mergetool--lib"
+
+merge_tool="$(get_merge_tool)"
+if test -z "$merge_tool"
+then
+                    echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
+                    usage
+fi
+
+start_dir=$(pwd)
+
+# All the file paths returned by the diff command are relative to the root
+# of the working copy. So if the script is called from a subdirectory, it
+# must switch to the root of working copy before trying to use those paths.
+cdup=$(git rev-parse --show-cdup) &&
+cd "$cdup" || {
+                    echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+                    exit 1
+}
+
+# set up temp dir
+tmp=$(perl -e 'use File::Temp qw(tempdir);
+                    $t=tempdir("/tmp/git-diffall.XXXXX") or exit(1);
+                    print $t') || exit 1
+#trap 'rm -rf "$tmp"' EXIT
+
+left=
+right=
+paths=
+dashdash_seen=
+compare_staged=
+merge_base=
+left_dir=
+right_dir=
+diff_tool=
+copy_back=
+
+while test $# != 0
+do
+                    case "$1" in
+                    -h|--h|--he|--hel|--help)
+                                        usage
+                                        ;;
+                    --cached)
+                                        compare_staged=1
+                                        ;;
+                    --copy-back)
+                                        copy_back=1
+                                        ;;
+                    -x|--e|--ex|--ext|--extc|--extcm|--extcmd)
+                                        if test $# = 1
+                                        then
+                                                            echo You must specify the tool for use with --extcmd
+                                                            usage
+                                        else
+                                                            diff_tool=$2
+                                                            shift
+                                        fi
+                                        ;;
+                    --)
+                                        dashdash_seen=1
+                                        ;;
+                    -*)
+                                        echo Invalid option: "$1"
+                                        usage
+                                        ;;
+                    *)
+                                        # could be commit, commit range or path limiter
+                                        case "$1" in
+                                        *...*)
+                                                            left=${1%...*}
+                                                            right=${1#*...}
+                                                            merge_base=1
+                                                            ;;
+                                        *..*)
+                                                            left=${1%..*}
+                                                            right=${1#*..}
+                                                            ;;
+                                        *)
+                                                            if test -n "$dashdash_seen"
+                                                            then
+                                                                                paths="$paths$1 "
+                                                            elif test -z "$left"
+                                                            then
+                                                                                left=$1
+                                                            elif test -z "$right"
+                                                            then
+                                                                                right=$1
+                                                            else
+                                                                                paths="$paths$1 "
+                                                            fi
+                                                            ;;
+                                        esac
+                                        ;;
+                    esac
+                    shift
+done
+
+# Determine the set of files which changed
+if test -n "$left" && test -n "$right"
+then
+                    left_dir="cmt-$(git rev-parse --short $left)"
+                    right_dir="cmt-$(git rev-parse --short $right)"
+
+                    if test -n "$compare_staged"
+                    then
+                                        usage
+                    elif test -n "$merge_base"
+                    then
+                                        git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist"
+                    else
+                                        git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
+                    fi
+elif test -n "$left"
+then
+                    left_dir="cmt-$(git rev-parse --short $left)"
+
+                    if test -n "$compare_staged"
+                    then
+                                        right_dir="staged"
+                                        git diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
+                    else
+                                        right_dir="working_tree"
+                                        git diff --name-only "$left" -- $paths >"$tmp/filelist"
+                    fi
+else
+                    left_dir="HEAD"
+
+                    if test -n "$compare_staged"
+                    then
+                                        right_dir="staged"
+                                        git diff --name-only --cached -- $paths >"$tmp/filelist"
+                    else
+                                        right_dir="working_tree"
+                                        git diff --name-only -- $paths >"$tmp/filelist"
+                    fi
+fi
+
+# Exit immediately if there are no diffs
+if test ! -s "$tmp/filelist"
+then
+                    exit 0
+fi
+
+if test -n "$copy_back" && test "$right_dir" != "working_tree"
+then
+                    echo "--copy-back is only valid when diff includes the working tree."
+                    exit 1
+fi
+
+# Create the named tmp directories that will hold the files to be compared
+mkdir -p "$tmp/$left_dir" "$tmp/$right_dir"
+
+# Populate the tmp/right_dir directory with the files to be compared
+while read name
+do
+                    if test -n "$right"
+                    then
+                                        ls_list=$(git ls-tree $right "$name")
+                                        if test -n "$ls_list"
+                                        then
+                                                            mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+                                                            git show "$right":"$name" >"$tmp/$right_dir/$name" || true
+                                        fi
+                    elif test -n "$compare_staged"
+                    then
+                                        ls_list=$(git ls-files -- "$name")
+                                        if test -n "$ls_list"
+                                        then
+                                                            mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+                                                            git show :"$name" >"$tmp/$right_dir/$name"
+                                        fi
+                    else
+                                        if test -e "$name"
+                                        then
+                                                            mkdir -p "$tmp/$right_dir/$(dirname "$name")"
+                                                            cp "$name" "$tmp/$right_dir/$name"
+                                        fi
+                    fi
+done < "$tmp/filelist"
+
+# Populate the tmp/left_dir directory with the files to be compared
+while read name
+do
+                    if test -n "$left"
+                    then
+                                        ls_list=$(git ls-tree $left "$name")
+                                        if test -n "$ls_list"
+                                        then
+                                                            mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+                                                            git show "$left":"$name" >"$tmp/$left_dir/$name" || true
+                                        fi
+                    else
+                                        if test -n "$compare_staged"
+                                        then
+                                                            ls_list=$(git ls-tree HEAD "$name")
+                                                            if test -n "$ls_list"
+                                                            then
+                                                                                mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+                                                                                git show HEAD:"$name" >"$tmp/$left_dir/$name"
+                                                            fi
+                                        else
+                                                            mkdir -p "$tmp/$left_dir/$(dirname "$name")"
+                                                            git show :"$name" >"$tmp/$left_dir/$name"
+                                        fi
+                    fi
+done < "$tmp/filelist"
+
+LOCAL="$tmp/$left_dir"
+REMOTE="$tmp/$right_dir"
+
+if test -n "$diff_tool"
+then
+                    export BASE
+                    eval $diff_tool '"$LOCAL"' '"$REMOTE"'
+else
+                    run_merge_tool "$merge_tool" false
+fi
+
+# Copy files back to the working dir, if requested
+if test -n "$copy_back" && test "$right_dir" = "working_tree"
+then
+                    cd "$start_dir"
+                    git_top_dir=$(git rev-parse --show-toplevel)
+                    find "$tmp/$right_dir" -type f |
+                    while read file
+                    do
+                                        cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
+                    done
+fi
\ No newline at end of file
diff --git a/bin/git-difftool.sh b/bin/git-difftool.sh
new file mode 100755 (executable)
index 0000000..ea69a60
--- /dev/null
@@ -0,0 +1,4 @@
+TOOL=$HOME/bin/vimdiff
+ARG=$@
+
+$TOOL $ARG
diff --git a/bin/git-editor.sh b/bin/git-editor.sh
new file mode 100755 (executable)
index 0000000..d5afa9c
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+if [[ -f $HOME/usr/bin/vim ]]; then
+  TOOL="${HOME}/usr/bin/vim"
+  ARG=$@
+elif [[ -f /usr/bin/vim ]]; then
+  TOOL="/usr/bin/vim"
+  ARG=$@
+fi
+
+$TOOL $ARG
diff --git a/bin/git-mergetool.sh b/bin/git-mergetool.sh
new file mode 100755 (executable)
index 0000000..576c19f
--- /dev/null
@@ -0,0 +1,16 @@
+#! /bin/bash
+if [[ -f $HOME/bin/bcompare ]]; then
+  TOOL="${HOME}/bin/bcompare"
+  ARG="$(cygpath -w $1) $(cygpath -w $2) $(cygpath -w $3) $(cygpath -w $4)"
+elif [[ -f /sw/stericsson/lud_tools/bcompare/3.3.5.15075/rh5/bin/bcompare ]]; then
+  TOOL=/sw/stericsson/lud_tools/bcompare/3.3.5.15075/rh5/bin/bcompare
+  ARG=$@
+elif [[ -f $HOME/usr/bin/vimdiff ]]; then
+  TOOL="${HOME}/usr/bin/vimdiff"
+  ARG=$@
+elif [[ -f /usr/bin/vimdiff ]]; then
+  TOOL="/usr/bin/vimdiff"
+  ARG=$@
+fi
+
+$TOOL $ARG
diff --git a/bin/git-proxy.sh b/bin/git-proxy.sh
new file mode 100755 (executable)
index 0000000..5878c22
--- /dev/null
@@ -0,0 +1,5 @@
+ #!/bin/sh
+exec connect-proxy -5 -R remote -S www-proxy.ericsson.se:3132 $*
+
+
+
diff --git a/bin/git-review b/bin/git-review
new file mode 100755 (executable)
index 0000000..9c1ba04
--- /dev/null
@@ -0,0 +1,1219 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+COPYRIGHT = """\
+Copyright (C) 2011-2012 OpenStack LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied.
+
+See the License for the specific language governing permissions and
+limitations under the License."""
+
+import datetime
+import json
+import os
+import re
+import shlex
+import subprocess
+import sys
+import time
+
+if sys.version < '3':
+    import ConfigParser
+    import urllib
+    import urlparse
+    urlopen = urllib.urlopen
+    urlparse = urlparse.urlparse
+    do_input = raw_input
+else:
+    import configparser as ConfigParser
+    import urllib.parse
+    import urllib.request
+    urlopen = urllib.request.urlopen
+    urlparse = urllib.parse.urlparse
+    do_input = input
+
+from distutils import version as du_version
+
+version = "1.22"
+
+VERBOSE = False
+UPDATE = False
+CONFIGDIR = os.path.expanduser("~/.config/git-review")
+GLOBAL_CONFIG = "/etc/git-review/git-review.conf"
+USER_CONFIG = os.path.join(CONFIGDIR, "git-review.conf")
+PYPI_URL = "http://pypi.python.org/pypi/git-review/json"
+PYPI_CACHE_TIME = 60 * 60 * 24  # 24 hours
+DEFAULTS = dict(hostname='gerrit.lud.stericsson.com', port='29418', project=False,
+                defaultbranch='master', defaultremote="gerrit",
+                defaultrebase="0")
+
+_branch_name = None
+_has_color = None
+_no_color_support = False
+
+
+class colors:
+    yellow = '\033[33m'
+    green = '\033[92m'
+    reset = '\033[0m'
+
+
+class GitReviewException(Exception):
+    pass
+
+
+class CommandFailed(GitReviewException):
+
+    def __init__(self, *args):
+        Exception.__init__(self, *args)
+        (self.rc, self.output, self.argv, self.envp) = args
+        self.quickmsg = dict([
+            ("argv", " ".join(self.argv)),
+            ("rc", self.rc),
+            ("output", self.output)])
+
+    def __str__(self):
+        return self.__doc__ + """
+The following command failed with exit code %(rc)d
+    "%(argv)s"
+-----------------------
+%(output)s
+-----------------------""" % self.quickmsg
+
+
+class ChangeSetException(GitReviewException):
+
+    def __init__(self, e):
+        GitReviewException.__init__(self)
+        self.e = str(e)
+
+    def __str__(self):
+        return self.__doc__ % self.e
+
+
+def parse_review_number(review):
+    parts = review.split(',')
+    if len(parts) < 2:
+        parts.append(None)
+    return parts
+
+
+def build_review_number(review, patchset):
+    if patchset is not None:
+        return '%s,%s' % (review, patchset)
+    return review
+
+
+def run_command_status(*argv, **env):
+    if VERBOSE:
+        print(datetime.datetime.now(), "Running:", " ".join(argv))
+    if len(argv) == 1:
+        argv = shlex.split(str(argv[0]))
+    newenv = os.environ
+    newenv.update(env)
+    p = subprocess.Popen(argv, stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT, env=newenv)
+    (out, nothing) = p.communicate()
+    out = out.decode('utf-8')
+    return (p.returncode, out.strip())
+
+
+def run_command(*argv, **env):
+    (rc, output) = run_command_status(*argv, **env)
+    return output
+
+
+def run_command_exc(klazz, *argv, **env):
+    """Run command *argv, on failure raise 'klazz
+
+    klass should be derived from CommandFailed
+    """
+    (rc, output) = run_command_status(*argv, **env)
+    if rc != 0:
+        raise klazz(rc, output, argv, env)
+    return output
+
+
+def update_latest_version(version_file_path):
+    """Cache the latest version of git-review for the upgrade check."""
+
+    if not os.path.exists(CONFIGDIR):
+        os.makedirs(CONFIGDIR)
+
+    if os.path.exists(version_file_path) and not UPDATE:
+        if (time.time() - os.path.getmtime(version_file_path)) < 28800:
+            return
+
+    latest_version = version
+    try:
+        latest_version = json.load(urlopen(PYPI_URL))['info']['version']
+    except Exception:
+        pass
+
+    with open(version_file_path, "w") as version_file:
+        version_file.write(latest_version)
+
+
+def latest_is_newer():
+    """Check if there is a new version of git-review."""
+
+    # Skip version check if distro package turns it off
+    if os.path.exists(GLOBAL_CONFIG):
+        config = dict(check=False)
+        configParser = ConfigParser.ConfigParser(config)
+        configParser.read(GLOBAL_CONFIG)
+        if not configParser.getboolean("updates", "check"):
+            return False
+
+    version_file_path = os.path.join(CONFIGDIR, "latest-version")
+    update_latest_version(version_file_path)
+
+    latest_version = None
+    with open(version_file_path, "r") as version_file:
+        latest_version = du_version.StrictVersion(version_file.read())
+    if latest_version > du_version.StrictVersion(version):
+        return True
+    return False
+
+
+def git_directories():
+    """Determine (absolute git work directory path, .git subdirectory path)."""
+    cmd = ("git", "rev-parse", "--show-toplevel", "--git-dir")
+    out = run_command_exc(GitDirectoriesException, *cmd)
+    try:
+        return out.split()
+    except ValueError:
+        raise GitDirectoriesException(0, out, cmd, {})
+
+
+class GitDirectoriesException(CommandFailed):
+    "Cannot determine where .git directory is."
+    EXIT_CODE = 70
+
+
+class CustomScriptException(CommandFailed):
+    """Custom script execution failed."""
+    EXIT_CODE = 71
+
+
+def run_custom_script(action):
+    """Get status and output of .git/hooks/$action-review or/and
+    ~/.config/hooks/$action-review if existing.
+    """
+    returns = []
+    script_file = "%s-review" % (action)
+    (top_dir, git_dir) = git_directories()
+    paths = [os.path.join(CONFIGDIR, "hooks", script_file),
+             os.path.join(git_dir, "hooks", script_file)]
+    for fpath in paths:
+        if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
+            status, output = run_command_status(fpath)
+            returns.append((status, output, fpath))
+
+    for (status, output, path) in returns:
+        if status is not None and status != 0:
+            raise CustomScriptException(status, output, [path], {})
+        elif output and VERBOSE:
+            print("script %s output is:" % (path))
+            print(output)
+
+
+def git_config_get_value(section, option, default=None):
+    try:
+        return run_command_exc(GitConfigException,
+                               "git", "config",
+                               "--get",
+                               "%s.%s" % (section, option)).strip()
+    except GitConfigException as exc:
+        if exc.rc == 1:
+            return default
+        raise
+
+
+class GitConfigException(CommandFailed):
+    """Git config value retrieval failed."""
+    EXIT_CODE = 128
+
+
+class CannotInstallHook(CommandFailed):
+    "Problems encountered installing commit-msg hook"
+    EXIT_CODE = 2
+
+
+def set_hooks_commit_msg(remote, target_file):
+    """Install the commit message hook if needed."""
+
+    # Create the hooks directory if it's not there already
+    hooks_dir = os.path.dirname(target_file)
+    if not os.path.isdir(hooks_dir):
+        os.mkdir(hooks_dir)
+
+    (hostname, username, port, project_name) = \
+        parse_git_show(remote, "Push")
+
+    if not os.path.exists(target_file) or UPDATE:
+        if VERBOSE:
+            print("Fetching commit hook from: scp://%s:%s" % (hostname, port))
+        if port is not None:
+            port = "-P %s" % port
+        else:
+            port = ""
+        if username is None:
+            userhost = hostname
+        else:
+            userhost = "%s@%s" % (username, hostname)
+        run_command_exc(
+            CannotInstallHook,
+            "scp", port,
+            userhost + ":hooks/commit-msg",
+            target_file)
+
+    if not os.access(target_file, os.X_OK):
+        os.chmod(target_file, os.path.stat.S_IREAD | os.path.stat.S_IEXEC)
+
+
+def test_remote(username, hostname, port, project):
+    """Tests that a possible gerrit remote works."""
+
+    if port is not None:
+        port = "-p %s" % port
+    else:
+        port = ""
+    if username is None:
+        userhost = hostname
+    else:
+        userhost = "%s@%s" % (username, hostname)
+
+    (status, ssh_output) = run_command_status(
+        "ssh", "-x", port, userhost,
+        "gerrit", "ls-projects")
+
+    if status == 0:
+        if VERBOSE:
+            print("%s@%s:%s worked." % (username, hostname, port))
+        return True
+    else:
+        if VERBOSE:
+            print("%s@%s:%s did not work." % (username, hostname, port))
+        return False
+
+
+def make_remote_url(username, hostname, port, project):
+    """Builds a gerrit remote URL."""
+    if username is None:
+        return "ssh://%s:%s/%s" % (hostname, port, project)
+    else:
+        return "ssh://%s@%s:%s/%s" % (username, hostname, port, project)
+
+
+def add_remote(hostname, port, project, remote):
+    """Adds a gerrit remote."""
+    asked_for_username = False
+
+    username = os.getenv("USERNAME")
+    if not username:
+        username = git_config_get_value("gitreview", "username")
+    if not username:
+        username = os.getenv("USER")
+    if port is None:
+        port = 29418
+
+    remote_url = make_remote_url(username, hostname, port, project)
+    if VERBOSE:
+        print("No remote set, testing %s" % remote_url)
+    if not test_remote(username, hostname, port, project):
+        print("Could not connect to gerrit.")
+        username = do_input("Enter your gerrit username: ")
+        remote_url = make_remote_url(username, hostname, port, project)
+        print("Trying again with %s" % remote_url)
+        if not test_remote(username, hostname, port, project):
+            raise Exception("Could not connect to gerrit at %s" % remote_url)
+        asked_for_username = True
+
+    print("Creating a git remote called \"%s\" that maps to:" % remote)
+    print("\t%s" % remote_url)
+    cmd = "git remote add -f %s %s" % (remote, remote_url)
+    (status, remote_output) = run_command_status(cmd)
+
+    if status != 0:
+        raise Exception("Error running %s" % cmd)
+
+    if asked_for_username:
+        print()
+        print("This repository is now set up for use with git-review.")
+        print("You can set the default username for future repositories with:")
+        print('  git config --global --add gitreview.username "%s"' % username)
+        print()
+
+
+def parse_git_show(remote, verb):
+    fetch_url = ""
+    for line in run_command("git remote show -n %s" % remote).split("\n"):
+        if line.strip().startswith("%s" % verb):
+            fetch_url = line.split()[2]
+
+    parsed_url = urlparse(fetch_url)
+    project_name = parsed_url.path.lstrip("/")
+    if project_name.endswith(".git"):
+        project_name = project_name[:-4]
+
+    hostname = parsed_url.netloc
+    username = None
+    port = parsed_url.port
+
+    if VERBOSE:
+        print("Found origin %s URL:" % verb, fetch_url)
+
+    # Workaround bug in urlparse on OSX
+    if parsed_url.scheme == "ssh" and parsed_url.path[:2] == "//":
+        hostname = parsed_url.path[2:].split("/")[0]
+
+    if "@" in hostname:
+        (username, hostname) = hostname.split("@")
+    if ":" in hostname:
+        (hostname, port) = hostname.split(":")
+
+    # Is origin an ssh location? Let's pull more info
+    if parsed_url.scheme == "ssh" and port is None:
+        port = 22
+
+    return (hostname, username, str(port), project_name)
+
+
+def check_color_support():
+    global _has_color
+    global _no_color_support
+    if _has_color is None:
+        test_command = "git log --color=never --oneline HEAD^1..HEAD"
+        (status, output) = run_command_status(test_command)
+        if status == 0:
+            _has_color = True
+        else:
+            _has_color = False
+            
+    if _no_color_support:
+      _has_color = False
+
+    return _has_color
+
+
+def get_config(config_file=None):
+    """Generate the configuration map by starting with some built-in defaults
+    and then loading GLOBAL_CONFIG, USER_CONFIG, and a repository-specific
+    .gitreview file, if they exist. In case of conflict, the configuration file
+    with the narrowest scope wins.
+    """
+    config = DEFAULTS.copy()
+    for filename in (GLOBAL_CONFIG, USER_CONFIG, config_file):
+        if filename is not None and os.path.exists(filename):
+            config.update(load_config_file(filename))
+    return config
+
+
+def load_config_file(config_file):
+    """Load configuration options from a file."""
+    configParser = ConfigParser.ConfigParser()
+    configParser.read(config_file)
+    options = {
+        'hostname': 'host',
+        'port': 'port',
+        'project': 'project',
+        'defaultbranch': 'defaultbranch',
+        'defaultremote': 'defaultremote',
+        'defaultrebase': 'defaultrebase',
+    }
+    config = {}
+    for config_key, option_name in options.items():
+        if configParser.has_option('gerrit', option_name):
+            config[config_key] = configParser.get('gerrit', option_name)
+    return config
+
+
+def update_remote(remote):
+    cmd = "git remote update %s" % remote
+    (status, output) = run_command_status(cmd)
+    if VERBOSE:
+        print(output)
+    if status != 0:
+        print("Problem running '%s'" % cmd)
+        if not VERBOSE:
+            print(output)
+        return False
+    return True
+
+
+def check_remote(branch, remote, hostname, port, project):
+    """Check that a Gerrit Git remote repo exists, if not, set one."""
+
+    has_color = check_color_support()
+    if has_color:
+        color_never = "--color=never"
+    else:
+        color_never = ""
+
+    if remote in run_command("git remote").split("\n"):
+
+        remotes = run_command("git branch -a %s" % color_never).split("\n")
+        for current_remote in remotes:
+            if (current_remote.strip() == "remotes/%s/%s" % (remote, branch)
+                    and not UPDATE):
+                return
+        # We have the remote, but aren't set up to fetch. Fix it
+        if VERBOSE:
+            print("Setting up gerrit branch tracking for better rebasing")
+        update_remote(remote)
+        return
+
+    if hostname is False or port is False or project is False:
+        # This means there was no .gitreview file
+        print("No '.gitreview' file found in this repository.")
+        print("We don't know where your gerrit is. Please manually create ")
+        print("a remote named \"%s\" and try again." % remote)
+        sys.exit(1)
+
+    # Gerrit remote not present, try to add it
+    try:
+        add_remote(hostname, port, project, remote)
+    except Exception:
+        print(sys.exc_info()[2])
+        print("We don't know where your gerrit is. Please manually create ")
+        print("a remote named \"%s\" and try again." % remote)
+        raise
+
+
+def rebase_changes(branch, remote, interactive=True):
+
+    remote_branch = "remotes/%s/%s" % (remote, branch)
+
+    if not update_remote(remote):
+        return False
+
+    if interactive:
+        cmd = "git rebase -i %s" % remote_branch
+    else:
+        cmd = "git rebase %s" % remote_branch
+
+    (status, output) = run_command_status(cmd, GIT_EDITOR='true')
+    if status != 0:
+        print("Errors running %s" % cmd)
+        if interactive:
+            print(output)
+        return False
+    return True
+
+
+def undo_rebase():
+    cmd = "git reset --hard ORIG_HEAD"
+    (status, output) = run_command_status(cmd)
+    if status != 0:
+        print("Errors running %s" % cmd)
+        print(output)
+        return False
+    return True
+
+
+def get_branch_name(target_branch):
+    global _branch_name
+    if _branch_name is not None:
+        return _branch_name
+    _branch_name = None
+    has_color = check_color_support()
+    if has_color:
+        color_never = "--color=never"
+    else:
+        color_never = ""
+    for branch in run_command("git branch %s" % color_never).split("\n"):
+        if branch.startswith('*'):
+            _branch_name = branch.split()[1].strip()
+    if _branch_name == "(no":
+        _branch_name = target_branch
+    return _branch_name
+
+
+def assert_one_change(remote, branch, yes, have_hook):
+    has_color = check_color_support()
+    if has_color:
+        color = git_config_get_value("color", "ui")
+        if color is None:
+            color = "auto"
+        else:
+            color = color.lower()
+        if (color == "" or color == "true"):
+            color = "auto"
+        elif color == "false":
+            color = "never"
+        elif color == "auto":
+            # Python is not a tty, we have to force colors
+            color = "always"
+        use_color = "--color=%s" % color
+    else:
+        use_color = ""
+    cmd = "git log %s --decorate --oneline HEAD --not remotes/%s/%s --" % (
+        use_color, remote, branch)
+    (status, output) = run_command_status(cmd)
+    if status != 0:
+        print("Had trouble running %s" % cmd)
+        print(output)
+        sys.exit(1)
+    output_lines = len(output.split("\n"))
+    if output_lines == 1 and not have_hook:
+        print("Your change was committed before the commit hook was installed")
+        print("Amending the commit to add a gerrit change id")
+        run_command("git commit --amend", GIT_EDITOR='true')
+    elif output_lines == 0:
+        print("No changes between HEAD and %s/%s." % (remote, branch))
+        print("Submitting for review would be pointless.")
+        sys.exit(1)
+    elif output_lines > 1:
+        if not yes:
+            print("You have more than one commit"
+                  " that you are about to submit.")
+            print("The outstanding commits are:\n\n%s\n" % output)
+            print("Is this really what you meant to do?")
+            yes_no = do_input("Type 'yes' to confirm: ")
+            if yes_no.lower().strip() != "yes":
+                print("Aborting.")
+                print("Please rebase/squash your changes and try again")
+                sys.exit(1)
+
+
+def use_topic(why, topic):
+    """Inform the user about why a particular topic has been selected."""
+    if VERBOSE:
+        print(why % ('"%s"' % topic,))
+    return topic
+
+
+def get_topic(target_branch):
+
+    branch_name = get_branch_name(target_branch)
+
+    branch_parts = branch_name.split("/")
+    if len(branch_parts) >= 3 and branch_parts[0] == "review":
+        return use_topic("Using change number %s "
+                         "for the topic of the change submitted",
+                         "/".join(branch_parts[2:]))
+
+    log_output = run_command("git log HEAD^1..HEAD")
+    bug_re = r'\b([Bb]ug|[Ll][Pp])\s*[#:]?\s*(\d+)'
+
+    match = re.search(bug_re, log_output)
+    if match is not None:
+        return use_topic("Using bug number %s "
+                         "for the topic of the change submitted",
+                         "bug/%s" % match.group(2))
+
+    bp_re = r'\b([Bb]lue[Pp]rint|[Bb][Pp])\s*[#:]?\s*([0-9a-zA-Z-_]+)'
+    match = re.search(bp_re, log_output)
+    if match is not None:
+        return use_topic("Using blueprint number %s "
+                         "for the topic of the change submitted",
+                         "bp/%s" % match.group(2))
+
+    return use_topic("Using local branch name %s "
+                     "for the topic of the change submitted",
+                     branch_name)
+
+
+class CannotQueryOpenChangesets(CommandFailed):
+    "Cannot fetch review information from gerrit"
+    EXIT_CODE = 32
+
+
+class CannotParseOpenChangesets(ChangeSetException):
+    "Cannot parse JSON review information from gerrit"
+    EXIT_CODE = 33
+
+
+def list_reviews(remote):
+
+    (hostname, username, port, project_name) = \
+        parse_git_show(remote, "Push")
+
+    if port is not None:
+        port = "-p %s" % port
+    else:
+        port = ""
+    if username is None:
+        userhost = hostname
+    else:
+        userhost = "%s@%s" % (username, hostname)
+
+    review_info = None
+    output = run_command_exc(
+        CannotQueryOpenChangesets,
+        "ssh", "-x", port, userhost,
+        "gerrit", "query",
+        "--current-patch-set --format=JSON project:%s status:open reviewer:self" % project_name)
+
+    review_list = []
+    review_field_width = {}
+    REVIEW_FIELDS = ('number', 'currentPatchSet', 'branch', 'subject')
+    FIELDS = range(0, len(REVIEW_FIELDS))
+    if check_color_support():
+        review_field_color = (colors.yellow, colors.yellow, colors.green, "")
+        color_reset = colors.reset
+    else:
+        review_field_color = ("", "", "", "")
+        color_reset = ""
+    review_field_width = [0, 0, 0, 0]
+    review_field_format = ["%*s", "%*s", "%*s", "%*s"]
+    review_field_justify = [+1, +1, +1, -1]  # -1 is justify to right
+
+    for line in output.split("\n"):
+        # Warnings from ssh wind up in this output
+        if line[0] != "{":
+            print(line)
+            continue
+        try:
+            review_info = json.loads(line)
+        except Exception:
+            if VERBOSE:
+                print(output)
+            raise(CannotParseOpenChangesets, sys.exc_info()[1])
+
+        if 'type' in review_info:
+            break
+
+        tempPS = review_info['currentPatchSet']
+        appPS = tempPS['approvals']
+        appValue = '-';
+        for appLine in appPS:
+          appBy = appLine['by']
+          appUser = appBy['username']
+          if appUser == username:
+            appValue = appLine['value']
+        review_info['currentPatchSet'] = tempPS['number'] + ' ' + appValue
+        
+        review_list.append([review_info[f] for f in REVIEW_FIELDS])
+        for i in FIELDS:
+            review_field_width[i] = max(
+                review_field_width[i],
+                len(review_info[REVIEW_FIELDS[i]])
+            )
+
+    review_field_format = "  ".join([
+        review_field_color[i] +
+        review_field_format[i] +
+        color_reset
+        for i in FIELDS])
+
+    review_field_width = [
+        review_field_width[i] * review_field_justify[i]
+        for i in FIELDS]
+    for review_value in review_list:
+        # At this point we have review_field_format
+        # like "%*s %*s %*s" and we need to supply
+        # (width1, value1, width2, value2, ...) tuple to print
+        # It's easy to zip() widths with actual values,
+        # but we need to flatten the resulting
+        #  ((width1, value1), (width2, value2), ...) map.
+        formatted_fields = []
+        for (width, value) in zip(review_field_width, review_value):
+            formatted_fields.extend([width, value])
+        print(review_field_format % tuple(formatted_fields))
+    print("Found %d items for review" % review_info['rowCount'])
+
+    return 0
+
+
+class CannotQueryPatchSet(CommandFailed):
+    "Cannot query patchset information"
+    EXIT_CODE = 34
+
+
+class ReviewInformationNotFound(ChangeSetException):
+    "Could not fetch review information for change %s"
+    EXIT_CODE = 35
+
+
+class ReviewNotFound(ChangeSetException):
+    "Gerrit review %s not found"
+    EXIT_CODE = 36
+
+
+class PatchSetGitFetchFailed(CommandFailed):
+    """Cannot fetch patchset contents
+
+Does specified change number belong to this project?
+"""
+    EXIT_CODE = 37
+
+
+class PatchSetNotFound(ChangeSetException):
+    "Review patchset %s not found"
+    EXIT_CODE = 38
+
+
+class CheckoutNewBranchFailed(CommandFailed):
+    "Cannot checkout to new branch"
+    EXIT_CODE = 64
+
+
+class CheckoutExistingBranchFailed(CommandFailed):
+    "Cannot checkout existing branch"
+    EXIT_CODE = 65
+
+
+class ResetHardFailed(CommandFailed):
+    "Failed to hard reset downloaded branch"
+    EXIT_CODE = 66
+
+
+def fetch_review(review, masterbranch, remote):
+
+    (hostname, username, port, project_name) = \
+        parse_git_show(remote, "Push")
+
+    if port is not None:
+        port = "-p %s" % port
+    else:
+        port = ""
+    if username is None:
+        userhost = hostname
+    else:
+        userhost = "%s@%s" % (username, hostname)
+
+    review_arg = review
+    patchset_opt = '--current-patch-set'
+
+    review, patchset_number = parse_review_number(review)
+    if patchset_number is not None:
+        patchset_opt = '--patch-sets'
+
+    review_info = None
+    output = run_command_exc(
+        CannotQueryPatchSet,
+        "ssh", "-x", port, userhost,
+        "gerrit", "query",
+        "--format=JSON %s change:%s" % (patchset_opt, review))
+
+    review_jsons = output.split("\n")
+    found_review = False
+    for review_json in review_jsons:
+        try:
+            review_info = json.loads(review_json)
+            found_review = True
+        except Exception:
+            pass
+        if found_review:
+            break
+    if not found_review:
+        if VERBOSE:
+            print(output)
+        raise ReviewInformationNotFound(review)
+
+    try:
+        if patchset_number is None:
+            refspec = review_info['currentPatchSet']['ref']
+        else:
+            refspec = [ps for ps
+                       in review_info['patchSets']
+                       if ps['number'] == patchset_number][0]['ref']
+    except IndexError:
+        raise PatchSetNotFound(review_arg)
+    except KeyError:
+        raise ReviewNotFound(review)
+
+    try:
+        topic = review_info['topic']
+        if topic == masterbranch:
+            topic = review
+    except KeyError:
+        topic = review
+    try:
+        author = re.sub('\W+', '_', review_info['owner']['name']).lower()
+    except KeyError:
+        author = 'unknown'
+
+    if patchset_number is None:
+        branch_name = "review/%s/%s" % (author, topic)
+    else:
+        branch_name = "review/%s/%s-patch%s" % (author, topic, patchset_number)
+
+    print("Downloading %s from gerrit" % refspec)
+    run_command_exc(PatchSetGitFetchFailed,
+                    "git", "fetch", remote, refspec)
+    return branch_name
+
+
+def checkout_review(branch_name):
+    """Checkout a newly fetched (FETCH_HEAD) change
+       into a branch
+    """
+
+    try:
+        run_command_exc(CheckoutNewBranchFailed,
+                        "git", "checkout", "-b",
+                        branch_name, "FETCH_HEAD")
+
+    except CheckoutNewBranchFailed as e:
+        if re.search("already exists\.?", e.output):
+            print("Branch already exists - reusing")
+            run_command_exc(CheckoutExistingBranchFailed,
+                            "git", "checkout", branch_name)
+            run_command_exc(ResetHardFailed,
+                            "git", "reset", "--hard", "FETCH_HEAD")
+        else:
+            raise
+
+    print("Switched to branch \"%s\"" % branch_name)
+
+
+class PatchSetGitCherrypickFailed(CommandFailed):
+    "There was a problem applying changeset contents to the current branch."
+    EXIT_CODE = 69
+
+
+def cherrypick_review(option=None):
+    cmd = ["git", "cherry-pick"]
+    if option:
+        cmd.append(option)
+    cmd.append("FETCH_HEAD")
+    print(run_command_exc(PatchSetGitCherrypickFailed, *cmd))
+
+
+class CheckoutBackExistingBranchFailed(CommandFailed):
+    "Cannot switch back to existing branch"
+    EXIT_CODE = 67
+
+
+class DeleteBranchFailed(CommandFailed):
+    "Failed to delete branch"
+    EXIT_CODE = 68
+
+
+class InvalidPatchsetsToCompare(GitReviewException):
+    def __init__(self, patchsetA, patchsetB):
+        Exception.__init__(
+            self,
+            "Invalid patchsets for comparison specified (old=%s,new=%s)" % (
+                patchsetA,
+                patchsetB))
+    EXIT_CODE = 39
+
+
+def compare_review(review_spec, branch, remote, rebase=False):
+    new_ps = None    # none means latest
+
+    if '-' in review_spec:
+        review_spec, new_ps = review_spec.split('-')
+    review, old_ps = parse_review_number(review_spec)
+
+    if old_ps is None or old_ps == new_ps:
+        raise InvalidPatchsetsToCompare(old_ps, new_ps)
+
+    old_review = build_review_number(review, old_ps)
+    new_review = build_review_number(review, new_ps)
+
+    old_branch = fetch_review(old_review, branch, remote)
+    checkout_review(old_branch)
+
+    if rebase:
+        print('Rebasing %s' % old_branch)
+        rebase = rebase_changes(branch, remote, False)
+        if not rebase:
+            print('Skipping rebase because of conflicts')
+            run_command_exc(CommandFailed, 'git', 'rebase', '--abort')
+
+    new_branch = fetch_review(new_review, branch, remote)
+    checkout_review(new_branch)
+
+    if rebase:
+        print('Rebasing also %s' % new_branch)
+        if not rebase_changes(branch, remote, False):
+            print("Rebasing of the new branch failed, "
+                  "diff can be messed up (use -R to not rebase at all)!")
+            run_command_exc(CommandFailed, 'git', 'rebase', '--abort')
+
+    subprocess.check_call(['git', 'difftool', old_branch])
+
+
+def finish_branch(target_branch):
+    local_branch = get_branch_name(target_branch)
+    if VERBOSE:
+        print("Switching back to '%s' and deleting '%s'" % (target_branch,
+                                                            local_branch))
+    run_command_exc(CheckoutBackExistingBranchFailed,
+                    "git", "checkout", target_branch)
+    print("Switched to branch '%s'" % target_branch)
+
+    run_command_exc(DeleteBranchFailed,
+                    "git", "branch", "-D", local_branch)
+    print("Deleted branch '%s'" % local_branch)
+
+
+def convert_bool(one_or_zero):
+    "Return a bool on a one or zero string."
+    return one_or_zero in ["1", "true", "True"]
+
+
+def print_exit_message(status, needs_update):
+
+    if needs_update:
+        print("""
+***********************************************************
+A new version of git-review is available on PyPI. Please
+update your copy with:
+
+  pip install -U git-review
+
+to ensure proper behavior with gerrit. Thanks!
+***********************************************************
+""")
+    sys.exit(status)
+
+
+def main():
+    global _no_color_support
+    usage = "git review [OPTIONS] ... [BRANCH]"
+
+    import argparse
+
+    class DownloadFlag(argparse.Action):
+        """Additional option parsing: store value in 'dest', but
+           at the same time set one of the flag options to True
+        """
+        def __call__(self, parser, namespace, values, option_string=None):
+            setattr(namespace, self.dest, values)
+            setattr(namespace, self.const, True)
+
+    parser = argparse.ArgumentParser(usage=usage, description=COPYRIGHT)
+
+    parser.add_argument("-t", "--topic", dest="topic",
+                        help="Topic to submit branch to")
+    parser.add_argument("-D", "--draft", dest="draft", action="store_true",
+                        help="Submit review as a draft")
+    parser.add_argument("-c", "--compatible", dest="compatible",
+                        action="store_true",
+                        help="Push change to refs/for/* for compatibility "
+                             "with Gerrit versions < 2.3. Ignored if "
+                             "-D/--draft is used.")
+    parser.add_argument("-n", "--dry-run", dest="dry", action="store_true",
+                        help="Don't actually submit the branch for review")
+    parser.add_argument("-i", "--new-changeid", dest="regenerate",
+                        action="store_true",
+                        help="Regenerate Change-id before submitting")
+    parser.add_argument("-r", "--remote", dest="remote",
+                        help="git remote to use for gerrit")
+    parser.add_argument("-R", "--no-rebase", dest="rebase",
+                        action="store_false",
+                        help="Don't rebase changes before submitting.")
+    parser.add_argument("-F", "--force-rebase", dest="force_rebase",
+                        action="store_true",
+                        help="Force rebase even when not needed.")
+    parser.add_argument("-B", "--no-color", dest="no_color_support",
+                        action="store_true",
+                        help="No color support.")
+                        
+
+    fetch = parser.add_mutually_exclusive_group()
+    fetch.set_defaults(download=False, compare=False, cherrypickcommit=False,
+                       cherrypickindicate=False, cherrypickonly=False)
+    fetch.add_argument("-d", "--download", dest="changeidentifier",
+                       action=DownloadFlag, metavar="CHANGE",
+                       const="download",
+                       help="Download the contents of an existing gerrit "
+                            "review into a branch")
+    fetch.add_argument("-x", "--cherrypick", dest="changeidentifier",
+                       action=DownloadFlag, metavar="CHANGE",
+                       const="cherrypickcommit",
+                       help="Apply the contents of an existing gerrit "
+                             "review onto the current branch and commit "
+                             "(cherry pick; not recommended in most "
+                             "situations)")
+    fetch.add_argument("-X", "--cherrypickindicate", dest="changeidentifier",
+                       action=DownloadFlag, metavar="CHANGE",
+                       const="cherrypickindicate",
+                       help="Apply the contents of an existing gerrit "
+                       "review onto the current branch and commit, "
+                       "indicating its origin")
+    fetch.add_argument("-N", "--cherrypickonly", dest="changeidentifier",
+                       action=DownloadFlag, metavar="CHANGE",
+                       const="cherrypickonly",
+                       help="Apply the contents of an existing gerrit "
+                       "review to the working directory and prepare "
+                       "for commit")
+    fetch.add_argument("-m", "--compare", dest="changeidentifier",
+                       action=DownloadFlag, metavar="CHANGE,PS[-NEW_PS]",
+                       const="compare",
+                       help="Download specified and latest (or NEW_PS) "
+                       "patchsets of an existing gerrit review into "
+                       "a branches, rebase on master "
+                       "(skipped on conflicts or when -R is specified) "
+                       "and show their differences")
+
+    parser.add_argument("-u", "--update", dest="update", action="store_true",
+                        help="Force updates from remote locations")
+    parser.add_argument("-s", "--setup", dest="setup", action="store_true",
+                        help="Just run the repo setup commands but don't "
+                             "submit anything")
+    parser.add_argument("-f", "--finish", dest="finish", action="store_true",
+                        help="Close down this branch and switch back to "
+                             "master on successful submission")
+    parser.add_argument("-l", "--list", dest="list", action="store_true",
+                        help="List available reviews for the current project")
+    parser.add_argument("-y", "--yes", dest="yes", action="store_true",
+                        help="Indicate that you do, in fact, understand if "
+                             "you are submitting more than one patch")
+    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
+                        help="Output more information about what's going on")
+    parser.add_argument("--no-custom-script", dest="custom_script",
+                        action="store_false", default=True,
+                        help="Do not run custom scripts.")
+    parser.add_argument("--license", dest="license", action="store_true",
+                        help="Print the license and exit")
+    parser.add_argument("--version", action="version",
+                        version='%s version %s' %
+                        (os.path.split(sys.argv[0])[-1], version))
+    parser.add_argument("branch", nargs="?")
+
+    try:
+        (top_dir, git_dir) = git_directories()
+    except GitDirectoriesException:
+        if sys.argv[1:] in ([], ['-h'], ['--help']):
+            parser.print_help()
+            sys.exit(1)
+        raise
+
+#    config = get_config(os.path.join(top_dir, ".gitreview"))
+    config = DEFAULTS.copy()       
+    cur_proj = run_command("git remote -v")
+    import re
+    m = re.search('(?<=29418\/)(\S+)', cur_proj)
+    config['project'] = m.group(0) 
+
+    
+    defaultrebase = convert_bool(
+        git_config_get_value("gitreview", "rebase",
+                             default=str(config['defaultrebase'])))
+    parser.set_defaults(dry=False,
+                        draft=False,
+                        rebase=defaultrebase,
+                        verbose=False,
+                        update=False,
+                        setup=False,
+                        list=False,
+                        yes=False,
+                        branch=config['defaultbranch'],
+                        remote=config['defaultremote'])
+    options = parser.parse_args()
+
+    if options.license:
+        print(COPYRIGHT)
+        sys.exit(0)
+
+    branch = options.branch
+    global VERBOSE
+    global UPDATE
+    VERBOSE = options.verbose
+    UPDATE = options.update
+    remote = options.remote
+    yes = options.yes
+    status = 0
+
+    needs_update = latest_is_newer()
+    check_remote(branch, remote,
+                 config['hostname'], config['port'], config['project'])
+
+    if options.no_color_support:
+      _no_color_support = True
+
+    if options.changeidentifier:
+        if options.compare:
+            compare_review(options.changeidentifier,
+                           branch, remote, options.rebase)
+            return
+        local_branch = fetch_review(options.changeidentifier, branch, remote)
+        if options.download:
+            checkout_review(local_branch)
+        else:
+            if options.cherrypickcommit:
+                cherrypick_review()
+            elif options.cherrypickonly:
+                cherrypick_review("-n")
+            if options.cherrypickindicate:
+                cherrypick_review("-x")
+        return
+    elif options.list:
+        list_reviews(remote)
+        return
+
+    if options.custom_script:
+        run_custom_script("pre")
+
+    hook_file = os.path.join(git_dir, "hooks", "commit-msg")
+    have_hook = os.path.exists(hook_file) and os.access(hook_file, os.X_OK)
+
+    if not have_hook:
+        set_hooks_commit_msg(remote, hook_file)
+
+    if options.setup:
+        if options.finish and not options.dry:
+            finish_branch(branch)
+        return
+
+    if options.rebase:
+        if not rebase_changes(branch, remote):
+            print_exit_message(1, needs_update)
+        if not options.force_rebase and not undo_rebase():
+            print_exit_message(1, needs_update)
+    assert_one_change(remote, branch, yes, have_hook)
+
+    ref = "publish"
+
+    if options.draft:
+        ref = "drafts"
+        if options.custom_script:
+            run_custom_script("draft")
+    elif options.compatible:
+        ref = "for"
+
+    cmd = "git push %s HEAD:refs/%s/%s" % (remote, ref, branch)
+    topic = options.topic or get_topic(branch)
+    if topic != branch:
+        cmd += "/%s" % topic
+    if options.regenerate:
+        print("Amending the commit to regenerate the change id\n")
+        regenerate_cmd = "git commit --amend"
+        if options.dry:
+            print("\tGIT_EDITOR=\"sed -i -e '/^Change-Id:/d'\" %s\n" %
+                  regenerate_cmd)
+        else:
+            run_command(regenerate_cmd,
+                        GIT_EDITOR="sed -i -e "
+                        "'/^Change-Id:/d'")
+
+    if options.dry:
+        print("Please use the following command "
+              "to send your commits to review:\n")
+        print("\t%s\n" % cmd)
+    else:
+        (status, output) = run_command_status(cmd)
+        print(output)
+
+    if options.finish and not options.dry and status == 0:
+        finish_branch(branch)
+        return
+
+    if options.custom_script:
+        run_custom_script("post")
+    print_exit_message(status, needs_update)
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except GitReviewException as e:
+        print(e)
+        sys.exit(e.EXIT_CODE)