#!/usr/bin/python

import os
import sys
import getopt
import subprocess
import urllib2
import json
import re
from xml.etree import ElementTree

cfg = dict()
cfg['draft'] = False
cfg['nodo'] = False
cfg['ssh'] = False
cfg['remote'] = None
cfg['verbose'] = 0

def verbose(s):
    if cfg['verbose'] > 0:
        sys.stderr.write(s)

def get_topdir():
    dir = os.getcwd()
    while not os.path.exists("%s/.repo" % (dir)):
        dir = os.path.realpath("%s/.." % (dir))
        if dir == '/':
            raise OSError(2, 'No such file or directory', dir)
    return dir

optargs, argv = getopt.getopt(sys.argv[1:], 'dnsv',
        ['draft', 'nodo', 'remote=', 'ssh', 'verbose'])
for k, v in optargs:
    if k in ('-d', '--draft'):
        cfg['draft'] = True
    if k in ('-n', '--nodo'):
        cfg['nodo'] = True
    if k in ('--remote'):
        cfg['remote'] = v
    if k in ('-s', '--ssh'):
        cfg['ssh'] = True
    if k in ('-v', '--verbose'):
        cfg['verbose'] += 1

if len(argv) != 0:
    print "Usage: gerrit-push [args]"
    print "  --draft    Push as draft"
    print "  --nodo     Do not apply the change"
    print "  --remote   Use specified remote"
    print "  --ssh      Use ssh, do not attempt http"
    print "  --verbose  Increase verbose level"
    sys.exit(1)

cur_dir = os.getcwd()
verbose("cur_dir=%s" % (cur_dir))
prj_dir = None
try:
    top_dir = get_topdir()
except OSError:
    sys.stderr.write("Cannot find top of android tree\n")
    sys.exit(1)
verbose("top_dir=%s" % (top_dir))
if len(top_dir) >= len(cur_dir):
    sys.stderr.write("Not in project directory\n")
    sys.exit(1)
prj_dir = cur_dir[len(top_dir)+1:]
verbose("prj_dir=%s" % (prj_dir))

# Read our manifest
args = []
args.append('repo')
args.append('manifest')
child = subprocess.Popen(args, stdin=None, stdout=subprocess.PIPE, stderr=None)
out, err = child.communicate()
if child.returncode != 0:
    sys.stderr.write('Failed to read manifest\n')
    sys.exit(1)
manifest = ElementTree.fromstring(out)

# Figure out which remote to use
remote_name = cfg['remote']
if remote_name is None:
    if not prj_dir is None:
        for elem in manifest.findall('project'):
            if elem.get('path') == prj_dir:
                remote_name = elem.get('remote')
    if remote_name is None:
        for elem in manifest.findall('default'):
            remote_name = elem.get('remote')
if remote_name is None:
    sys.stderr.write("Cannot find appropriate remote entry in manifest\n");
    sys.exit(1);
verbose("remote_name=%s\n" % (remote_name))

review_url = None
review_host = None
for elem in manifest.findall('remote'):
    if elem.get('name') == remote_name:
        review_url = elem.get('review')
        if review_url.find(':') == -1:
            review_host = review_url
            review_url = "ssh://%s" % (review_url)
        else:
            review_host = review_url.strip_url_schema()
if review_url is None or review_host is None:
    sys.stderr.write("Cannot find appropriate remote url in manifest\n");
    sys.exit(1);
verbose("review_url=%s, review_host=%s\n" % (review_url, review_host))

project = None
for elem in manifest.findall('project'):
    if elem.get('path') == prj_dir:
        project = elem
if project is None:
    sys.stderr.write('Error: project not found\n')
    sys.exit(1)
project_path = project.get('path')
project_name = project.get('name')

# Figure out which branch to use
project_branch = project.get('revision')
if project_branch is None:
    for elem in manifest.findall('default'):
        project_branch = elem.get('revision')
if project_branch is None:
    sys.stderr.write("Cannot find project branch in manifest\n");
    sys.exit(1);
if project_branch.startswith('refs/heads/'):
    project_branch = project_branch[11:]
verbose("project_branch=%s\n" % (project_branch))

# Push the change
args = []
args.append('git')
args.append('push')
args.append('%s/%s' % (review_url, project_name))
args.append('HEAD:refs/for/%s' % (project_branch))
if cfg['nodo']:
    print ' '.join(args)
else:
    child = subprocess.Popen(args, stdin=None, stdout=None, stderr=None)
    out, err = child.communicate()
    if child.returncode != 0:
        sys.stderr.write('Failed to push change\n')
        sys.exit(1)

verbose('Success\n')
sys.exit(0)
